Java Restfull Webservice: Jax-Rs Implementation with Jersey 2.3.1 Libraries

Java RestFull WebService: JAX-RS implementation with Jersey 2.3.1 libraries

NoSuchMethodError usually means you are having two different versions of the class on your classpath. As the javax.ws.rs.core.Application class does have the getProperties() method in its JAX-RS 2 version, but not in JAX-RS 1.x, I would guess that somehow you are combining the old 1.x Jersey (or old REST api) with the current (2.3.1) one.

Also the package you are working in (com.sun.jersey - the 'old' Jersey package) points a bit towards this direction (although just placing your code into that package itself cannot cause the mentioned problem), you obviously started with the Jersey 1.x example as a base (there are samples in Jersey 2 as well, see helloworld-webapp on Jersey GitHub).

Is it possible, that restEasy (also definitely containing the javax.ws.rs.core.Application class) is not completely switched off and somehow defaults to JAX-RS 1.x version?

I would start with inspecting your pom file, look at the effective pom (if your project descriptor has some parent) and check carefully what is on your classpath - I believe there is a 1.x version of javax.ws.rs-api somewhere. Also try to clean all the compiled stuff and rebuild from scratch.

Speaking of dependencies, if your list is exhaustive (regarding Jersey), you will most likely have to add jersey-common (2.3.1) dependency, as already during the initialization, the ResourceConfig.packages() method calls the PackageScanner constructor, which contains call to ReflectionHelper - and this is not a part of the server jar any more.

Hope this helps.

Jersey 2 on Jboss 7

You can use Jersey 2 on JBoss 7 if you configure your jboss-deployment-structure.xml similar to this:

<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
<deployment>

<exclude-subsystems>
<subsystem name="resteasy" />
</exclude-subsystems>

<exclusions>
<module name="javaee.api" />
<module name="javax.ws.rs.api"/>
<module name="org.jboss.resteasy.resteasy-jaxrs" />
</exclusions>

<local-last value="true" />

</deployment>
</jboss-deployment-structure>

Because JBoss 7 includes dependencies of modules, it is not sufficient to exclude the resteasy module itself but you need to exclude the whole javaee.api module. Also make sure to not exclude too many modules. This may also break your application - the example above is sufficient to disable resteasy.

As you already discovered, you still need to include the following lines in your web.xml

  <context-param>
<param-name>resteasy.scan</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>resteasy.scan.providers</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>resteasy.scan.resources</param-name>
<param-value>false</param-value>
</context-param>

Spring Restfull Jax-RS annotation support

No, you cannot use javax.ws.* annotations in spring. You can use something like resteasy with spring. It is rather easy. If you need I can provide with an example. (Jersey and CXF has good JAX-RS implementations too.)

AFAIK Springsource has no idea to provide an implementation to JAX-RS. So if you want to use the features described in JAX-RS you will not get it directly from spring. But you can develop a rest web service using spring. That's a different story. A question was found on SO on that.

Update

Depending on PaulNUK's answer below, I need to clarify my answer. End of the day rest is a specification, and someone needs to implement it in first place.

Question clearly asks, whether we can replace the annotations, you cant do it, unless you add an external dependency like Jersey to your classpath. That case implementation is provided by Jersey.

Therefore you would never be able to use spring implemented JAX-RS annotation ever.

Swagger JAX-RS with Jersey 1.19 gives 'Conflicting URI templates' error

Update 2: Looks like version 1.5.8 of swagger-core fixes that issue. See this commit for details.


Update: Instead of adding Swagger resource as sub-resource it much easier to just override @Path mapping. See Solution 2 for details.


I was facing exactly the same problem. The cause of that is Swagger resource being mapped to root @Path("/") public class ApiListingResource.



Solution 1 - No concurring mappings

One simple and inflexible way around it, is not to define any resource mapping to root path @Path("/").



Solution 2 - Override @Path mapping

2.1 Override Swagger classes

ApiListingResource should get a new @Path mapping

package my.api.package.swagger

