Reputation: 316
I am trying to create a simple Rest API with Java 11, jax-rs and Tomee Plume 9 for the server.
After many conflicts between javax.X
and jakarta.X
, I was finally able to compile the project.
But when I try to run it on Intellij Idea, I get a 404 error on all my requests...
I have no errors in the logs.
Here my web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0"
metadata-complete="true">
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>fr.theogiraudet.rest</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
</web-app>
And an extract of my Rest resource, located in the package fr.theogiraudet.rest
:
@Path("/pianos")
public class PianoResource {
@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response getAllPianos(@Context UriInfo uriInfo) {
final var optParams = filter(uriInfo);
if (optParams.isEmpty())
return Response.status(Response.Status.BAD_REQUEST).build();
final var listOpt = dao.getAllPianos(optParams.get());
if (listOpt.isEmpty())
return Response.serverError().build();
return Response.ok().entity(listOpt.get().toArray(new Piano[0])).build();
}
}
My request: GET - http://localhost:8080/api/pianos
The application context is /
.
At server startup, the war seems to be well located and deployed, as seen in logs:
10-Aug-2021 21:09:58.897 INFOS [http-nio-8080-exec-4] org.apache.openejb.assembler.classic.Assembler.createApplication Deployed Application(path=E:\Programmation\IntelliJ\Pause Piano - Backend\target\pause-piano-backend-1.0-SNAPSHOT)
10-Aug-2021 21:09:59.188 INFOS [http-nio-8080-exec-4] org.apache.jasper.servlet.TldScanner.scanJars Au moins un fichier JAR a été analysé pour trouver des TLDs mais il n'en contenait pas, le mode "debug" du journal peut être activé pour obtenir une liste complète de JAR scannés sans succès ; éviter d'analyser des JARs inutilement peut améliorer sensiblement le temps de démarrage et le temps de compilation des JSPs
[2021-08-10 09:10:00,169] Artifact Pause Piano - Backend:war: Artifact is deployed successfully
[2021-08-10 09:10:00,169] Artifact Pause Piano - Backend:war: Deploy took 4,904 milliseconds
The project can be found here if you need more information about the code (like pom.xml): https://github.com/Pause-Piano/PausePiano-Backend
Upvotes: 1
Views: 1373
Reputation: 5751
You are using a version of swagger
, which does not support the jakarta
namespace. You have to upgrade to 2.1.7
or higher and add the related -jakarta
suffix to the artifact descriptors. In addition, you are using an unsupported jackson, which does not support jakarta
as well. You have to switch to jackson-jakarta-rs-providers
(see details below).
To reproduce the deployment process I quickly added the following plugin configuration to your pom.xml to run TomEE from within Maven via tomee:run
<plugin>
<groupId>org.apache.tomee.maven</groupId>
<artifactId>tomee-maven-plugin</artifactId>
<version>8.0.7</version>
<configuration>
<tomeeVersion>9.0.0-M7</tomeeVersion>
<tomeeClassifier>plume</tomeeClassifier>
<debug>true</debug>
<tomeeHttpPort>8282</tomeeHttpPort>
<debugPort>5005</debugPort>
<args>-Dfoo=bar</args>
<config>${project.basedir}/src/test/tomee/conf</config>
<skipCurrentProject>true</skipCurrentProject>
<webapps>
<webapp>
fr.pause-piano:pause-piano-backend:1.0-SNAPSHOT?name=ROOT
</webapp>
</webapps>
</configuration>
</plugin>
Then it tries to deploy your webapp, it will print some ClassNotFoundExceptions
to the console output indicating some hassle between javax
and jakarta
namespaces.
You are using a version of swagger
, which does not support the jakarta
namespace. The official repository on GitHub states:
NOTE: Since version 2.1.7 Swagger Core supports also Jakarta namespace, with a parallel set of artifacts with -jakarta suffix, providing the same functionality as the "standard" javax namespace ones. Please check Wiki for more details
That means, you have to upgrade the related artifacts in and suffix in your code to:
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-jakarta</artifactId>
<version>2.1.10</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-servlet-initializer-v2-jakarta</artifactId>
<version>2.1.10</version>
</dependency>
However, this will not be sufficient as the webapp is still using an unsupported jackson version, which does not support the jakarta
namespace (see GitHub):
(*) NOTE! JAX-RS is the "old" API defined under javax.ws.rs; in 2019 or so, Oracle decided to force a forking of this into "Jakarta" variant under jakarta.ws.ws. As of 2021 most frameworks still use the old API but if you do need/want to use newer one, check out Jakarta-RS provider repo at jackson-jakarta-rs-providers
You have to switch to jackson-jakarta-rs-providers
by replacing the jackson dependency in your project with
<dependency>
<groupId>com.fasterxml.jackson.jakarta.rs</groupId>
<artifactId>jackson-jakarta-rs-json-provider</artifactId>
<version>2.13.0-rc2</version>
</dependency>
After applying these changes, the webapp will still throw another ClassNotFoundException
. Using mvn dependency:tree
, we can see, that the updated swagger-jaxrs2-jakarta
pulls in a jackson-jaxrs-provider
dependency. Odd, isn't it? So we need to exclude it:
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-jakarta</artifactId>
<version>2.1.10</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
</exclusion>
</exclusions>
</dependency>
After that change, we can give it another try by running mvn clean install
and mvn tomee:run
. The log output logs good and shows the deployed endpoints:
31-Aug-2021 14:46:20.894 INFORMATION [main] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints REST Application: http://localhost:8282/sample -> fr.theogiraudet.swagger.Swagger@f25176a
31-Aug-2021 14:46:20.903 INFORMATION [main] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints Service URI: http://localhost:8282/sample/openapi -> Pojo io.swagger.v3.jaxrs2.integration.resources.AcceptHeaderOpenApiResource
31-Aug-2021 14:46:20.903 INFORMATION [main] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints GET http://localhost:8282/sample/openapi -> Response getOpenApiJson(HttpHeaders, UriInfo) throws Exception
31-Aug-2021 14:46:20.903 INFORMATION [main] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints GET http://localhost:8282/sample/openapi -> Response getOpenApiYaml(HttpHeaders, UriInfo) throws Exception
31-Aug-2021 14:46:20.905 INFORMATION [main] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints Service URI: http://localhost:8282/sample/openapi.{type:json|yaml} -> Pojo io.swagger.v3.jaxrs2.integration.resources.OpenApiResource
31-Aug-2021 14:46:20.905 INFORMATION [main] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints GET http://localhost:8282/sample/openapi.{type:json|yaml} -> Response getOpenApi(HttpHeaders, UriInfo, String) throws Exception
31-Aug-2021 14:46:20.905 INFORMATION [main] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints Service URI: http://localhost:8282/sample/pianos -> Pojo fr.theogiraudet.rest.PianoResource
31-Aug-2021 14:46:20.905 INFORMATION [main] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints DELETE http://localhost:8282/sample/pianos -> Response deleteAllPianos()
31-Aug-2021 14:46:20.906 INFORMATION [main] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints GET http://localhost:8282/sample/pianos -> Response getAllPianos(UriInfo)
31-Aug-2021 14:46:20.906 INFORMATION [main] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints GET http://localhost:8282/sample/pianos/{id} -> Response getPiano(int)
31-Aug-2021 14:46:20.906 INFORMATION [main] org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints POST http://localhost:8282/sample/pianos -> Response postPiano(PianoData)
31-Aug-2021 14:46:20.956 INFORMATION [main] jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke Deployment of web application archive [/home/zowallar/IdeaProjects/PausePiano-Backend/target/apache-tomee/webapps/ROOT.war] has finished in [4.433] ms
31-Aug-2021 14:46:20.968 INFORMATION [main] org.apache.catalina.core.StandardContext.setClassLoaderProperty Unable to set the web application class loader property [clearReferencesRmiTargets] to [true] as the property does not exist.
31-Aug-2021 14:46:20.969 INFORMATION [main] org.apache.catalina.core.StandardContext.setClassLoaderProperty Unable to set the web application class loader property [clearReferencesObjectStreamClassCaches] to [true] as the property does not exist.
31-Aug-2021 14:46:20.969 INFORMATION [main] org.apache.catalina.core.StandardContext.setClassLoaderProperty Unable to set the web application class loader property [clearReferencesObjectStreamClassCaches] to [true] as the property does not exist.
31-Aug-2021 14:46:20.969 INFORMATION [main] org.apache.catalina.core.StandardContext.setClassLoaderProperty Unable to set the web application class loader property [clearReferencesThreadLocals] to [true] as the property does not exist.
31-Aug-2021 14:46:20.989 INFORMATION [main] jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke Starting ProtocolHandler ["http-nio-8282"]
31-Aug-2021 14:46:21.003 INFORMATION [main] jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke Server startup in [4564] milliseconds
However, invoking a related endpoints leads to another exception:
jakarta.servlet.ServletException: Servlet.init() for servlet [fr.theogiraudet.swagger.Swagger] threw exception
org.apache.tomee.catalina.OpenEJBValve.invoke(OpenEJBValve.java:45)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:543)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
org.apache.tomee.catalina.OpenEJBSecurityListener$RequestCapturer.invoke(OpenEJBSecurityListener.java:97)
org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:353)
org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:870)
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1696)
org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
java.base/java.lang.Thread.run(Thread.java:829)
caused by
java.lang.IllegalStateException: The resource configuration is not modifiable in this context.
org.glassfish.jersey.server.ResourceConfig$ImmutableState.register(ResourceConfig.java:248)
org.glassfish.jersey.server.ResourceConfig$ImmutableState.register(ResourceConfig.java:195)
org.glassfish.jersey.server.ResourceConfig.register(ResourceConfig.java:428)
org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:306)
org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:154)
org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:347)
jakarta.servlet.GenericServlet.init(GenericServlet.java:158)
org.apache.tomee.catalina.OpenEJBValve.invoke(OpenEJBValve.java:45)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:543)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
org.apache.tomee.catalina.OpenEJBSecurityListener$RequestCapturer.invoke(OpenEJBSecurityListener.java:97)
org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:353)
org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:870)
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1696)
org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
java.base/java.lang.Thread.run(Thread.java:829)
Looking into the log reveals some issues with jackson
:
java.lang.NoClassDefFoundError: com/fasterxml/jackson/module/jaxb/JaxbAnnotationIntrospector
It looks like, that the related tooling (swagger
) in combination with jackson
is not yet ready to fully work with the jakarta
namespace. if you are not torn to use 9, you could simply switch to 8 with working tooling (as 9 only contains namespace changes).
Upvotes: 2