CLOVER🍀

That was when it all began.

UndertowからVert.xバックエンドになった、QuarkusのRESTEasyを試す

これは、なにをしたくて書いたもの?

最近Quarkusを触っていなかったのですが、少し前にRESTEasyのバックエンドがUndertowからVert.xに移ったという話を見たので、
1度見ておこうかなと。

Quarkus 0.24.0 released - Vert.x everywhere

Quarkus 0.23.2 released - Back on track

Quarkus 0.23.1 released - Paving the way to our new HTTP layer

0.24.0で完全に移行していて、0.23.1から移り始めていたんですね。2019年9月の話ですねぇ。

久しぶりに、ちょっと試してみましょう。

環境

今回の環境は、こちら。

$ java -version
openjdk version "1.8.0_232"
OpenJDK Runtime Environment (build 1.8.0_232-8u232-b09-0ubuntu1~18.04.1-b09)
OpenJDK 64-Bit Server VM (build 25.232-b09, mixed mode)


$ $GRAALVM_HOME/bin/native-image --version
GraalVM Version 19.2.1 CE


$ mvn --version
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 1.8.0_232, vendor: Private Build, runtime: /usr/lib/jvm/java-8-openjdk-amd64/jre
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "4.15.0-74-generic", arch: "amd64", family: "unix"

サンプルプロジェクト

今回は、RESTEasy+JSON(Jackson)な構成でいきましょう。

プロジェクトの作成。今回使用するQuarkusのバージョンは、1.1.1.Finalです。

$ mvn io.quarkus:quarkus-maven-plugin:1.1.1.Final:create \
    -DprojectGroupId=org.littlewings \
    -DprojectArtifactId=resteasy-vertx-jackson \
    -Dextensions="resteasy-jackson"

作成されたディレクトリに移動。

$ cd resteasy-vertx-jackson

pom.xmlに書かれた依存関係は、こんな感じです。

  <dependencies>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-junit5</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>rest-assured</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy-jackson</artifactId>
    </dependency>
  </dependencies>

Mavenで依存関係を見てみましょう。

$ mvn dependency:tree