import javax.ws.rs.Path;

@Path("swagger")
public class ApiListingResource extends io.swagger.jaxrs.listing.ApiListingResource {}

SwaggerSerializers should get new package

package my.api.package.swagger;

import javax.ws.rs.ext.Provider;

@Provider
public class SwaggerSerializers extends io.swagger.jaxrs.listing.SwaggerSerializers {}

2.2 Configure overriden classes

Add my.api.package.swagger instead of io.swagger.jaxrs.listing in Swagger package config.



Solution 3 - Swagger resource as sub-resource

Other solution is to move Swagger to a different path, allowing your resources to be mapped anywhere you like. To achieve this you need to:

3.1 Remove ApiListingResource from provider classes.

if you subclass Application:

public MyApplication() {
//init BeanConfig
//add your resource classes

//classes.add(io.swagger.jaxrs.listing.ApiListingResource.class);
classes.add(io.swagger.jaxrs.listing.SwaggerSerializers.class);
}

if you configure via web.xml using com.sun.jersey.config.property.packages param:

<servlet>
<servlet-name>your-rest-api</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>
{your_application_packages},
<!--io.swagger.jaxrs.json,-->
<!--io.swagger.jaxrs.listing-->
</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.classnames</param-name>
<param-value>
io.swagger.jaxrs.listing.SwaggerSerializers,
io.swagger.jaxrs.json.JacksonJsonProvider
</param-value>
</init-param>
</servlet>

BTW, I have noticed that GF 3.1.2.2 with Jersey configured using <filter/> in web.xml does not work with Swagger due to Grizzly related bug.

3.2 Add ApiListingResources as a subresource to one of your resources

@Path("/") 
class RootResource {
@Context ServletContext context;

@Path("/swagger")
public ApiListingResource swagger() {
return new ApiListingSubResource(context);
}
}

As ApiListingResource is now not managed by Jersey, it does not get ServletContext injected. To overcome this problem you have to pass it as a constructor parameter, and for that subclass ApiListingResource and provide proper constructor:

// context has 'default' visibility
// so we need to stay in the same package
// to be able to access it
package io.swagger.jaxrs.listing;

import javax.servlet.ServletContext;

public class ApiListingSubResource extends ApiListingResource {
public ApiListingSubResource(ServletContext sc) { this.context = sc; }
}

Now your Swagger descriptors will be under http://hostname/app-path/swagger/swagger.json and you will still be able to use the root resource.

It's a little bit longer way , but works! Hope that helps.

init method in jersey jax-rs web service

There are multiple ways to achieve it, depending on what you have available in your application:

Using ServletContextListener from the Servlet API

Once JAX-RS is built on the top of the Servlet API, the following piece of code will do the trick:

@WebListener
public class StartupListener implements ServletContextListener {

@Override
public void contextInitialized(ServletContextEvent event) {
// Perform action during application's startup
}

@Override
public void contextDestroyed(ServletContextEvent event) {
// Perform action during application's shutdown
}
}

Using @ApplicationScoped and @Observes from CDI

When using JAX-RS with CDI, you can have the following:

@ApplicationScoped
public class StartupListener {

public void init(@Observes
@Initialized(ApplicationScoped.class) ServletContext context) {
// Perform action during application's startup
}

public void destroy(@Observes
@Destroyed(ApplicationScoped.class) ServletContext context) {
// Perform action during application's shutdown
}
}

In this approach, you must use @ApplicationScoped from the javax.enterprise.context package and not @ApplicationScoped from the javax.faces.bean package.

Using @Startup and @Singleton from EJB

When using JAX-RS with EJB, you can try:

@Startup
@Singleton
public class StartupListener {

@PostConstruct
public void init() {
// Perform action during application's startup
}

@PreDestroy
public void destroy() {
// Perform action during application's shutdown
}
}

If you are interested in reading a properties file, check this question. If you are using CDI and you are open to add Apache DeltaSpike dependencies to your project, considering having a look at this answer.



Related Topics



Leave a reply



Submit