2013-05-26 3 views
11

Non riesco a ottenere il mio modulo ObjectMapper Jackson registrato correttamente.Come agganciare Jackson ObjectMapper con Guice/Jersey

Sto usando uno stack Guice + Jersey + Jackson (FasterXML).

Ho seguito come personalizzare l'ObjectMapper in base alle varie domande qui. In particolare, ho dichiarato ContextResolver, contrassegnato come @javax.ws.rs.ext.Provider e @javax.inject.Singleton.

Ho un GuiceServletContextListener lungo le linee di:

@Override 
protected Injector getInjector() { 

    Injector injector = Guice.createInjector(new DBModule(dataSource), 
      new ServletModule() 
      { 
       @Override 
       protected void configureServlets() { 


        // Mapper 
        bind(JacksonOMP.class).asEagerSingleton(); 

        // ... 

        Map<String, String> initParams = new HashMap<String, String>(); 
        initParams.put("com.sun.jersey.config.feature.Trace", 
          "true"); 
        initParams.put("com.sun.jersey.api.json.POJOMappingFeature", "true"); 

        serve("/services/*").with(
          GuiceContainer.class, 
          initParams); 
       } 
      }); 

    return injector; 
} 

Mapper definito

import javax.inject.Singleton; 
import javax.ws.rs.Produces; 
import javax.ws.rs.ext.ContextResolver; 
import javax.ws.rs.ext.Provider; 

@Provider 
@Singleton 
@Produces 
public class JacksonOMP implements ContextResolver<ObjectMapper> { 

    @Override 
    public ObjectMapper getContext(Class<?> aClass) { 
    final ObjectMapper mapper = new ObjectMapper(); 
    mapper.registerModule(new Hibernate4Module()); 
    return mapper; 
    } 
} 

Tuttavia - con la sola questa configurazione, getContext() non viene mai chiamato, in modo che il mapping non è mai registrati. Sono bloccato in un tipico guizzo - annotazioni-mistero, in cui è praticamente impossibile da definire per quello che dovrei fare in realtà. Gli utenti Spring hanno appena segnalato la registrazione del componente e il contenitore lo riprende.

This risposta parla dell'override della mia implementazione javax.ws.rs.core.Application. Tuttavia, questo sembra hard-wired nel impementation jersey-Guice di GuiceContainer essere DefaultResourceConfig():

@Override 
protected ResourceConfig getDefaultResourceConfig(Map<String, Object> props, 
     WebConfig webConfig) throws ServletException { 
    return new DefaultResourceConfig(); 
} 

dovrei sottoclasse GuiceContainer qui? O c'è qualche altra annotazione magica che mi manca?

Questa sembra una cosa abbastanza comune da voler fare - Sono sorpreso da quanto duramente stia provando a fare con questa combinazione di scommesse.

risposta

22

Sono bloccato in un tipico Guice - annotazioni-mistero, dove è praticamente introvabile a quello che sto in realtà dovrebbe fare. Gli utenti Spring segnalano appena la registrazione del componente e il contenitore lo preleva.

Dovresti davvero leggere excellent Guice documentation. Guice è molto facile da usare, ha un numero molto ridotto di concetti di base. Il tuo problema è che hai mescolato l'iniezione di dipendenza Jersey JAX-RS e l'iniezione di dipendenza da Guice. Se si utilizza GuiceContainer, si dichiara di utilizzare Guice per tutti gli del proprio DI, quindi è necessario aggiungere collegamenti con Guice e non con JAX-RS.

Per esempio, non è necessario ContextResolver, si dovrebbe usare pianura Guice Provider invece:

import com.google.inject.Provider; 

public class ObjectMapperProvider implements Provider<ObjectMapper> { 
    @Override 
    public ObjectMapper get() { 
     final ObjectMapper mapper = new ObjectMapper(); 
     mapper.registerModule(new Hibernate4Module()); 
     return mapper; 
    } 
} 

Poi si dovrebbe aggiungere corrispondente vincolante al modulo:

bind(ObjectMapper.class).toProvider(ObjectMapperProvider.class).in(Singleton.class); 

Questo legherà ObjectMapper, ma non è abbastanza per usare Jersey con Jackson. Avrai bisogno di una specie di MessageBodyReader/MessageBodyWriter, ad es. JacksonJsonProvider.Avrete bisogno di un altro fornitore per esso:

public class JacksonJsonProviderProvider implements Provider<JacksonJsonProvider> { 
    private final ObjectMapper mapper; 

    @Inject 
    JacksonJsonProviderProvider(ObjectMapper mapper) { 
     this.mapper = mapper; 
    } 

    @Override 
    public JacksonJsonProvider get() { 
     return new JacksonJsonProvider(mapper); 
    } 
} 

quindi associare esso:

bind(JacksonJsonProvider.class).toProvider(JacksonJsonProviderProvider.class).in(Singleton.class); 

Questo è tutto quello che dovete fare - non è necessaria alcuna sottoclassi.

C'è comunque spazio per l'ottimizzazione della dimensione del codice. Se fossi in te vorrei utilizzare @Provides -metodi:

@Provides @Singleton 
ObjectMapper objectMapper() { 
    final ObjectMapper mapper = new ObjectMapper(); 
    mapper.registerModule(new Hibernate4Module()); 
    return mapper; 
} 

@Provides @Singleton 
JacksonJsonProvider jacksonJsonProvider(ObjectMapper mapper) { 
    return new JacksonJsonProvider(mapper); 
} 

Questi metodi devono essere aggiunti a uno dei moduli, per esempio all'anonimo ServletModule. Quindi non avrai bisogno di classi di provider separate.
BTW, dovresti usare JerseyServletModule invece del semplice ServletModule, fornisce molti collegamenti utili per te.

+0

Questo è molto utile. Il mio problema particolare era in realtà che avevo i jackson * 2 * (sia la versione codehaus che la versione fasterxml), quindi gli objectmapper sono stati completamente ignorati perché erano del tipo sbagliato. – user340535

+0

Ho avuto lo stesso conflitto di dipendenze (codehaus + fasterxml): 'JsonIgnore' non funzionava affatto. Nel mio caso, jackson codehaus (jackson-mapper-asl o core-asl) è stato collegato a una dipendenza del pacchetto documentdb azzurro ed è stato rimosso completamente (mediante esclusione pom) per mantenere solo la versione più recente (fasterxml). Grazie a @ user340535 per il tuo commento che mi aiuta a correggere il gancio di JacksonJsonProvider! – boly38

+0

Per qualche motivo la versione con annotazioni non funziona con me in Guice 4 usando JerseyGuiceServletContextListener. Cosa può causarlo? Con il binding normale e le classi extra funziona senza problemi. – Atais