こんな感じの結果に。

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ resteasy-vertx-jackson ---
[INFO] org.littlewings:resteasy-vertx-jackson:jar:1.0-SNAPSHOT
[INFO] +- io.quarkus:quarkus-resteasy:jar:1.1.1.Final:compile
[INFO] |  +- io.quarkus:quarkus-vertx-http:jar:1.1.1.Final:compile
[INFO] |  |  +- io.quarkus.security:quarkus-security:jar:1.0.1.Final:compile
[INFO] |  |  +- jakarta.enterprise:jakarta.enterprise.cdi-api:jar:2.0.2:compile
[INFO] |  |  |  +- jakarta.el:jakarta.el-api:jar:3.0.3:compile
[INFO] |  |  |  \- jakarta.interceptor:jakarta.interceptor-api:jar:1.2.5:compile
[INFO] |  |  +- io.quarkus:quarkus-vertx-core:jar:1.1.1.Final:compile
[INFO] |  |  |  +- io.quarkus:quarkus-netty:jar:1.1.1.Final:compile
[INFO] |  |  |  |  +- io.netty:netty-codec:jar:4.1.42.Final:compile
[INFO] |  |  |  |  \- io.netty:netty-handler:jar:4.1.42.Final:compile
[INFO] |  |  |  \- io.vertx:vertx-core:jar:3.8.4:compile
[INFO] |  |  |     +- io.netty:netty-common:jar:4.1.42.Final:compile
[INFO] |  |  |     +- io.netty:netty-buffer:jar:4.1.42.Final:compile
[INFO] |  |  |     +- io.netty:netty-transport:jar:4.1.42.Final:compile
[INFO] |  |  |     +- io.netty:netty-handler-proxy:jar:4.1.42.Final:compile
[INFO] |  |  |     |  \- io.netty:netty-codec-socks:jar:4.1.42.Final:compile
[INFO] |  |  |     +- io.netty:netty-codec-http:jar:4.1.42.Final:compile
[INFO] |  |  |     +- io.netty:netty-codec-http2:jar:4.1.42.Final:compile
[INFO] |  |  |     +- io.netty:netty-resolver:jar:4.1.42.Final:compile
[INFO] |  |  |     \- io.netty:netty-resolver-dns:jar:4.1.42.Final:compile
[INFO] |  |  |        \- io.netty:netty-codec-dns:jar:4.1.42.Final:compile
[INFO] |  |  \- io.vertx:vertx-web:jar:3.8.4:compile
[INFO] |  |     +- io.vertx:vertx-web-common:jar:3.8.4:compile
[INFO] |  |     +- io.vertx:vertx-auth-common:jar:3.8.4:compile
[INFO] |  |     \- io.vertx:vertx-bridge-common:jar:3.8.4:compile
[INFO] |  \- io.quarkus:quarkus-resteasy-server-common:jar:1.1.1.Final:compile
[INFO] |     +- io.quarkus:quarkus-arc:jar:1.1.1.Final:compile
[INFO] |     |  +- io.quarkus.arc:arc:jar:1.1.1.Final:compile
[INFO] |     |  \- org.eclipse.microprofile.context-propagation:microprofile-context-propagation-api:jar:1.0.1:compile
[INFO] |     +- io.quarkus:quarkus-resteasy-common:jar:1.1.1.Final:compile
[INFO] |     |  +- org.jboss.resteasy:resteasy-core:jar:4.4.1.Final:compile
[INFO] |     |  |  +- org.jboss.spec.javax.ws.rs:jboss-jaxrs-api_2.1_spec:jar:2.0.1.Final:compile
[INFO] |     |  |  +- org.jboss.resteasy:resteasy-core-spi:jar:4.4.1.Final:compile
[INFO] |     |  |  +- org.reactivestreams:reactive-streams:jar:1.0.3:compile
[INFO] |     |  |  \- org.eclipse.microprofile.config:microprofile-config-api:jar:1.3:compile
[INFO] |     |  \- com.sun.activation:jakarta.activation:jar:1.2.1:compile
[INFO] |     \- jakarta.validation:jakarta.validation-api:jar:2.0.2:compile
[INFO] +- io.quarkus:quarkus-junit5:jar:1.1.1.Final:test
[INFO] |  +- io.quarkus:quarkus-bootstrap-core:jar:1.1.1.Final:test
[INFO] |  |  +- com.google.guava:guava:jar:27.0.1-jre:compile
[INFO] |  |  |  +- com.google.guava:failureaccess:jar:1.0.1:compile
[INFO] |  |  |  +- com.google.guava:listenablefuture:jar:9999.0-empty-to-avoid-conflict-with-guava:compile
[INFO] |  |  |  +- com.google.code.findbugs:jsr305:jar:3.0.2:compile
[INFO] |  |  |  +- org.checkerframework:checker-qual:jar:2.5.2:compile
[INFO] |  |  |  +- com.google.errorprone:error_prone_annotations:jar:2.2.0:compile
[INFO] |  |  |  +- com.google.j2objc:j2objc-annotations:jar:1.1:compile
[INFO] |  |  |  \- org.codehaus.mojo:animal-sniffer-annotations:jar:1.17:compile
[INFO] |  |  +- org.apache.commons:commons-lang3:jar:3.9:test
[INFO] |  |  +- org.apache.maven:maven-embedder:jar:3.5.4:test
[INFO] |  |  |  +- org.apache.maven:maven-settings:jar:3.5.4:test
[INFO] |  |  |  +- org.apache.maven:maven-core:jar:3.5.4:test
[INFO] |  |  |  |  \- org.apache.maven:maven-artifact:jar:3.5.4:test
[INFO] |  |  |  +- org.apache.maven:maven-plugin-api:jar:3.5.4:test
[INFO] |  |  |  +- org.apache.maven:maven-model:jar:3.5.4:test
[INFO] |  |  |  +- org.apache.maven:maven-model-builder:jar:3.5.4:test
[INFO] |  |  |  +- org.apache.maven:maven-builder-support:jar:3.5.4:test
[INFO] |  |  |  +- org.apache.maven.resolver:maven-resolver-api:jar:1.1.1:test
[INFO] |  |  |  +- org.apache.maven.resolver:maven-resolver-util:jar:1.1.1:test
[INFO] |  |  |  +- org.apache.maven.shared:maven-shared-utils:jar:3.2.1:test
[INFO] |  |  |  |  \- commons-io:commons-io:jar:2.6:test
[INFO] |  |  |  +- com.google.inject:guice:jar:no_aop:4.2.0:test
[INFO] |  |  |  |  \- aopalliance:aopalliance:jar:1.0:test
[INFO] |  |  |  +- org.codehaus.plexus:plexus-utils:jar:3.0.24:test
[INFO] |  |  |  +- org.codehaus.plexus:plexus-classworlds:jar:2.5.2:test
[INFO] |  |  |  +- org.eclipse.sisu:org.eclipse.sisu.plexus:jar:0.3.3:test
[INFO] |  |  |  +- org.codehaus.plexus:plexus-component-annotations:jar:1.7.1:test
[INFO] |  |  |  \- commons-cli:commons-cli:jar:1.4:test
[INFO] |  |  +- jakarta.annotation:jakarta.annotation-api:jar:1.3.5:compile
[INFO] |  |  +- jakarta.inject:jakarta.inject-api:jar:1.0:compile
[INFO] |  |  +- org.apache.maven:maven-settings-builder:jar:3.5.4:test
[INFO] |  |  |  +- org.codehaus.plexus:plexus-interpolation:jar:1.24:test
[INFO] |  |  |  \- org.sonatype.plexus:plexus-sec-dispatcher:jar:1.4:test
[INFO] |  |  |     \- org.sonatype.plexus:plexus-cipher:jar:1.4:test
[INFO] |  |  +- org.apache.maven:maven-resolver-provider:jar:3.5.4:test
[INFO] |  |  |  +- org.apache.maven:maven-repository-metadata:jar:3.5.4:test
[INFO] |  |  |  +- org.apache.maven.resolver:maven-resolver-spi:jar:1.1.1:test
[INFO] |  |  |  \- org.apache.maven.resolver:maven-resolver-impl:jar:1.1.1:test
[INFO] |  |  +- org.apache.maven.resolver:maven-resolver-connector-basic:jar:1.1.1:test
[INFO] |  |  +- org.apache.maven.resolver:maven-resolver-transport-wagon:jar:1.1.1:test
[INFO] |  |  |  \- org.apache.maven.wagon:wagon-provider-api:jar:3.0.0:test
[INFO] |  |  +- org.apache.maven.wagon:wagon-http:jar:3.0.0:test
[INFO] |  |  |  \- org.apache.maven.wagon:wagon-http-shared:jar:3.0.0:test
[INFO] |  |  |     \- org.jsoup:jsoup:jar:1.7.2:test
[INFO] |  |  +- org.apache.maven.wagon:wagon-file:jar:3.0.0:test
[INFO] |  |  +- org.jboss.logging:jboss-logging:jar:3.3.2.Final:compile
[INFO] |  |  \- org.jboss.logging:commons-logging-jboss-logging:jar:1.0.0.Final:test
[INFO] |  +- io.quarkus:quarkus-test-common:jar:1.1.1.Final:test
[INFO] |  |  +- io.quarkus:quarkus-core-deployment:jar:1.1.1.Final:test
[INFO] |  |  |  +- io.quarkus.gizmo:gizmo:jar:1.0.0.Final:test
[INFO] |  |  |  |  \- org.ow2.asm:asm-util:jar:7.1:test
[INFO] |  |  |  |     +- org.ow2.asm:asm-tree:jar:7.1:test
[INFO] |  |  |  |     \- org.ow2.asm:asm-analysis:jar:7.1:test
[INFO] |  |  |  +- org.ow2.asm:asm:jar:7.1:test
[INFO] |  |  |  \- io.quarkus:quarkus-builder:jar:1.1.1.Final:test
[INFO] |  |  +- io.quarkus:quarkus-jsonp-deployment:jar:1.1.1.Final:test
[INFO] |  |  |  \- io.quarkus:quarkus-jsonp:jar:1.1.1.Final:test
[INFO] |  |  |     \- org.glassfish:jakarta.json:jar:1.1.6:test
[INFO] |  |  \- org.jboss:jandex:jar:2.1.2.Final:test
[INFO] |  +- org.junit.jupiter:junit-jupiter:jar:5.5.2:test
[INFO] |  |  +- org.junit.jupiter:junit-jupiter-api:jar:5.5.2:test
[INFO] |  |  |  +- org.apiguardian:apiguardian-api:jar:1.1.0:test
[INFO] |  |  |  +- org.opentest4j:opentest4j:jar:1.2.0:test
[INFO] |  |  |  \- org.junit.platform:junit-platform-commons:jar:1.5.2:test
[INFO] |  |  +- org.junit.jupiter:junit-jupiter-params:jar:5.5.2:test
[INFO] |  |  \- org.junit.jupiter:junit-jupiter-engine:jar:5.5.2:test
[INFO] |  |     \- org.junit.platform:junit-platform-engine:jar:1.5.2:test
[INFO] |  \- io.quarkus:quarkus-core:jar:1.1.1.Final:compile
[INFO] |     +- io.smallrye.config:smallrye-config:jar:1.5.1:compile
[INFO] |     |  \- io.smallrye.config:smallrye-config-common:jar:1.5.1:compile
[INFO] |     +- org.jboss.logmanager:jboss-logmanager-embedded:jar:1.0.4:compile
[INFO] |     +- org.jboss.logging:jboss-logging-annotations:jar:2.1.0.Final:compile
[INFO] |     +- org.jboss.threads:jboss-threads:jar:3.0.0.Final:compile
[INFO] |     +- org.slf4j:slf4j-api:jar:1.7.29:compile
[INFO] |     +- org.jboss.slf4j:slf4j-jboss-logging:jar:1.2.0.Final:compile
[INFO] |     +- org.graalvm.sdk:graal-sdk:jar:19.2.1:compile
[INFO] |     \- org.wildfly.common:wildfly-common:jar:1.5.0.Final-format-001:compile
[INFO] +- io.rest-assured:rest-assured:jar:4.1.2:test
[INFO] |  +- org.codehaus.groovy:groovy:jar:2.5.8:test
[INFO] |  +- org.codehaus.groovy:groovy-xml:jar:2.5.8:test
[INFO] |  +- org.apache.httpcomponents:httpclient:jar:4.5.10:test
[INFO] |  |  +- org.apache.httpcomponents:httpcore:jar:4.4.12:test
[INFO] |  |  \- commons-codec:commons-codec:jar:1.13:test
[INFO] |  +- org.apache.httpcomponents:httpmime:jar:4.5.3:test
[INFO] |  +- org.hamcrest:hamcrest:jar:2.1:test
[INFO] |  +- org.ccil.cowan.tagsoup:tagsoup:jar:1.2.1:test
[INFO] |  +- io.rest-assured:json-path:jar:4.1.2:test
[INFO] |  |  +- org.codehaus.groovy:groovy-json:jar:2.5.8:test
[INFO] |  |  \- io.rest-assured:rest-assured-common:jar:4.1.2:test
[INFO] |  \- io.rest-assured:xml-path:jar:4.1.2:test
[INFO] |     +- javax.xml.bind:jaxb-api:jar:2.3.1:test
[INFO] |     \- org.apache.sling:org.apache.sling.javax.activation:jar:0.1.0:test
[INFO] \- io.quarkus:quarkus-resteasy-jackson:jar:1.1.1.Final:compile
[INFO]    +- io.quarkus:quarkus-jackson:jar:1.1.1.Final:compile
[INFO]    |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.9.10.2:compile
[INFO]    |  +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.9.10:compile
[INFO]    |  +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.9.10:compile
[INFO]    |  \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.9.10:compile
[INFO]    +- org.jboss.resteasy:resteasy-jackson2-provider:jar:4.4.1.Final:compile
[INFO]    |  +- org.jboss.resteasy:resteasy-jaxb-provider:jar:4.4.1.Final:compile
[INFO]    |  |  \- org.glassfish.jaxb:jaxb-runtime:jar:2.3.3-b01:compile
[INFO]    |  |     +- org.glassfish.jaxb:txw2:jar:2.3.3-b01:compile
[INFO]    |  |     \- com.sun.istack:istack-commons-runtime:jar:3.0.10:compile
[INFO]    |  +- com.fasterxml.jackson.core:jackson-core:jar:2.9.10:compile
[INFO]    |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.10:compile
[INFO]    |  +- com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:jar:2.9.10:compile
[INFO]    |  |  +- com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:jar:2.9.10:compile
[INFO]    |  |  \- com.fasterxml.jackson.module:jackson-module-jaxb-annotations:jar:2.9.10:compile
[INFO]    |  \- com.github.fge:json-patch:jar:1.9:compile
[INFO]    |     \- com.github.fge:jackson-coreutils:jar:1.6:compile
[INFO]    |        \- com.github.fge:msg-simple:jar:1.1:compile
[INFO]    |           \- com.github.fge:btf:jar:1.2:compile
[INFO]    \- org.jboss.spec.javax.xml.bind:jboss-jaxb-api_2.3_spec:jar:2.0.0.Final:compile

