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
How to Pass Console Arguments to Application in Eclipse
What's the Difference Between a Resource, Uri, Url, Path and File in Java
Sharing a Persistence Unit Across Components in a .Ear File
Resize a Picture to Fit a Jlabel
How to Get Java Logging Output to Appear on a Single Line
Java:Does Wait() Release Lock from Synchronized Block
Why Are Java 8 Lambdas Invoked Using Invokedynamic
Data Structures That Can Map a Range of Keys to a Value
Java 8 Stream with Batch Processing
Java Enum Methods - Return Opposite Direction Enum
How to Make Hashmap Work with Arrays as Key
Nosuchmethoderror on Startup in Java Jersey App
How to Get Java to Ignore the "Trust Store" and Just Accept Whatever Ssl Certificate It Gets