2015-05-15 2 views
7

ich eine jersey2 Anwendung für JSON-Unterstützung über Jackson konfiguriert habe,Wie bekomme ich einen Verweis auf den Jackson Object Mapper in einer jersey2/hk2 Anwendung

<dependency> 
    <groupId>org.glassfish.jersey.media</groupId> 
    <artifactId>jersey-media-json-jackson</artifactId> 
    <version>${jersey.version}</version> 
</dependency> 

in der POM-Datei und

public MyApplication() { 
    ... 
    register(JacksonFeature.class) 
    ... 
} 
Hinzufügen

in meiner Anwendung. Alles funktioniert, meine Ressourcen entserialisierten POJOs als Argument

@POST @Consumes(MediaType.APPLICATION_JSON) 
public void blah(MyPojo p) { 
    ... 
} 

Jetzt ist einer der thoese Ressourcen benötigt einen Verweis auf Jackson bekommen ObjectMapper einig Deserialisierung auf seinem eigenen zu tun. Ich habe versucht, etwas zu tun, wie

@Inject 
public MyResource(@Context ObjectMapper mapper) { 
    ... 
} 

oder

@GET 
public String foo(@Context ObjectMapper mapper) { 
    ... 
} 

aber in beiden Fällen ist die Bezugnahme auf mapper null ist. Wie kann ich einen Verweis auf die ObjectMapper in meinen Ressourcen einfügen?

Antwort

5

Zuerst ObjectMapper kein Standard durch die verwendete Jackson Anbieter. Es verwendet überhaupt kein ObjectMapper. Es nutzt andere Jackson-APIs, um die (De-) Serialisierung zu handhaben.

Wenn Sie eine einzelne ObjectMapper Instanz verwenden/injizieren wollen, dann sollten Sie nur ein Factory dafür

public class ObjectMapperFactory implements Factory<ObjectMapper> { 

    final ObjectMapper mapper = new ObjectMapper(); 

    @Override 
    public ObjectMapper provide() { 
     return mapper; 
    } 

    @Override 
    public void dispose(ObjectMapper t) {} 
} 

Dann erstellen Sie binden es, dass jede

register(new AbstractBinder(){ 
    @Override 
    public void configure() { 
     bindFactory(ObjectMapperFactory.class) 
      .to(ObjectMapper.class).in(Singleton.class); 
    } 
}); 

Eine Sache sollte beachtet werden, ist Konfiguration der ObjectMapper ist nicht Thread sicher. Also sagen Sie, dass Sie versucht haben, es von Ihrer Ressourcenmethode aus zu konfigurieren, diese Operationen sind nicht Thread-sicher.

Eine andere Sache, mit dem Jackson-Provider zu beachten, ist, dass, wenn wir eine ContextResolver liefern, wie mentioned by @Laurentiu L, dann ist der Jackson-Provider unsere ObjectMapper zu verwenden wechseln. In diesem Fall, wenn Sie das gleiche ObjectMapper verwenden möchten, können Sie es in der Factory nachschlagen.Zum Beispiel

public class ObjectMapperFactory implements Factory<ObjectMapper> { 

    private final Providers providers; 
    final ObjectMapper mapper = new ObjectMapper(); 

    public ObjectMapperFactory(@Context Providers providers) { 
     this.providers = providers; 
    } 

    @Override 
    public ObjectMapper provide() { 
     ContextResolver<ObjectMapper> resolver = providers.getContextResolver(
       ObjectMapper.class, MediaType.APPLICATION_JSON); 
     if (resolver == null) { return mapper; } 

     return resolver.getContext(null); 
    } 

    @Override 
    public void dispose(ObjectMapper t) {} 
} 

Für die oben zu arbeiten (ein einzelnes ObjectMapper verwenden), müssen Sie sicherstellen, dass die ContextResolver<ObjectMapper>, umzusetzen und sicherzustellen, dass die ContextResolver mit den entsprechenden @Produces und @Consumes Medientypen in Annotations.

3

Neben dem JacksonFeature müssen Sie einen ContextResolver für ObjectMapper registrieren.

Einfaches Beispiel aus der Documentation bei 9.1.4.2. Konfigurieren und registrieren

@Provider 
public class MyObjectMapperProvider implements ContextResolver<ObjectMapper> { 

    final ObjectMapper defaultObjectMapper; 

    public MyObjectMapperProvider() { 
     defaultObjectMapper = createDefaultMapper(); 
    } 

    @Override 
    public ObjectMapper getContext(Class<?> type) { 
     return defaultObjectMapper; 
    } 

    private static ObjectMapper createDefaultMapper() { 
     final ObjectMapper result = new ObjectMapper(); 
     result.configure(Feature.INDENT_OUTPUT, true); 

     return result; 
    } 

    // ... 
} 

komplette Codebeispiel available on Github

Sie auch brauchen, es zu registrieren

 .register(MyObjectMapperProvider.class) 
+0

Das funktioniert, aber da ich (noch?) Von einem benutzerdefinierten 'ObjectMapper' nicht benötigt habe, habe ich auf einen Weg gehofft, Jersey's geschaffenes zu verwenden, anstatt mein eigenes zu liefern. – agnul

+0

Wenn jemand "ein Problem hat: abstrakte Typen müssen entweder mit Dropwizard auf konkrete Typen gemappt werden, obwohl Sie ein Modul mit' addAbstractTypeMapping' registriert haben, hat diese Lösung das Problem wie ein Charm behoben (registrieren Sie einfach Ihr Modul in 'createDefaultMapper' und registriere diesen 'Provider' mit' environment.jersey(). register() 'im' run() 'deiner' Anwendung')! – qwertzguy

Verwandte Themen