2012-11-30 7 views
5

Jersey: 1.12 Primavera: 3.11 JDK: 1.6.0_35 Tomcat: 6..0.33Jersey ;: Registrazione istanze ExceptionMapper iniettato attraverso SpringServlet

Sto cercando di registrare le istanze ExceptionMapper per un servlet Jersey che sono un'istanza da un contenitore IoC Primavera nel contesto di una SpringServlet, e sono in esecuzione in ye Olde "il campo di applicazione della classe del componente X deve essere un singleton" eccezione durante l'inizializzazione del servlet Jersey. Io non sono in grado di pubblicare il codice vero e proprio in questo momento, così ho intenzione di dare gli elementi essenziali di attuazione, per vedere se qualcosa di ovvio salta fuori qualcuno, o se posso essere puntato verso una certa documentazione che ho perse.

esempio

L'ExceptionMapper è essenzialmente il seguente:

// ... 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(); 
    } 
} 

La definizione fagiolo in applicationContext.xml è come segue che imposta Singleton portata (e aggiungendo uno specificatore ambito esplicito non sembra modificare il comportamento):

<bean id="myExceptionMapper" class="my.package.MyExceptionMapper" /> 

The Spring contesto loader ascoltatore e configurazione SpringServlet in web.xml sono essenzialmente boilerplate, e il servlet caricherà, inizializzare e funzionare correttamente con altri attributi iniezione quando il bean defin ition per MyExceptionMapper è commentato da applicationContext.xml. Ma quando la definizione di fagioli è presente in applicationContext.xml, ottengo i messaggi di log per effetto di:

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(...) 

Ho provato mettendo MyExceptionMapper nella gerarchia pacchetti digitalizzata per essere prelevati dal SpringServlet durante l'inizializzazione, e in una gerarchia di pacchetti separata e i risultati non cambiano.

Qualsiasi forma di assistenza o di orientamento su questo sarebbe molto apprezzato.

+0

Vi siete doppio controllato che si sta utilizzando javax. Inject.Singleton e le annotazioni javax.inject sono abilitate in primavera? –

risposta

1

calpestato lo stesso problema con la Primavera 3.2.3 e 2.3.1 Jersey integrazione.

Che cosa ha funzionato per me era la combinazione di due:

  1. Annotazione jersey @Provider classe con @Service o rendere esplicito Singleton in app-contesto xml

    @Service //implies a singleton-scope 
    @Provider 
    public class UnhandledExceptionMapper implements ExceptionMapper<Throwable> { 
    
        @Override 
        public Response toResponse(Throwable exception) { //... 
    
  2. Aggiungendo pacchetto che contiene classe fornitore per i pacchetti jersey, preferisco farlo nella classe MyApplication:

    public class MyApplication extends ResourceConfig { 
    public MyApplication() { 
        packages("com.mycompany.api.controller", "com.mycompany.api.jersey"); 
          //.... 
        } 
    } 
    
1

ho avuto lo stesso problema, ma con una classe MessageReaderWriterProvider:

package my.provider.package; 
... 
@Provider 
@Consumes({MediaType.APPLICATION_JSON, "text/json"}) 
@Produces({MediaType.APPLICATION_JSON, "text/json"}) 
public class ReRwProvider extends AbstractMessageReaderWriterProvider<Object> { 
... 
} 

La soluzione era quella di aggiungere il pacchetto di questa classe in un tag init-param per SpringServlet di Jersey in web.xml:

<init-param> 
    <param-name>com.sun.jersey.config.property.packages</param-name> 
    <param-value>my.provider.package</param-value> 
</init-param> 

Nota che non si deve definire questo fagiolo nel vostro contesto primavera.

4

I miei ExceptionMapper s sono sotto la struttura dove sto facendo scansione dei componenti, e il mio sono semplicemente annotati con @Component per il registro Spring e @Provider per Jersey.

mio scansione componente appena si presenta come:

<context:component-scan base-package="com.company.web"/> 

e la ExceptionMapper sembra più o meno come la tua:

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(); 
    } 
} 
4

Aggiunta la portata in modo esplicito nella configurazione primavera ha fatto il trucco per me:

<bean id="exceptionMapper" class="my.pkg.MyExceptionMapper" scope="singleton" /> 
+1

Ok, ha funzionato, ma cosa significa? Per impostazione predefinita, Spring non considera tutti i bean definiti nell'XML come singleton? Perché dobbiamo specificarlo esplicitamente? – saratbeesa

0

Sembra a me che l'ExceptionMapper deve essere configurato come un "cantare leton "con Spring.Se vuoi usare la configurazione di annotazione devi prestare attenzione perché la jersey ha anche un'annotazione "@Singleton" (con un diverso significato di javax.inject.Singleton interpretato dalla molla) Per evitare qualsiasi confusione preferisco usare la molla @ l'annotazione di servizio, che implica un ambito Singleton ... quindi:

import org.springframework.stereotype.Service; 

import javax.ws.rs.core.Response; 
import javax.ws.rs.ext.ExceptionMapper; 
import javax.ws.rs.ext.Provider; 

@Service //implies a singleton-scope 
@Provider 
public class UnhandledExceptionMapper implements ExceptionMapper<Throwable> { 

    @Override 
    public Response toResponse(Throwable exception) { 
     return Response.status(Response.Status.INTERNAL_SERVER_ERROR) 
       .entity(new ErrorBean(false, exception.getMessage(), null)) 
       .build(); 
    } 
} 
0

Ho anche trovato qualche volta coustom ExceptionMapper non funziona, e non sempre funziona o non funziona.

quindi eseguo il debug del codice sorgente della jersey.

classe: org.glassfish.jersey.server.ServerRuntime, methed: mapException

... 
final long timestamp = tracingLogger.timestamp(ServerTraceEvent.EXCEPTION_MAPPING); 
**ExceptionMapper mapper = runtime.exceptionMappers.findMapping(throwable);** 
if (mapper != null) { 
     request.getRequestEventBuilder().setExceptionMapper(mapper); 

... se il mapper è nullo, il coustom ExceptionMapper non verrà funziona.

classe: org.glassfish.jersey.internal.ExceptionMapperFactory methed: ExceptionMapperFactory

il Mapper eccezione: (non due eccezioni mappatura uno stesso Eccezione: java.lang.Exception)

org.glassfish.jersey .server.mvc.internal.ErrorTemplateExceptionMapper @ 6473fc2, classe java.lang.Exception

...

com.baidu.ssp.web.ws.exception.BaseExceptionMapper @ 7a84639c, classe java.lang.Exception

è perché in MvcFeature:

@Override public boolean configure (contesto FeatureContext finale) { finale config Configurazione = context.getConfiguration();

if (!config.isRegistered(ErrorTemplateExceptionMapper.class)) { 
    context.register(ErrorTemplateExceptionMapper.class); 
    context.register(new MvcBinder()); 

    return true; 
} 

return false; 

} l'ErrorTemplateExceptionMapper è anche aggiungere al ExceptionMapper.

così a cambiare il tipo genericità del mio MapperException personalizzato: ExceptionMapper per ExceptionMapper

può essere la mia risoluzione non è adatto per voi, il problema principale è l'ExceptionMapper

Problemi correlati