RESTEasy annotation scan unable to find resources (under Tomcat) - java

I'm trying to update WAR with old RESTEasy 3.0.5 to something newer. 3.0.6 works fine, but after updating to 3.0.7 (or higher, like 3.0.24) all resources (#Path) are lost — 404 for any resource. WAR is run under Apache Tomcat server.
I believe the reason is linked to change of annotation scanner:
https://issues.jboss.org/browse/RESTEASY-1010
I've tried to create class which extends javax.ws.rs.core.Application instead of web.xml configuration. According to answer https://stackoverflow.com/a/29957040/2528366, empty set should trigger scan for #Path but no any resource is found. If I override getClasses() which returns non-empty set, that resources work as expected.
web.xml: https://pastebin.com/uRD2w6Z6
New Application inherited class:
#ApplicationPath("/rest")
public class WebApi extends Application
{
#Override
public Set<Class<?>> getClasses()
{
Set<Class<?>> s = new HashSet<>();
// if line below is uncommented SomeResource works fine
// s.add(SomeResourceImpl.class);
return s;
}
}
Resources are interfaces and implementation is in derived classes. Moving annotations to classes itself changes nothing.
What's wrong with annotations or configuration? Or is there something else needed to trigger scanning for annotations?

If you are using a Tomcat version that is compatible with the Servlet 3.0 specification, you need to add the resteasy-servlet-initializer dependency :
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-servlet-initializer</artifactId>
<version>${resteasy.version}</version>
</dependency>
As stated in the documentation :
Resteasy uses the ServletContainerInitializer integration interface in Servlet 3.0 containers to initialize an application, automatically scanning for resources and providers. To enable automatic scanning, you must also include the resteasy-servlet-initializer artifact in your WAR file as well

Related

Use #ArquillianResource to inject URL when deploying an EnterpriseArchive