RESTEasyまわりを見ると、確かにUndertowがいません。Vert.xとNettyが見えます。

[INFO] +- io.quarkus:quarkus-resteasy:jar:1.1.1.Final:compile
[INFO] |  +- io.quarkus:quarkus-vertx-http:jar:1.1.1.Final:compile
[INFO] |  |  +- io.quarkus.security:quarkus-security:jar:1.0.1.Final:compile
[INFO] |  |  +- jakarta.enterprise:jakarta.enterprise.cdi-api:jar:2.0.2:compile
[INFO] |  |  |  +- jakarta.el:jakarta.el-api:jar:3.0.3:compile
[INFO] |  |  |  \- jakarta.interceptor:jakarta.interceptor-api:jar:1.2.5:compile
[INFO] |  |  +- io.quarkus:quarkus-vertx-core:jar:1.1.1.Final:compile
[INFO] |  |  |  +- io.quarkus:quarkus-netty:jar:1.1.1.Final:compile
[INFO] |  |  |  |  +- io.netty:netty-codec:jar:4.1.42.Final:compile
[INFO] |  |  |  |  \- io.netty:netty-handler:jar:4.1.42.Final:compile
[INFO] |  |  |  \- io.vertx:vertx-core:jar:3.8.4:compile
[INFO] |  |  |     +- io.netty:netty-common:jar:4.1.42.Final:compile
[INFO] |  |  |     +- io.netty:netty-buffer:jar:4.1.42.Final:compile
[INFO] |  |  |     +- io.netty:netty-transport:jar:4.1.42.Final:compile
[INFO] |  |  |     +- io.netty:netty-handler-proxy:jar:4.1.42.Final:compile
[INFO] |  |  |     |  \- io.netty:netty-codec-socks:jar:4.1.42.Final:compile
[INFO] |  |  |     +- io.netty:netty-codec-http:jar:4.1.42.Final:compile
[INFO] |  |  |     +- io.netty:netty-codec-http2:jar:4.1.42.Final:compile
[INFO] |  |  |     +- io.netty:netty-resolver:jar:4.1.42.Final:compile
[INFO] |  |  |     \- io.netty:netty-resolver-dns:jar:4.1.42.Final:compile
[INFO] |  |  |        \- io.netty:netty-codec-dns:jar:4.1.42.Final:compile
[INFO] |  |  \- io.vertx:vertx-web:jar:3.8.4:compile
[INFO] |  |     +- io.vertx:vertx-web-common:jar:3.8.4:compile
[INFO] |  |     +- io.vertx:vertx-auth-common:jar:3.8.4:compile
[INFO] |  |     \- io.vertx:vertx-bridge-common:jar:3.8.4:compile
[INFO] |  \- io.quarkus:quarkus-resteasy-server-common:jar:1.1.1.Final:compile
[INFO] |     +- io.quarkus:quarkus-arc:jar:1.1.1.Final:compile
[INFO] |     |  +- io.quarkus.arc:arc:jar:1.1.1.Final:compile
[INFO] |     |  \- org.eclipse.microprofile.context-propagation:microprofile-context-propagation-api:jar:1.0.1:compile
[INFO] |     +- io.quarkus:quarkus-resteasy-common:jar:1.1.1.Final:compile
[INFO] |     |  +- org.jboss.resteasy:resteasy-core:jar:4.4.1.Final:compile
[INFO] |     |  |  +- org.jboss.spec.javax.ws.rs:jboss-jaxrs-api_2.1_spec:jar:2.0.1.Final:compile
[INFO] |     |  |  +- org.jboss.resteasy:resteasy-core-spi:jar:4.4.1.Final:compile
[INFO] |     |  |  +- org.reactivestreams:reactive-streams:jar:1.0.3:compile
[INFO] |     |  |  \- org.eclipse.microprofile.config:microprofile-config-api:jar:1.3:compile
[INFO] |     |  \- com.sun.activation:jakarta.activation:jar:1.2.1:compile
[INFO] |     \- jakarta.validation:jakarta.validation-api:jar:2.0.2:compile

