JAX-RSのコードを書いた
中身としてはタイトル通りなのですが。
Java8, maven, lombokを使います。
Java8, maven ,lombok成分はあまりありません。
非同期Responseでデータ返すところまでやってみます。
urlのマッピングとしてはこんな感じになってます。
(URLのマッピングは適当です)
localhost:8080 - /test/user/{id} --> User(json data) - /assets/ --> 静的ファイル
設定周り
dependencyはこんな感じ
<dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-grizzly2-http</artifactId> <version>2.23.2</version> </dependency> <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-json-jackson</artifactId> <version>2.23.2</version> </dependency> <dependency> <groupId>org.glassfish.hk2</groupId> <artifactId>hk2-metadata-generator</artifactId> <version>2.5.0-b05</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.10</version> <scope>provided</scope> </dependency>
jerseyのcontainer、grizzly実装です。
Request/ResponseのJSON Serialize, Desirializeはjacksonの実装を使います。
ベースはこちらのリポジトリを参考にソース書いてます。
github.com
コードを書いていく
JAX-RSの設定のクラスです。DIのためのクラス登録みたいなことやってる感じですね。
JacksonFeatureはJacksonのモジュールを登録してJAX-RSでシリアライズ・デシリアライズするためのモジュールです。
public class App { private static final URI BASE_URI = URI.create("http://localhost:8080/"); public static void main(String[] args) throws IOException { final HttpServer server = GrizzlyHttpServerFactory .createHttpServer(BASE_URI, create()); // /assetsに静的ファイルマッピングを行う server.getServerConfiguration() .addHttpHandler(new StaticHttpHandler(),"/assets"); // "assets"にしてると動かなくてアレって思って調べたら"/hogehoge"っぽい System.in.read(); server.shutdownNow(); } public static ResourceConfig create() throws IOException { ResourceConfig resourceConfig = new ResourceConfig(); //jackson resourceConfig.register(JacksonFeature.class); resourceConfig.register(DiscoveryFeature.class); resourceConfig.packages("com.wreulicke.jaxrs"); return resourceConfig; } }
上のコードに出てきたDiscoveryFeatureはこちらのサイトを参考に書いた
以下のコードになります。
public class DiscoveryFeature implements Feature { @Override public boolean configure(FeatureContext context) { ServiceLocator locator = ServiceLocatorProvider .getServiceLocator(context); DynamicConfigurationService dcs = locator .getService(DynamicConfigurationService.class); Populator populator = dcs.getPopulator(); try { populator.populate(new ClasspathDescriptorFileFinder(this.getClass() .getClassLoader()), new DuplicatePostProcessor()); } catch (IOException | MultiException ex) { throw new RuntimeException(ex); } return true; } }
リンク先で設定されているように、mavenのbuildの設定をやってもいいのですが
annotation processingでやってくれてる(っぽい)hk2-metadata-generatorを使いました。
で、ここまでがプロジェクトの設定部分ですが
残りの実コードは大したことないのでまとめて以下に書いておきます。
// Resourceクラス @Path("/test") public class Resource { @Inject UserRepository repository; @GET @Path("/user/{id}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public void findUser(@Suspended AsyncResponse response, @PathParam("id") String user) { repository.find(user).thenAcceptAsync(response::resume); } } // interafaceとimplementation @Contract public interface UserRepository { public CompletionStage<User> find(String id); } @Service public class UserRepository implements com.wreulicke.jaxrs.service.UserRepository{ @Inject ExecutorService service; Function<String, User> supplier=User::new; @Override public CompletionStage<User> find(String id) { // stub:とりあえず入ってきたidでuser返すだけ return CompletableFuture.supplyAsync(()->supplier.apply(id), service); } } // とりあえずのvalue object @AllArgsConstructor @Data public class User { String id; }
こんなところです。
@Contractと@Serviceでインターフェースと実装の紐づけが行われます。(正確にはその設定が書かれたファイルが吐かれる)
静的ファイルを設定するところでurl mappingの仕様が分かっておらず、詰まって頭抱えてました。
まとめ
Java SEの延長線のJAX-RSでした。少ない機能でとりあえず書きました。
しかし、これではJAX-RSがどうやって成り立ってるかはあまり分かりません。
とりあえず、使えるまで、でした。
今回書いたコードは以下のリポジトリに置いてあります。
github.com