0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Open LibertyのJAX-RS実装がJSONを扱う際のライブラリを確認する

Last updated at Posted at 2024-10-18

What's?

Open LibertyのJakarta RESTful Web Services(JAX-RS)のリファレンスを見ていて、JSONをどうやって処理しているのかがわからなかったので確認してみようかなと。

Jakarta RESTful Web Services

結果としては、Jakarta JSON Binding(JSON-B)でした。

Jakarta JSON Binding

環境

$ java --version
openjdk 21.0.4 2024-07-16
OpenJDK Runtime Environment (build 21.0.4+7-Ubuntu-1ubuntu222.04)
OpenJDK 64-Bit Server VM (build 21.0.4+7-Ubuntu-1ubuntu222.04, mixed mode, sharing)


$ mvn --version
Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937)
Maven home: /home/charon/.sdkman/candidates/maven/current
Java version: 21.0.4, vendor: Ubuntu, runtime: /usr/lib/jvm/java-21-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "5.15.0-124-generic", arch: "amd64", family: "unix"

Open Libertyプロジェクトを作成する

Get started(Create a starter application)を使って、Open LibertyのMavenプロジェクトを作成。

$ curl -G https://start.openliberty.io/api/start \
  -o jaxrs-sample.zip \
  -d a=jaxrs-sample \
  -d b=maven \
  -d e=10.0 \
  -d g=com.example \
  -d j=21 \
  -d m=6.1

zipを展開。

$ unzip -d jaxrs-sample jaxrs-sample.zip
Archive:  jaxrs-sample.zip
   creating: jaxrs-sample/src/main/java/com/example/
  inflating: jaxrs-sample/src/main/liberty/config/server.xml
  inflating: jaxrs-sample/Dockerfile
  inflating: jaxrs-sample/.dockerignore
  inflating: jaxrs-sample/src/main/java/com/example/rest/RestApplication.java
  inflating: jaxrs-sample/README.txt
  inflating: jaxrs-sample/.mvn/wrapper/maven-wrapper.jar
  inflating: jaxrs-sample/.mvn/wrapper/maven-wrapper.properties
  inflating: jaxrs-sample/mvnw
  inflating: jaxrs-sample/mvnw.cmd
  inflating: jaxrs-sample/pom.xml
  inflating: jaxrs-sample/.gitignore
  inflating: jaxrs-sample/src/main/resources/META-INF/microprofile-config.properties

pom.xmlserver.xmlを少し修正して、JAX-RSソースコードを作成。

Applicationのサブクラスは、@ApplicationPathのパスだけ修正しました。

src/main/java/com/example/rest/RestApplication.java
package com.example.rest;

import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;

@ApplicationPath("/")
public class RestApplication extends Application {

}

JSONを使ったリクエスト、レスポンスに対応するクラス。

src/main/java/com/example/rest/CalcRequest.java
package com.example.rest;

public class CalcRequest {
    private Integer x;
    private Integer y;

    public CalcRequest() {
        System.out.println("CalcRequest@constructor");
        Thread.dumpStack();
    }

    public Integer getX() {
        return x;
    }

    public void setX(Integer x) {
        System.out.println("CalcRequest@setY");
        Thread.dumpStack();
        this.x = x;
    }

    public Integer getY() {
        return y;
    }

    public void setY(Integer y) {
        this.y = y;
    }
}
src/main/java/com/example/rest/CalcResponse.java
package com.example.rest;

public class CalcResponse {
    private Integer result;

    public CalcResponse(Integer result) {
        this.result = result;
    }

    public Integer getResult() {
        System.out.println("CalcResponse@getX");
        Thread.dumpStack();
        return result;
    }

    public void setResult(Integer result) {
        this.result = result;
    }
}

呼び出し確認ができるように、Thread#dumpStackを仕込んでいます。

JAX-RSリソースクラス。

src/main/java/com/example/rest/CalcResource.java
package com.example.rest;

import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/calc")
public class CalcResource {
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public CalcResponse calc(CalcRequest request) {
        return new CalcResponse(request.getX() + request.getY());
    }
}

JSONを処理しているライブラリを確認する

ビルド、起動。

$ mvn compile liberty:dev

確認。

$ curl -X POST -H 'Content-Type: application/json' localhost:9080/calc -d '{"x": 10, "y": 15}'
{"result":25}

この時に得られたスタックトレース。