というか、Servletすらいないじゃないですか。JAX-RSのSpecは、さすがにいますね。

今回は、書籍をお題にコードを書いてみます。

書籍クラス。
src/main/java/org/littlewings/quarkus/resteasy/Book.java

package org.littlewings.quarkus.resteasy;

public class Book {
    private String isbn;
    private String title;
    private int price;

    // getter/setterは省略
}

JAX-RSリソースクラス。
src/main/java/org/littlewings/quarkus/resteasy/BookResource.java

package org.littlewings.quarkus.resteasy;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

@Path("book")
public class BookResource {
    Map<String, Book> books = new ConcurrentHashMap<>();

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<Book> books() {
        return new ArrayList<>(books.values());
    }

    @GET
    @Path("{isbn}")
    @Produces(MediaType.APPLICATION_JSON)
    public Book find(@PathParam("isbn") String isbn) {
        return books.get(isbn);
    }

    @PUT
    @Path("{isbn}")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response create(Book book, @Context UriInfo uriInfo) {
        books.put(book.getIsbn(), book);

        return Response.created(uriInfo.getRequestUriBuilder().build()).build();
    }
}

パッケージングして、

$ mvn package

起動。

$ java -jar target/resteasy-vertx-jackson-1.0-SNAPSHOT-runner.jar

