Jersey: 1.12 Spring: 3.11 JDK: 1.6.0_35 Tomcat: 6..0.33
I am trying to register ExceptionMapper instances for a Jersey servlet that are instantiated by a Spring IoC container in the context of a SpringServlet, and am running into ye olde "The scope of the component class X must be a singleton" exception during the Jersey servlet initialization. I'm not in a position to post the actual code at this time, so I'm going to give the essentials of the implementation to see if something obvious jumps out at someone, or if I can be pointed at some documentation that I have missed.
The ExceptionMapper instance is essentially as follows:
// ... package definitions omitted ...
@Provider
@Singleton
public class MyExceptionMapper
implements ExceptionMapper<MyException>
{
// ... injected attributes omitted ...
@Override
public Response toResponse(MyException exception)
{
// ... specific handling logic omitted ...
return Response.status(Status.BAD_REQUEST).entity(exception.getMessage()).build();
}
}
The bean definition in applicationContext.xml is as follows, which defaults to singleton scope (and adding an explicit scope specifier doesn't seem to change the behavior):
<bean id="myExceptionMapper" class="my.package.MyExceptionMapper" />
The Spring context loader listener and SpringServlet configuration in web.xml are essentially boilerplate, and the servlet will load, initialize and operate properly with other inject attributes when the bean definition for MyExceptionMapper is commented out of the applicationContext.xml. But when the bean definition is present in applicationContext.xml, I get log messages to the effect of:
SpringProviderFactory - Registering Spring bean, myExpectionMapper, of type my.package.MyExceptionMapper as a provider class
SpringProviderFactory - Registering Spring bean, myServiceController, of type my.package.MyServiceController as a root resource class
... other root resource classes loading ...
SpringServlet - Exception occurred when initialization
java.lang.RuntimeException: The scope of the component class my.package.MyExceptionMapper must be a singleton
at som.sun.jersey.core.spi.component.ioc.IoCProviderFactory.wrap(...)
I have tried placing MyExceptionMapper in the scanned packages hierarchy to be picked up by the SpringServlet during initialization, and in a separate package hierarchy, and the results do not change.
Any assistance or guidance on this would be greatly appreciated.
My ExceptionMapper
s are under the structure where I'm doing component scan, and mine are simply annotated with @Component
for Spring registry and @Provider
for Jersey.
My component scan just looks like:
<context:component-scan base-package="com.company.web"/>
and the ExceptionMapper
looks pretty much like yours:
package com.mycompany.web.provider;
import com.mycompany.exception.SpecialException;
import com.mycompany.exception.Error;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
@Provider
@Component
public class SpecialExceptionMapper implements ExceptionMapper<SpecialException> {
@Autowired
private MessageSource messageSource;
@Override
public Response toResponse(SpecialException exception) {
Error error = new Error();
error.errorMessage = messageSource.getMessage(exception.getResourceBundleKey(), exception.getArgs());
return Response.status(Response.Status.BAD_REQUEST).
entity(error).
type(MediaType.APPLICATION_JSON).
build();
}
}
Adding the scope explicitly in the spring config did the trick for me:
<bean id="exceptionMapper" class="my.pkg.MyExceptionMapper" scope="singleton" />
Stepped on same problem with Spring 3.2.3 and Jersey 2.3.1 integration.
What worked for me was combination of two:
Annotating jersey @Provider
class with @Service
or making it explicitly singleton in app-context xml
@Service //implies a singleton-scope
@Provider
public class UnhandledExceptionMapper implements ExceptionMapper<Throwable> {
@Override
public Response toResponse(Throwable exception) { //...
Adding package that contains provider class to jersey packages, I prefer to do this in MyApplication class:
public class MyApplication extends ResourceConfig {
public MyApplication() {
packages("com.mycompany.api.controller", "com.mycompany.api.jersey");
//....
}
}
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