[INFO] CalcRequest@constructor
[INFO] [err] java.lang.Exception: Stack trace
[INFO] [err]    at java.base/java.lang.Thread.dumpStack(Thread.java:2209)
[INFO] [err]    at com.example.rest.CalcRequest.<init>(CalcRequest.java:9)
[INFO] [err]    at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62)
[INFO] [err]    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502)
[INFO] [err]    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486)
[INFO] [err]    at org.eclipse.yasson.internal.ReflectionUtils.createNoArgConstructorInstance(ReflectionUtils.java:282)
[INFO] [err]    at [internal classes]
[INFO] [err]    at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:413)
[INFO] [err]    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:385)
[INFO] [err]    at [internal classes]
[INFO] [err]    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:240)
[INFO] [err]    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:154)
[INFO] [err]    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:385)
[INFO] [err]    at [internal classes]
[INFO] [err]    at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614)
[INFO] [err]    at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1266)
[INFO] [err]    at [internal classes]
[INFO] [err]    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
[INFO] [err]    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
[INFO] [err]    at java.base/java.lang.Thread.run(Thread.java:1583)
[INFO] CalcRequest@setY
[INFO] [err] java.lang.Exception: Stack trace
[INFO] [err]    at java.base/java.lang.Thread.dumpStack(Thread.java:2209)
[INFO] [err]    at com.example.rest.CalcRequest.setX(CalcRequest.java:18)
[INFO] [err]    at org.eclipse.yasson.internal.deserializer.ValueSetterDeserializer.deserialize(ValueSetterDeserializer.java:37)
[INFO] [err]    at [internal classes]
[INFO] [err]    at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:413)
[INFO] [err]    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:385)
[INFO] [err]    at [internal classes]
[INFO] [err]    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:240)
[INFO] [err]    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:154)
[INFO] [err]    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:385)
[INFO] [err]    at [internal classes]
[INFO] [err]    at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614)
[INFO] [err]    at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1266)
[INFO] [err]    at [internal classes]
[INFO] [err]    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
[INFO] [err]    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
[INFO] [err]    at java.base/java.lang.Thread.run(Thread.java:1583)
[INFO] CalcResponse@getX
[INFO] [err] java.lang.Exception: Stack trace
[INFO] [err]    at java.base/java.lang.Thread.dumpStack(Thread.java:2209)
[INFO] [err]    at com.example.rest.CalcResponse.getResult(CalcResponse.java:12)
[INFO] [err]    at org.eclipse.yasson.internal.serializer.ValueGetterSerializer.serialize(ValueGetterSerializer.java:39)
[INFO] [err]    at org.eclipse.yasson.internal.serializer.ObjectSerializer.lambda$serialize$0(ObjectSerializer.java:41)
[INFO] [err]    at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:986)
[INFO] [err]    at org.eclipse.yasson.internal.serializer.ObjectSerializer.serialize(ObjectSerializer.java:38)
[INFO] [err]    at [internal classes]
[INFO] [err]    at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.lambda$writeTo$1(ServerWriterInterceptorContext.java:74)
[INFO] [err]    at org.jboss.resteasy.plugins.server.servlet.Servlet3AsyncHttpRequest$Servlet3ExecutionContext.executeBlockingIo(Servlet3AsyncHttpRequest.java:392)
[INFO] [err]    at [internal classes]
[INFO] [err]    at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.lambda$getStarted$0(ServerWriterInterceptorContext.java:68)
[INFO] [err]    at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.aroundWriteTo(ServerWriterInterceptorContext.java:87)
[INFO] [err]    at [internal classes]
[INFO] [err]    at org.jboss.resteasy.core.ServerResponseWriter.lambda$writeNomapResponse$3(ServerResponseWriter.java:216)
[INFO] [err]    at org.jboss.resteasy.core.interception.jaxrs.ContainerResponseContextImpl.filter(ContainerResponseContextImpl.java:420)
[INFO] [err]    at [internal classes]
[INFO] [err]    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:240)
[INFO] [err]    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:154)
[INFO] [err]    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:385)
[INFO] [err]    at [internal classes]
[INFO] [err]    at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614)
[INFO] [err]    at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1266)
[INFO] [err]    at [internal classes]
[INFO] [err]    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
[INFO] [err]    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
[INFO] [err]    at java.base/java.lang.Thread.run(Thread.java:1583)

Eclipse Yassonなので、JSON-Bですね。

なお、使用するフィーチャーを絞り込む場合は、restfulWS-x.yだけではなくjsonb-x.yも必要です。

    <featureManager>
        <feature>restfulWS-3.1</feature>
        <feature>jsonb-3.0</feature>
    </featureManager>

jsonb-x.yがない場合は、JSONのリクエストを送信しても受け付けてもらえません

[INFO] RESTEASY003200: Could not find message body reader for type: class com.example.rest.CalcRequest of content type: application/json

pom.xmlとserver.xmlの変更箇所

このあたりを少し変更しました。

$ diff -u pom.xml*
--- pom.xml     2024-10-18 12:44:34.376505859 +0900
+++ pom.xml.org 2024-10-18 03:34:46.000000000 +0900
@@ -6,14 +6,13 @@

     <groupId>com.example</groupId>
     <artifactId>jaxrs-sample</artifactId>
-    <version>0.0.1-SNAPSHOT</version>
+    <version>1.0-SNAPSHOT</version>
     <packaging>war</packaging>

     <properties>
         <maven.compiler.source>21</maven.compiler.source>
         <maven.compiler.target>21</maven.compiler.target>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
     </properties>

     <dependencies>
@@ -52,15 +51,6 @@
             <plugin>
                 <groupId>io.openliberty.tools</groupId>
                 <artifactId>liberty-maven-plugin</artifactId>
-                <version>3.11.1</version>
-                <configuration>
-                  <runtimeArtifact>
-                    <groupId>io.openliberty</groupId>
-                    <artifactId>openliberty-kernel</artifactId>
-                    <version>24.0.0.10</version>
-                    <type>zip</type>
-                  </runtimeArtifact>
-                </configuration>
             </plugin>
         </plugins>
     </build>
$ diff -u src/main/liberty/config/server.xml*
--- src/main/liberty/config/server.xml  2024-10-18 12:44:28.900481784 +0900
+++ src/main/liberty/config/server.xml.org      2024-10-18 03:34:46.000000000 +0900
@@ -35,7 +35,7 @@
     <applicationManager autoExpand="true"/>

     <!-- Configures the application on a specified context root -->
-    <webApplication contextRoot="/" location="jaxrs-sample.war" />
+    <webApplication contextRoot="/jaxrs-sample" location="jaxrs-sample.war" />

     <!-- Default SSL configuration enables trust for default certificates from the Java runtime -->
     <ssl id="defaultSSLConfig" trustDefaultCerts="true" />
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?