認識しているExtensionに、Servletはいません。

2020-01-25 19:11:45,900 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy, resteasy-jackson]

データの登録。

$ curl -i -XPUT -H 'Content-Type: application/json' http://localhost:8080/book/978-4774183169 -d '{"isbn": "978-4774183169", "title": "パーフェクト Java EE", "price": 3456}'
HTTP/1.1 201 Created
Content-Length: 0
Location: http://localhost:8080/book/978-4774183169


$ curl -i -XPUT -H 'Content-Type: application/json' http://localhost:8080/book/978-4798124605 -d '{"isbn": "978-4798124605", "title": "Beginning Java EE 6", "price": 3891}'
HTTP/1.1 201 Created
Content-Length: 0
Location: http://localhost:8080/book/978-4798124605


$ curl -i -XPUT -H 'Content-Type: application/json' http://localhost:8080/book/978-4798140926 -d '{"isbn": "978-4798140926", "title": "Java EE 7徹底入門", "price": 4104}'
HTTP/1.1 201 Created
Content-Length: 0
Location: http://localhost:8080/book/978-4798140926

データの取得。

$ curl -s http://localhost:8080/book/978-4774183169 | jq
{
  "isbn": "978-4774183169",
  "title": "パーフェクト Java EE",
  "price": 3456
}


$ curl -s localhost:8080/book | jq
[
  {
    "isbn": "978-4798124605",
    "title": "Beginning Java EE 6",
    "price": 3891
  },
  {
    "isbn": "978-4798140926",
    "title": "Java EE 7徹底入門",
    "price": 4104
  },
  {
    "isbn": "978-4774183169",
    "title": "パーフェクト Java EE",
    "price": 3456
  }
]

ネイティブイメージにしても結果は同じなので、割愛。

$ mvn -P native package

Servlet APIの代わりや、スレッドの情報を見る

ところで、ここまでだと特に面白味がないので、HttpServletRequest代わりの情報とかどうしたらいいんだろう?というところだと、
RESTEasyのSPIを使うみたいです。

HttpRequest (RESTEasy JAX-RS 4.4.1.Final API)

Servlet compatibility

https://docs.jboss.org/resteasy/docs/4.4.1.Final/javadocs/org/jboss/resteasy/spi/package-summary.html

あと、スレッドの情報とか気になったりします。

というわけで、こんなJAX-RSリソースクラスを使って確認。
src/main/java/org/littlewings/quarkus/resteasy/HttpRequestResource.java

package org.littlewings.quarkus.resteasy;

import java.util.LinkedHashMap;
import java.util.Map;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest;

@Path("http-request")
public class HttpRequestResource {
    Logger logger = Logger.getLogger(HttpRequestResource.class);