I am using Arquillian for functional testing an application against a Jakarta EE application server.
I am running into an issue where I am unable to properly inject the servlet URL to test against.
public class SecurityTests extends ArquillianTests {
#ArquillianResource(SecurityServlet.class)
URL baseURL;
#Deployment(testable=false)
public static EnterpriseArchive createDeployment() {
WebArchive war = ShrinkWrap.create(WebArchive.class)
.addPackages(true, SecurityServlet.class.getPackage());
JavaArchive jar = ShrinkWrap.create(JavaArchive.class)
.addClasses(SecurityTestRemote.class, SecurityTestEjb.class)
.addAsManifestResource(ContextTests.class.getPackage(), "ejb-jar.xml", "ejb-jar.xml");
EnterpriseArchive ear = ShrinkWrap.create(EnterpriseArchive.class)
.addAsModules(war, jar)
.addAsManifestResource(ContextTests.class.getPackage(), "sun-ejb-jar.xml", "sun-ejb-jar.xml");
return ear;
}
}
#WebServlet("/SecurityServlet")
public class SecurityServlet extends HttpServlet
When my Enterprise Archive is deployed, the archive and its' modules are all given random names, such as:
> 681737db-3621-4b1a-b77a-4f571b877126.ear
> META-INF
> 5f6d70e5-13f9-4d49-a32f-c7b3138da9fa.war
> WEB-INF ...
> 90772573-9202-4c77-b8b9-99b5869dd29f.jar
> META-INF ...
If I just use #ArquillianResource URL baseURL;
Then baseURL will be set to http://localhost:8010/681737db-3621-4b1a-b77a-4f571b877126
The servlet, however, is deployed the endpoint that matches the modules name so I would expect to get http://localhost:8010/5f6d70e5-13f9-4d49-a32f-c7b3138da9fa
If I use #ArquillianResource(SecurityServlet.class) URL baseURL;
Then I get an exception
arquillianBeforeTest(jakarta.enterprise.concurrent.spec.ManagedScheduledExecutorService.security.SecurityTests) Time elapsed: 4.134 sec <<< FAILURE!
java.lang.RuntimeException: Could not lookup value for field java.net.URL jakarta.enterprise.concurrent.spec.ManagedScheduledExecutorService.security.SecurityTests.baseURL
at org.jboss.arquillian.test.impl.enricher.resource.ArquillianResourceTestEnricher.enrich(ArquillianResourceTestEnricher.java:68)
at org.jboss.arquillian.test.impl.TestInstanceEnricher.enrich(TestInstanceEnricher.java:51)
Caused by: java.lang.RuntimeException: All Providers for type class java.net.URL returned a null value: [org.jboss.arquillian.container.test.impl.enricher.resource.URLResourceProvider#9e28539]
at org.jboss.arquillian.test.impl.enricher.resource.ArquillianResourceTestEnricher.lookup(ArquillianResourceTestEnricher.java:126)
at org.jboss.arquillian.test.impl.enricher.resource.ArquillianResourceTestEnricher.enrich(ArquillianResourceTestEnricher.java:66)
at org.jboss.arquillian.test.impl.TestInstanceEnricher.enrich(TestInstanceEnricher.java:51)
at org.jboss.arquillian.container.test.impl.ClientTestInstanceEnricher.enrich(ClientTestInstanceEnricher.java:48)
Questions:
Is my assumption correct that I need to use #ArquillianResource(SecurityServlet.class)?
If yes, could the exception be caused by the container implementation I am using? (I am using OpenLiberty)
If no, what is the correct way to get the module's URL?
Update:
Liberty features enabled
<featureManager>
<!-- Features being tested -->
<feature>jakartaee-9.1</feature>
<!-- Supporting features -->
<feature>jndi-1.0</feature>
<!-- Features needed for arquillan support -->
<feature>localConnector-1.0</feature>
<feature>restConnector-2.0</feature>
<feature>arquillian-support-jakarta-2.0</feature>
</featureManager>
Dependencies
<dependency>
<groupId>io.openliberty.arquillian</groupId>
<artifactId>arquillian-liberty-remote-jakarta-testng</artifactId>
<version>2.0.2</version>
<type>pom</type>
<scope>test</scope>
<dependency>
Edit note: I see from your update you're using the remote container so I'm adding a section about that.
Using the managed container
I think your test code is correct. The liberty arquillian container has a test here which is similar.
If you're using Java EE 7 or 8 features, make sure you have the j2eeManagement-1.1 feature enabled as the liberty arquillian container uses it to find the correct context root for the servlet. Docs here.
<feature>j2eeManagement-1.1</feature> <!-- Optional, needed to allow injection on ArquillianResources related to servlets -->
If you're using Jakarta EE 9 features, it should work without this.
Using the remote container
It looks like the logic for finding servlets is missing from the remote container (as of the current version 2.0.1).
Please can you open an issue on the liberty-arquillian repository?
In the short term, if possible, you could try using the managed container instead.

Jackson with JodaTime and Jax-rs

I have a REST web-service created in Java. I am using Joda-time for the date and Jackson for the JSON formatting. Everything is uploaded on a Glassfish 4.1 server
Versions
avax.ws.rs-api-2.0.1.jar
joda-time-2.7.jar
jackson-annotation-2.8.8.jar
jackson-core-2.8.8.jar
jackson-databind-2.8.8.jar
jackson.datatype-joda-2.8.8.jar
Mapper
#Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper>{
final ObjectMapper mapper = new ObjectMapper();
public ObjectMapperContextResolver() {
mapper.registerModule(new JodaModule());
}
#Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}
}
Error when calling the service
java.lang.NoSuchFieldError: WRITE_DURATIONS_AS_TIMESTAMPS
What I found
I already found that it may have a mismatch between different versions. All the jars come from maven repository and I took each times the dependencies needed.
Question
What am I missing ? Is there a missing library ? Is there a wrong library's version ?
Note: I am not using Maven
Update
I tried to update the jackson-?.jars inside glassfish4.1/glassfish/modules but now I cant even start the server because of a requirement mismatch with jackson versions
Updates 2
Is there a way to use the jackson libraries that are inside my project instead of the one in Glassfish ? This seems to be the solution
Is there a way to use the Jackson libraries that are inside my project instead of the one in Glassfish? This seems to be the solution.
See the following quote from the chapter 2 of the GlassFish 4 Application Development Guide:
The Java Servlet specification recommends that a web module's class loader look in the local class loader before delegating to its parent. You can make this class loader follow the delegation inversion model in the Servlet specification by setting delegate="false" in the class-loader element of the glassfish-web.xml file. It is safe to do this only for a web module that does not interact with any other modules. [...]
The default value is delegate="true", which causes a web module's class loader to delegate in the same manner as the other class loaders. You must use delegate="true" for a web application that accesses EJB components or that acts as a web service client
or endpoint. [...]
For a number of packages, including java.* and javax.*, symbol resolution is always delegated to the parent class loader regardless of the delegate setting. This prevents applications from overriding core Java runtime classes or changing the API versions of specifications that are part of the Java EE platform.
In the section B of the GlassFish 4 Application Deployment Guide you'll find an example of the glassfish-web.xml deployment descriptor. Tailoring it to your issue, your glassfish-web.xml file would be like:
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD
GlassFish Application Server 3.1 Servlet 3.0//EN"
"http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app>
<class-loader delegate="false" />
</glassfish-web-app>
Then place it under WEB-INF of your web module.

