これは、なにをしたくて書いたもの?
前に、Quarkus HTTPを使ってServletを動かすエントリーを書いてみました。
Quarkus HTTPでServletを試す - CLOVER🍀
Quarkus HTTPは使い方がUndertowと変わらないので、RESTEasyもそのまま動かせるのでは?ということで遊んでみました。
完全にネタです。
Quarkus HTTP上でRESTEasyを動かす
Quarkus HTTPは、Vert.xをベースにしたServletの実装です。
GitHub - quarkusio/quarkus-http
サンプルを見るとわかりますが、見た目はUndertowそのものです。
一方、RESTEasyにはUndertow向けのServer Adapterがあります。
Jakarta RESTFul Web Services / Embedded Containers / Undertow
依存しているJakarta Servletのバージョンは、RESTEasy、Quarkus HTTPともに4.0.4です。
https://github.com/resteasy/resteasy/blob/5.0.2.Final/resteasy-dependencies-bom/pom.xml#L70
https://github.com/quarkusio/quarkus-http/blob/4.1.8/pom.xml#L76
Jakarta Servletのバージョン的には、RESTEasy 5.0で良さそうです。
また、RESTEasyが依存するUndertowのバージョンは2.2.7.Finalです。
https://github.com/resteasy/resteasy/blob/5.0.2.Final/resteasy-dependencies-bom/pom.xml#L32
Undertowについては、RESTEasy Undertow Adapterの依存関係に含まれているのでexcludeする必要があります。
ちなみに、この方法でやるくらいなら素直にVert.xやNetty 4の上で動かした方がいいような気はします。
Jakarta RESTFul Web Services / Embedded Containers / Vert.x
Jakarta RESTFul Web Services / Embedded Containers / Netty
Vert.xを使う場合は4.1.0に依存していますが、Vert.xの場合は依存関係がprovided
(利用者側で明示的に依存関係に追加する必要がある)に
なっています。
https://github.com/resteasy/resteasy/blob/5.0.2.Final/resteasy-dependencies-bom/pom.xml#L31
Netty 4の場合は、依存関係に含まれます。
とりあえず、今回はRESTEasyをQuarkus HTTP上で動かし、加えてJackson 2 Providerも入れて動かしてみましょう。
環境
今回の環境は、こちらです。
$ java --version openjdk 17.0.2 2022-01-18 OpenJDK Runtime Environment (build 17.0.2+8-Ubuntu-120.04) OpenJDK 64-Bit Server VM (build 17.0.2+8-Ubuntu-120.04, mixed mode, sharing) $ mvn --version Apache Maven 3.8.5 (3599d3414f046de2324203b78ddcf9b5e4388aa0) Maven home: $HOME/.sdkman/candidates/maven/current Java version: 17.0.2, vendor: Private Build, runtime: /usr/lib/jvm/java-17-openjdk-amd64 Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "5.4.0-105-generic", arch: "amd64", family: "unix"
準備
Maven依存関係等は、こちら。
<dependencies> <dependency> <groupId>io.quarkus.http</groupId> <artifactId>quarkus-http-servlet</artifactId> <version>4.1.8</version> </dependency> <dependency> <groupId>io.quarkus.http</groupId> <artifactId>quarkus-http-vertx-backend</artifactId> <version>4.1.8</version> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-undertow</artifactId> <version>5.0.2.Final</version> <exclusions> <exclusion> <groupId>io.undertow</groupId> <artifactId>undertow-servlet</artifactId> </exclusion> <exclusion> <groupId>io.undertow</groupId> <artifactId>undertow-core</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-jackson2-provider</artifactId> <version>5.0.2.Final</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.8.2</version> <scope>test</scope> </dependency> <dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <version>4.5.1</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.2</version> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.6.5</version> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
Quakus HTTPはこちらですね。
<dependency> <groupId>io.quarkus.http</groupId> <artifactId>quarkus-http-servlet</artifactId> <version>4.1.8</version> </dependency> <dependency> <groupId>io.quarkus.http</groupId> <artifactId>quarkus-http-vertx-backend</artifactId> <version>4.1.8</version> </dependency>
resteasy-undertow
からUndertowに関するアーティファクトをexcludeし、Jackson 2 Providerも足しておきます。
<dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-undertow</artifactId> <version>5.0.2.Final</version> <exclusions> <exclusion> <groupId>io.undertow</groupId> <artifactId>undertow-servlet</artifactId> </exclusion> <exclusion> <groupId>io.undertow</groupId> <artifactId>undertow-core</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-jackson2-provider</artifactId> <version>5.0.2.Final</version> </dependency>
Spring Boot Maven Pluginが入っているのは、Uber JARを作るために入れています。
プログラムを作成する
では、JAX-RSとQuarkus HTTPを使ってプログラムを作成します。
JAX-RSリソースクラス。
src/main/java/org/littlewings/quarkus/http/EchoResource.java
package org.littlewings.quarkus.http; import java.util.Map; import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @Path("echo") public class EchoResource { @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Map<String, String> message(Map<String, String> request) { String message = request.getOrDefault("message", "World"); return Map.of("replyMessage", "Hello " + message + "!!"); } }
Application
のサブクラス。
src/main/java/org/littlewings/quarkus/http/JaxrsActivator.java
package org.littlewings.quarkus.http; import java.util.Set; import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; @ApplicationPath("") public class JaxrsActivator extends Application { @Override public Set<Object> getSingletons() { return Set.of(new EchoResource()); } }
mainクラス。こちらで、Undertow Adapterを使います。
src/main/java/org/littlewings/quarkus/http/Server.java
package org.littlewings.quarkus.http; import javax.ws.rs.core.Application; import io.undertow.Undertow; import io.undertow.servlet.api.DeploymentInfo; import org.jboss.logging.Logger; import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer; public class Server implements AutoCloseable { UndertowJaxrsServer server; public static void main(String... args) { Logger logger = Logger.getLogger(Server.class); int port = 8080; String contextPath = "/"; try (Server server = new Server()) { server.start(port, new JaxrsActivator(), contextPath); logger.infof("server[port = %d, context-path = %s] startup.", port, contextPath); System.console().readLine("Enter stop."); } logger.info("server stopped."); } public void start(int port, Application jaxrsActivator, String contextPath) { server = new UndertowJaxrsServer(); server.start(Undertow.builder().addHttpListener(port, "0.0.0.0")); DeploymentInfo deployment = server.undertowDeployment(jaxrsActivator.getClass()); deployment.setContextPath(contextPath); deployment.setDeploymentName("app"); server.deploy(deployment); } @Override public void close() { server.stop(); } }
停止は、Enterで。
プログラムはこれくらいにしておきます。
パッケージング。
$ mvn package
起動。
$ java -jar target/resteasy-server-0.0.1-SNAPSHOT.jar
ログ。
3月 25, 2022 11:54:35 午後 org.jboss.resteasy.core.ResteasyDeploymentImpl processApplication INFO: RESTEASY002225: Deploying javax.ws.rs.core.Application: class org.littlewings.quarkus.http.JaxrsActivator 3月 25, 2022 11:54:35 午後 org.jboss.resteasy.core.ResteasyDeploymentImpl processApplication INFO: RESTEASY002220: Adding singleton resource org.littlewings.quarkus.http.EchoResource from Application class org.littlewings.quarkus.http.JaxrsActivator 3月 25, 2022 11:54:35 午後 org.littlewings.quarkus.http.Server main INFO: server[port = 8080, context-path = /] startup. Enter stop.
確認。
$ curl -XPOST -H 'Content-Type: application/json' localhost:8080/echo -d '{"message": "RESTEasy"}' {"replyMessage":"Hello RESTEasy!!"}
OKですね。
最後に、テストコードも書いておきましょう。REST-assuredを使ったテスト。
src/test/java/org/littlewings/quarkus/http/EchoResourceTest.java
package org.littlewings.quarkus.http; import java.util.Map; import io.restassured.RestAssured; import io.restassured.http.ContentType; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static io.restassured.RestAssured.given; import static org.hamcrest.Matchers.equalTo; class EchoResourceTest { Server server; int port = 8081; String contextPath = "/"; @BeforeEach public void setUp() { RestAssured.baseURI = "http://localhost"; RestAssured.port = port; RestAssured.basePath = contextPath; server = new Server(); server.start(port, new JaxrsActivator(), contextPath); } @AfterEach public void tearDown() { server.close(); } @Test public void reply() { given() .contentType(ContentType.JSON) .body(Map.of("message", "RESTEasy")) .when() .post("echo") .then() .body("replyMessage", equalTo("Hello RESTEasy!!")); } }
こんな感じで。
まとめ
Quarkus HTTP上で、RESTEasyを動かしてみました。
見かけがほぼUndertowそのままなので勢いでやってみた感じなのですが、あっさりと動きましたね。
まあ、今回は完全にネタです…。