    @GET
    @Path("print-request")
    @Produces(MediaType.APPLICATION_JSON)
    public Map<String, Object> printRequest(@Context HttpRequest request) {
        Map<String, Object> response = new LinkedHashMap<>();

        response.put("method", request.getHttpMethod());
        response.put("request-uri", request.getUri().getRequestUri().toString());
        response.put("path", request.getUri().getPath());
        response.put("query", request.getUri().getRequestUri().getQuery());

        return response;
    }

    @GET
    @Path("thread-dump")
    @Produces(MediaType.TEXT_PLAIN)
    public String printThreadDump() {
        logger.infof("Thread[%s / %s]", Thread.currentThread().getName(), Thread.currentThread().getClass().getName());

        Thread.dumpStack();

        return "print Thread Dump";
    }
}

確認。

$ curl -s localhost:8080/http-request/print-request?param=hoge | jq
{
  "method": "GET",
  "request-uri": "http://localhost:8080/http-request/print-request?param=hoge",
  "path": "/http-request/print-request",
  "query": "param=hoge"
}


$ curl -s http://localhost:8080/http-request/thread-dump
print Thread Dump

スレッドダンプは、こんな感じでした。

2020-01-25 19:12:04,117 INFO  [org.lit.qua.res.HttpRequestResource] (executor-thread-1) Thread[executor-thread-1 / org.jboss.threads.JBossThread]
java.lang.Exception: Stack trace
    at java.lang.Thread.dumpStack(Thread.java:1336)
    at org.littlewings.quarkus.resteasy.HttpRequestResource.printThreadDump(HttpRequestResource.java:38)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:151)
    at org.jboss.resteasy.core.MethodInjectorImpl.lambda$invoke$3(MethodInjectorImpl.java:122)
    at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:616)
    at java.util.concurrent.CompletableFuture.uniApplyStage(CompletableFuture.java:628)
    at java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:1996)
    at java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:110)
    at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:122)
    at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:594)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:468)
    at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:421)
    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:363)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:423)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:391)
    at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invoke$1(ResourceMethodInvoker.java:365)
    at java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:995)
    at java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2137)
    at java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:110)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:365)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:477)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:252)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:153)
    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:363)
    at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:156)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:238)
    at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:120)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.access$000(VertxRequestHandler.java:36)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler$1.run(VertxRequestHandler.java:85)
    at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
    at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1535)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1426)
    at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
    at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
    at java.lang.Thread.run(Thread.java:748)
    at org.jboss.threads.JBossThread.run(JBossThread.java:479)

スレッドプールの情報を追うと、このあたりのようです。

quarkus/ExecutorRecorder.java at 1.1.1.Final · quarkusio/quarkus · GitHub

https://quarkus.io/guides/all-config#quarkus-core_quarkus.thread-pool.core-threads

https://github.com/quarkusio/quarkus/blob/1.1.1.Final/core/runtime/src/main/java/io/quarkus/runtime/ThreadPoolConfig.java

他のバージョンだと、Vert.xのスレッドプールで調整しているようだったので、バージョンごとにだいぶ変わるんですねぇ…。

なお、ネイティブイメージの時のスタックトレースは、こんな感じでした。

2020-01-25 19:12:49,917 INFO  [org.lit.qua.res.HttpRequestResource] (executor-thread-1) Thread[executor-thread-1 / org.jboss.threads.JBossThread]
java.lang.Exception: Stack trace
    at java.lang.Thread.dumpStack(Thread.java:1336)
    at org.littlewings.quarkus.resteasy.HttpRequestResource.printThreadDump(HttpRequestResource.java:38)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:151)
    at org.jboss.resteasy.core.MethodInjectorImpl.lambda$invoke$3(MethodInjectorImpl.java:122)
    at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:616)
    at java.util.concurrent.CompletableFuture.uniApplyStage(CompletableFuture.java:628)
    at java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:1996)
    at java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:110)
    at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:122)
    at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:594)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:468)
    at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:421)
    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:363)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:423)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:391)
    at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invoke$1(ResourceMethodInvoker.java:365)
    at java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:995)
    at java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2137)
    at java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:110)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:365)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:477)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:252)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:153)
    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:363)
    at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:156)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:238)
    at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:120)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.access$000(VertxRequestHandler.java:36)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler$1.run(VertxRequestHandler.java:85)
    at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
    at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1535)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1395)
    at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
    at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
    at java.lang.Thread.run(Thread.java:748)
    at org.jboss.threads.JBossThread.run(JBossThread.java:479)
    at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:460)
    at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:193)

ここが増えてますね。

 at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:460)
    at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:193)

Servlet APIを使う

RESTEasyのバックエンドを、Vert.xではなくUndertowにするには、Undertow Extensionを追加します。

$ mvn quarkus:add-extension -Dextensions=quarkus-undertow

依存関係に、こちらが追加されます。

    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-undertow</artifactId>
    </dependency>

「mvn dependency:tree」で依存関係を見ると、Servlet APIは追加されるものの、その背後にいるのはVert.xですね。