JAX-RS - Loading #Provider classes from a jar file

I have a simple Rest application that is deployed to an IBM MobileFirst 7.1 Liberty Server. (I don't know the implementation of the JAX-RS but it is included with the liberty server runtime I believe)
I have to share some of my common code with other teams, so I moved some of the code into a separate maven project to be jared and added as a server library. This all works great until I had to add some #Provider annotated classes into the separate maven project. Specifically, some ExceptionMapper implementations marked with the #Provider annotation.
I have tried setting the class directly within the Application classes getClasses() method. This seemed to work, but I get a warning message saying that my exception mapper implementations need to be marked with the #Provider or #Path annotations (which they are).
Is there some sort of trick to get JAX-RS to recognize these resource classes from a Jar file?
In order to have the #Provider recognized, please try to put the JAR inside the adapter /lib folder instead of the server/lib folder.

How to write Jersey Multipart webapp, Tomcat Server

I've been doing a lot of REST tutorials and enjoying them. Recently, I tried writing a jersey multipart webapp with Netbeans but I can't seem to because it seems something's missing my jersey library.
I downloaded the jersey-multipart.jar file, but still that didn't help:
#Path("/file")
public class UploadFileService {
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(
#FormDataParam("file") InputStream uploadedInputStream,
#FormDataParam("file") FormDataContentDisposition fileDetail) {
This code is from blog. I'm trying to put it in my webapp, but the #FormDataParam tag and the FormDataContentDisposition class are not recognised. I downloaded the jersey-multipart.jar and that seemed to solve the #FormDataParam tag problem, but not the FormDataContentDisposition class.
I'm using Tomcat 7.0.
How do I go about successfully creating a jersey multipart webapp without any problems? And how come the jersey-multipart jar file isn't included in the jersey library in Netbeans?
Thanks.
Lutz Horn has a point, but for the sake of those using Netbeans 7.4 (Java EE 6) and are still struggling with this issue, here's a step by step on how to create your very own multipart rest web service and deploying on Tomcat, with Netbeans. (Note, deploying on Glassfish requires a slightly different configuration which isn't covered in this answer).
First off, my suggestion is to create a maven web application and not a normal web application. Reason is, the JAX-RS and Jersey libraries that come with Java EE 6 are not sufficient enough, and once you start fiddling around with external jars, things tend to get messy, especially with Jersey. (Hopefully, this has been corrected in Netbeans 8.0 (Java EE 7)).
(1) Create a maven web-app, choose Java EE 6 and Tomcat 7. Once you're done, you'll notice you don't have a web.xml. Most multipart tutorials will tell you to include certain configurations in your web.xml file. Don't bother with that. You don't need a web.xml file.
(2) Create a RESTfull web service by either writing it manually or using the wizard (right click on your maven web-app -- New -- Other -- Web Services -- [choose the RESTful web service you want])
(3) Open your pom.xml (you can find it under the Project Files folder in your maven web-app) and add these dependencies:
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.7</version>
</dependency>
If you're doing this for the first time, you need an active internet connection, as maven will download the dependencies from its central repository.
(4) Go to your ApplicationConfig class or whatever class that holds that contains your #ApplicationPath(). It should look like this:
#javax.ws.rs.ApplicationPath("webresources")
public class ApplicationConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<Class<?>>();
resources.add(MultiPartFeature.class);
addRestResourceClasses(resources);
return resources;
}
/**
* Do not modify addRestResourceClasses() method.
* It is automatically populated with
* all resources defined in the project.
* If required, comment out calling this method in getClasses().
*/
private void addRestResourceClasses(Set<Class<?>> resources) {
resources.add(com.mycompany.mavenrestuploader.UploaderResource.class);
}
Note: resources.add(MultiPartFeature.class); That has to be included, otherwise Jersey multipart won't work.
The reason I put that line of code in the getClasses method and not the addRestResourceClasses method is because the addRestResourceClasses method gets modified whenever there's a change to your resource class, and if you include the MultiPartFeature code in there, it will get erased.
Once you've done all these things, you are good to go.
If you're just looking to create a RESTful web service without multipart, follow steps 1 to 3, but in step 3 do not include the jersey-media-multipart dependency.
I hope this helps you ;)
The imports for these two are
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
If you use Maven, add this dependencies:
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.0</version>
<type>jar</type>
</dependency>
Together with jersey-media-multipart dependency, instead of Application (see below) you can configure ResourceConfig:
#ApplicationPath("/")
public class AppConfig extends ResourceConfig {
public AppConfig() {
packages("packages.to.scan");
register(MultiPartFeature.class);
}
}
or Jersey REST configuration in web.xml:
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>

