I have a Servlet 3.0 web app that uses both Spring and Jersey. I currently have it set up using the SpringServlet configured as a filter in web.xml, and the resource classes annotated with both @Path
and @Component
. Here's the web.xml snippet:
<filter>
<filter-name>jersey-serlvet</filter-name>
<filter-class>
com.sun.jersey.spi.spring.container.servlet.SpringServlet
</filter-class>
<init-param>
<param-name>
com.sun.jersey.config.property.packages
</param-name>
<param-value>com.foo;com.bar</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.feature.FilterForwardOn404</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>jersey-serlvet</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
This setup works, but I really want to get this set up with annotations only - no web.xml config. My first attempt at this was to remove the above SpringServlet configuration and create a class that extends Application
. Here's a snippet of that:
@ApplicationPath("/*")
public class MyApplication extends PackagesResourceConfig {
public MyApplication() {
super("com.foo;com.bar");
HashMap<String, Object> settings = new HashMap<String, Object>(1);
settings.put(ServletContainer.FEATURE_FILTER_FORWARD_ON_404, true);
this.setPropertiesAndFeatures(settings);
}
}
This works in that the JAX-RS resources are registered and I can hit them at their URLs, but they throw NullPointerExceptions when they try and use their autowired properties... this makes sense because I'm guessing the resources are now being loaded by Jersey and are not Spring managed beans, therefore no autowiring.
Despite a fair bit of searching around I cannot find any way of loading the Jersey resources as Spring beans with annotations only. Is there such a way? I don't really want to have to write a bunch of code for the resources to manually fetch the Spring context and invoke the DI if I can help it.
If annotations-only isn't going to work, then I can live with the filter config in web.xml if I can specify an Application
class to load instead of a list of packages to scan. If I can get rid of the package list in there and just specify an Application
class instance then I'll be content.
Obviously it would be great if someone had a definitive answer for me but I'd also be grateful for any pointers or hints of where else I could look or things to try.
Thanks, Matt
The spring-boot-starter-jersey is a starter for building RESTful web applications using JAX-RS and Jersey. It is an alternative to spring-boot-starter-web . The spring-boot-starter-test is a starter for testing Spring Boot applications with libraries including JUnit, Hamcrest and Mockito.
Spring Security can be used to secure a Jersey-based web application in much the same way as it can be used to secure a Spring MVC-based web application. However, if you want to use Spring Security's method-level security with Jersey, you must configure Jersey to use setStatus(int) rather sendError(int) .
Jersey is an open source framework for developing RESTful Web Services. It serves as a reference implementation of JAX-RS. In this article, we'll explore the creation of a RESTful Web Service using Jersey 2. Also, we'll use Spring's Dependency Injection (DI) with Java configuration.
Below is part of my app, which uses Servlet 3.0, Spring, Jersey 1.8 and it has no web.xml:
public class WebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
final AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setConfigLocation("com.myapp.config");
final FilterRegistration.Dynamic characterEncodingFilter = servletContext.addFilter("characterEncodingFilter", new CharacterEncodingFilter());
characterEncodingFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
characterEncodingFilter.setInitParameter("encoding", "UTF-8");
characterEncodingFilter.setInitParameter("forceEncoding", "true");
final FilterRegistration.Dynamic springSecurityFilterChain = servletContext.addFilter("springSecurityFilterChain", new DelegatingFilterProxy());
springSecurityFilterChain.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
servletContext.addListener(new ContextLoaderListener(context));
servletContext.setInitParameter("spring.profiles.default", "production");
final SpringServlet servlet = new SpringServlet();
final ServletRegistration.Dynamic appServlet = servletContext.addServlet("appServlet", servlet);
appServlet.setInitParameter("com.sun.jersey.config.property.packages", "com.myapp.api");
appServlet.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters", "com.myapp.api.SizeLimitFilter");
appServlet.setLoadOnStartup(1);
final Set<String> mappingConflicts = appServlet.addMapping("/api/*");
if (!mappingConflicts.isEmpty()) {
throw new IllegalStateException("'appServlet' cannot be mapped to '/' under Tomcat versions <= 7.0.14");
}
}
}
I haven't been able to get my ideal result but I have been able to make some progress, so I'll post here in case it helps anyone else. I was able to use the Spring Servlet to specify my application class, thereby removing the package list from the web.xml.
The web.xml changes required are in the init params (the filter mapping is not shown but is still required):
<filter>
<filter-name>jersey-serlvet</filter-name>
<filter-class>
com.sun.jersey.spi.spring.container.servlet.SpringServlet
</filter-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name> <!-- Specify application class here -->
<param-value>com.foo.MyApplication</param-value>
</init-param>
</filter>
And then in the application class I had to change the way I called the super constructor slightly:
public MyApplication() {
super("com.foo", "com.bar"); // Pass in packages as separate params
HashMap<String, Object> settings = new HashMap<String, Object>(1);
settings.put(ServletContainer.FEATURE_FILTER_FORWARD_ON_404, true);
this.setPropertiesAndFeatures(settings);
}
Still not exactly what I was after but at least this pulls a little more config into Java code and out of the web.xml, which is important for me as I'm trying to hide this detail.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With