[INFO] \- io.quarkus:quarkus-undertow:jar:1.1.1.Final:compile
[INFO]    +- io.quarkus:quarkus-arc:jar:1.1.1.Final:compile
[INFO]    |  \- io.quarkus.arc:arc:jar:1.1.1.Final:compile
[INFO]    +- io.quarkus.security:quarkus-security:jar:1.0.1.Final:compile
[INFO]    +- jakarta.enterprise:jakarta.enterprise.cdi-api:jar:2.0.2:compile
[INFO]    |  +- jakarta.el:jakarta.el-api:jar:3.0.3:compile
[INFO]    |  \- jakarta.interceptor:jakarta.interceptor-api:jar:1.2.5:compile
[INFO]    +- io.quarkus.http:quarkus-http-servlet:jar:3.0.1.Final:compile
[INFO]    +- jakarta.servlet:jakarta.servlet-api:jar:4.0.3:compile
[INFO]    +- jakarta.annotation:jakarta.annotation-api:jar:1.3.5:compile
[INFO]    +- io.quarkus.http:quarkus-http-vertx-backend:jar:3.0.1.Final:compile
[INFO]    |  +- io.vertx:vertx-core:jar:3.8.4:compile
[INFO]    |  |  +- io.netty:netty-common:jar:4.1.42.Final:compile
[INFO]    |  |  +- io.netty:netty-buffer:jar:4.1.42.Final:compile
[INFO]    |  |  +- io.netty:netty-transport:jar:4.1.42.Final:compile
[INFO]    |  |  +- io.netty:netty-handler:jar:4.1.42.Final:compile
[INFO]    |  |  +- io.netty:netty-handler-proxy:jar:4.1.42.Final:compile
[INFO]    |  |  |  \- io.netty:netty-codec-socks:jar:4.1.42.Final:compile
[INFO]    |  |  +- io.netty:netty-codec-http2:jar:4.1.42.Final:compile
[INFO]    |  |  +- io.netty:netty-resolver:jar:4.1.42.Final:compile
[INFO]    |  |  \- io.netty:netty-resolver-dns:jar:4.1.42.Final:compile
[INFO]    |  |     \- io.netty:netty-codec-dns:jar:4.1.42.Final:compile
[INFO]    |  \- io.quarkus.http:quarkus-http-http-core:jar:3.0.1.Final:compile
[INFO]    +- io.quarkus.http:quarkus-http-core:jar:3.0.1.Final:compile
[INFO]    |  \- io.netty:netty-codec-http:jar:4.1.42.Final:compile
[INFO]    |     \- io.netty:netty-codec:jar:4.1.42.Final:compile
[INFO]    \- org.eclipse.microprofile.context-propagation:microprofile-context-propagation-api:jar:1.0.1:com

アプリケーションの起動時には、ExtensionとしてServletが認識されています。

2020-01-25 19:18:56,652 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy, resteasy-jackson, servlet]

起動時に、XNIOのログも出力されず、スレッドダンプを取ったりするとNettyが現れるので、完全にNettyベースになったんですねぇ。

"vert.x-acceptor-thread-0" #31 prio=5 os_prio=0 tid=0x00007f46780a2800 nid=0x4722 runnable [0x00007f46a2dee000]
   java.lang.Thread.State: RUNNABLE
    at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
    at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
    at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
    at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
    - locked <0x00000006c6c26e60> (a io.netty.channel.nio.SelectedSelectionKeySet)
    - locked <0x00000006c6c27f60> (a java.util.Collections$UnmodifiableSet)
    - locked <0x00000006c6c27e88> (a sun.nio.ch.EPollSelectorImpl)
    at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
    at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62)
    at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:824)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:457)
    at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1044)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Thread.java:748)

"vert.x-eventloop-thread-15" #30 prio=5 os_prio=0 tid=0x00007f4711177800 nid=0x4721 runnable [0x00007f46a30ef000]
   java.lang.Thread.State: RUNNABLE
    at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
    at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
    at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
    at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
    - locked <0x00000006c6c06978> (a io.netty.channel.nio.SelectedSelectionKeySet)
    - locked <0x00000006c6c07a98> (a java.util.Collections$UnmodifiableSet)
    - locked <0x00000006c6c079a0> (a sun.nio.ch.EPollSelectorImpl)
    at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
    at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62)
    at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:824)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:457)
    at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1044)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Thread.java:748)


〜省略〜

"vert.x-eventloop-thread-0" #15 prio=5 os_prio=0 tid=0x00007f471115e000 nid=0x4712 runnable [0x00007f46a3ffe000]
   java.lang.Thread.State: RUNNABLE
    at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
    at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
    at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
    at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
    - locked <0x00000006c6ce4040> (a io.netty.channel.nio.SelectedSelectionKeySet)
    - locked <0x00000006c6ce5150> (a java.util.Collections$UnmodifiableSet)
    - locked <0x00000006c6ce5068> (a sun.nio.ch.EPollSelectorImpl)
    at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
    at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62)
    at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:824)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:457)
    at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1044)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Thread.java:748)