AbstractAnnotationConfigDispatcherServletInitializer with Jetty

I'm using Jetty 9.1.0.RC2 and Spring 4.
Have a AbstractAnnotationConfigDispatcherServletInitializer and trying to kick start the initialization with:
Server server = new Server();
WebAppContext webAppContext = new WebAppContext();
webAppContext.setContextPath("/");
webAppContext.setConfigurations(new Configuration[] { new AnnotationConfiguration() });
webAppContext.setParentLoaderPriority(true);
webAppContext.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", ".*/target/classes/.*");
server.setHandler(webAppContext);
server.start();
server.join();
But failing to detect:
No Spring WebApplicationInitializer types detected on classpath
This is a common problem. Many more people are facing this issue. Sometimes it is causing error or sometimes it gives just as info. For info, there is no problem(just like warning). For error, there are many types of reason for occuring this error. I am trying to give you some sort of solutions.
Sometimes spring library and jdk version mismatch causes this error.
Classes are built in lower version of jdk and trying to run in upper
version may cause the error. Then we need to change using Eclipse
from Preferences\Java\Compiler We have to set "compiler compliance
level: 1.7" and "Generated .class files compatibility: 1.6", "Source
compatibility: 1.6".
Some of people get that log4j wasn't configured to capture error
output which was throwing configuration errors in the background.
If you are using maven, then WEB-INF directory must be inside your
webapp. Structure will be src/main/webapp/WEB-INF It also solves
this issue.
If "Project -> Build Automatically" is not selected. You can force
the "m2e-wtp folder and contents" generation by doing;
"(right-click
on your project) -> Maven -> Update Project..."
Note: make sure the
"Clean Projects" option is un-selected. Otherwise the contents of
target/classes will be deleted and you're back to square one.
Add WebROOT file directory to the default directory, then this
problem will be solved.
properties->MyEclipse->Deployment
Assembly->Add
Resource Link:
No Spring WebApplicationInitializer types detected on classpath
INFO: No Spring WebApplicationInitializer types detected on classpath
only one error: No Spring WebApplicationInitializer types detected on classpath
For tomcat,
if maven has tomcat7 plugin but the JRE environment was 1.6. Then
this problem occurs. Then you need to downgrade tomcat7 to tomcat6
or upgrade jdk and jre version to 1.7.
Sometimes it is need to stop your tomcat. Then clean the project,
clean the server and run again your project. Sometimes caches make this
issue. After following this way, it may solve.
For JBOSS,
#Sotirios Delimanolis given a very nice answer. That is given below:
In a typical servlet application, you would have a web.xml descriptor file to declare your serlvets, filters, listeners, context params, security configuration, etc. for your application. Since servlet 3.0 you can do most of that programmatically.
Servlet 3.0 offers the interface ServletContainerInitializer, which you can implement. Your servlet container will look for your implementation of that class in META-INF/services/javax.servlet.ServletContainerInitializer file, instantiate it, and call its onStartup() method.
Spring has built WebApplicationInitializer on top of that interface, as an adapter/helper.
You need either the web.xml descriptor or a class that implements WebApplicationInitializer to setup and run your application.
Resource Link:
Jboss No Spring WebApplicationInitializer types detected on classpath
A brief detail answer is given below with Jetty:
Spring WebApplicationInitializer - how it works and what may go wrong
Startup of servlet contexts without web.xml
Servlets of release 3 can be configured programatically, without any web.xml.
With Spring and its Java-configuration you create a configuration class that implements org.springframework.web.WebApplicationInitializer.
Spring will automatically find all classes that implement this interface and start the according servlet contexts. More excatly its not Spring that searches for those classes, its the servlet container (e.g. jetty or tomcat ).
The class org.springframework.web.SpringServletContainerInitializer is annotated with
#javax.servlet.annotation.HandlesTypes(WebApplicationInitializer.class)
and implements javax.servlet.ServletContainerInitializer
According to the Servlet 3 specification the container will call org.springframework.web.SpringServletContainerInitializer.onStartup(Set<Class<?>>, ServletContext) on every class in the classpath implementing that interface, suppling a set of classes as defined in HandlesTypes
Startup order, if there is more than one context
If there is more than one class that implements WebApplicationInitializer, the order in which they are started can be controlled with the annotation org.springframework.core.Ordered .
Things that may go wrong
Different Spring versions in the classpath
If you have different versions of WebApplicationInitializer in the classpath, the servlet container may scan for the classes implementing WebApplicationInitializer of version 'A' while your configuration classes implement WebApplicationInitializer of version 'B'. And than your configuration classes will not be found and the sercletontexts will not be started.
Unexpected WebApplicationInitializers in the classpath
Do not package any WebApplicationInitializers into jars or wars that you later may have in the classpath of other web applications. They may get found and started when you do not expect it. This happend to me when I packed WebApplicationInitializers with Maven into test-jars, which were reused by other tests.
To many classes in the classpath
The servlet container has to scan the classpath, and the more classes, the longer it takes.
At least Jetty has a build in timeout, so you may get an
javax.websocket.DeploymentException thrown by
org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer
The solution is to tell jetty which jars to scan. This will make the
startup much faster and avoids the timeout. In Maven you can do it
like this :
pom.xml
<plugin>
<groupId> org.eclipse.jetty</groupId >
<artifactId> jetty-maven-plugin</artifactId >
<configuration>
<webAppConfig>
<contextPath> /${project.artifactId}</contextPath >
<webInfIncludeJarPattern> busines-letter-*.</webInfIncludeJarPattern >
</webAppConfig>
Spring logging
When you have logging configured you should find one of the following entries in your log :
If Spring finds no WebApplicationInitializer at all, you will see in the log :
No Spring WebApplicationInitializer types detected on classpath
If Spring finds at least one WebApplicationInitializer you will see :
Spring WebApplicationInitializers detected on classpath: " + initializers

Categories