2013-05-26 56 views
11

我似乎無法讓我的Jackson ObjectMapper模塊正確註冊。如何將Jackson ObjectMapper與Guice/Jersey掛鉤

我正在使用Guice + Jersey + Jackson(FasterXML)堆棧。

我跟着如何根據各種問題在這裏自定義ObjectMapper。特別是,我聲明瞭一個ContextResolver,標記爲@ javax.ws.rs.ext.Provider和@ javax.inject.Singleton。

我的線沿線的一個GuiceServletContextListener:

@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; 
} 

映射定義

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; 
    } 
} 

但是 - 單獨使用本配置,的getContext()不會被調用,所以映射器永遠不會註冊。我陷入了一個典型的詭計 - 註解 - 神祕之謎,在那裏它幾乎無法追蹤我實際上應該做的事情。 Spring用戶只是報告註冊組件,容器只是拿起它。

This回答關於覆蓋我自己的javax.ws.rs.core.Application實現的討論。然而,這看起來硬連線在GuiceContainer的球衣 - 吉斯impementation是DefaultResourceConfig():

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

我在這裏應該子類GuiceContainer?或者是否還有其他一些我錯過的魔法註釋?

這似乎是一件相當普遍的事情要做 - 我很驚訝它證明如何處理這個guice組合。

回答

22

我被困在一個典型的guice-annotations-mystery,它的 實際上難以追蹤到我實際上應該做的事情。 春季用戶只是報告註冊組件,容器 只是拿起它。

你真的應該讀excellent Guice documentation。 Guice非常易於使用,它的基本概念數量非常少。你的問題在於你混合了Jersey JAX-RS依賴注入和Guice依賴注入。如果您使用的是GuiceContainer,那麼您聲明您將使用Guice 來處理DI的所有,因此您必須添加與Guice綁定而不是JAX-RS的綁定。

舉例來說,你不需要ContextResolver,你應該使用普通吉斯Provider代替:

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; 
    } 
} 

那麼你應該添加相應的綁定到你的模塊:

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

這將綁定ObjectMapper,但與傑克遜一起使用澤西還不夠。您需要某種MessageBodyReader/MessageBodyWriter,例如JacksonJsonProvider。您需要其他供應商爲它:

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

然後將其綁定:

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

這是所有你需要做的 - 不需要子類。

雖然有代碼大小優化的空間。如果我是你,我會用@Provides - 方法:

@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); 
} 

這些方法應該添加到您的模塊,例如一個以匿名ServletModule。那麼你將不需要單獨的提供者類。
順便說一句,你應該使用JerseyServletModule而不是普通的ServletModule,它爲你提供了很多有用的綁定。

+0

這非常有幫助。我特別的問題是,我有* 2 * jacksons(codehaus版本和fasterxml版本),所以objectmappers完全被忽略,因爲它們是錯誤的類型。 – user340535

+0

我有相同的依賴關係衝突問題(codehaus + fasterxml):'JsonIgnore'根本不起作用。在我的情況下,jackson codehaus(jackson-mapper-asl或core-asl)與azure documentdb軟件包依賴關聯,並已完全刪除(通過pom排除)以僅保留最新版本(fasterxml)。感謝@ user340535的評論,幫助我修復JacksonJsonProvider鉤子! – boly38

+0

出於某種原因,使用JerseyGuiceServletContextListener的註釋版本在Guice 4中不適用於我。什麼會導致它?使用普通綁定和額外的類,它確實沒有問題。 – Atais