"vertx-blocked-thread-checker" #13 daemon prio=5 os_prio=0 tid=0x00007f4710e52000 nid=0x4711 in Object.wait() [0x00007f46ac3db000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000006c6ce6148> (a java.util.TaskQueue)
    at java.util.TimerThread.mainLoop(Timer.java:552)
    - locked <0x00000006c6ce6148> (a java.util.TaskQueue)
    at java.util.TimerThread.run(Timer.java:505)

〜省略〜

先ほど作成したJAX-RSリソースクラスを使って、スタックトレースを出力してみます。

2020-01-25 19:18:58,459 INFO  [org.lit.qua.res.HttpRequestResource] (executor-thread-1) Thread[executor-thread-1 / org.jboss.threads.JBossThread]
java.lang.Exception: Stack trace
    at java.lang.Thread.dumpStack(Thread.java:1336)
    at org.littlewings.quarkus.resteasy.HttpRequestResource.printThreadDump(HttpRequestResource.java:38)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:151)
    at org.jboss.resteasy.core.MethodInjectorImpl.lambda$invoke$3(MethodInjectorImpl.java:122)
    at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:616)
    at java.util.concurrent.CompletableFuture.uniApplyStage(CompletableFuture.java:628)
    at java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:1996)
    at java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:110)
    at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:122)
    at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:594)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:468)
    at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:421)
    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:363)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:423)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:391)
    at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invoke$1(ResourceMethodInvoker.java:365)
    at java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:995)
    at java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2137)
    at java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:110)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:365)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:477)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:252)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:153)
    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:363)
    at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:156)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:238)
    at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:249)
    at io.quarkus.resteasy.runtime.ResteasyFilter$ResteasyResponseWrapper.sendError(ResteasyFilter.java:65)
    at io.undertow.servlet.handlers.DefaultServlet.doGet(DefaultServlet.java:172)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:503)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:590)
    at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
    at io.quarkus.resteasy.runtime.ResteasyFilter.doFilter(ResteasyFilter.java:28)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:63)
    at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
    at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:133)
    at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
    at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:65)
    at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
    at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
    at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
    at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:270)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:59)
    at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:116)
    at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:113)
    at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
    at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
    at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$9$1$1.call(UndertowDeploymentRecorder.java:482)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:250)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:59)
    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:82)
    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:290)
    at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:669)
    at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
    at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1535)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1395)
    at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
    at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
    at java.lang.Thread.run(Thread.java:748)
    at org.jboss.threads.JBossThread.run(JBossThread.java:479)

ここでは、がっつりとUndertowのAPIが登場します。

この状態だと、Servlet APIが利用可能になります。

    @GET
    @Path("print-servlet-request")
    @Produces(MediaType.APPLICATION_JSON)
    public Map<String, Object> printServletRequest(@Context HttpServletRequest request) {
        Map<String, Object> response = new LinkedHashMap<>();

        response.put("method", request.getMethod());
        response.put("request-url", request.getRequestURL());
        response.put("request-uri", request.getRequestURI());
        response.put("query", request.getQueryString());

        return response;
    }

確認。

$ curl -s localhost:8080/http-request/print-servlet-request?param=hoge | jq
{
  "method": "GET",
  "request-url": "http://localhost:8080/http-request/print-servlet-request",
  "request-uri": "/http-request/print-servlet-request",
  "query": "param=hoge"
}

メソッド追加後のコードは、こちら。
src/main/java/org/littlewings/quarkus/resteasy/HttpRequestResource.java

package org.littlewings.quarkus.resteasy;

import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest;

@Path("http-request")
public class HttpRequestResource {
    Logger logger = Logger.getLogger(HttpRequestResource.class);

    @GET
    @Path("print-request")
    @Produces(MediaType.APPLICATION_JSON)
    public Map<String, Object> printRequest(@Context HttpRequest request) {
        Map<String, Object> response = new LinkedHashMap<>();

        response.put("method", request.getHttpMethod());
        response.put("request-uri", request.getUri().getRequestUri().toString());
        response.put("path", request.getUri().getPath());
        response.put("query", request.getUri().getRequestUri().getQuery());

        return response;
    }

    @GET
    @Path("thread-dump")
    @Produces(MediaType.TEXT_PLAIN)
    public String printThreadDump() {
        logger.infof("Thread[%s / %s]", Thread.currentThread().getName(), Thread.currentThread().getClass().getName());

        Thread.dumpStack();

        return "print Thread Dump";
    }

    @GET
    @Path("print-servlet-request")
    @Produces(MediaType.APPLICATION_JSON)
    public Map<String, Object> printServletRequest(@Context HttpServletRequest request) {
        Map<String, Object> response = new LinkedHashMap<>();

        response.put("method", request.getMethod());
        response.put("request-url", request.getRequestURL());
        response.put("request-uri", request.getRequestURI());
        response.put("query", request.getQueryString());

        return response;
    }
}

ところでですね、依存関係にUndertowの名前がほとんど登場しなかったのに、スレッドダンプを見たらいきなり出てきたのがちょっと
気になります。

どうやら、こちらが実体のようですね。

GitHub - quarkusio/quarkus-http

A Vert.x based Servlet implementation.

らしいです。

こちらに置かれているコードのパッケージは、「io.undertow」となっていますし。

とりあえず、見たかったものはざっくりと見れたので、ここまで。