我似乎无法正确注册我的Jackson ObjectMapper模块。
我正在使用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用户只是报告说注册了组件,而容器只是将其拾取。
这个答案讨论了重写我自己的javax.ws.rs.core.Application实现。但是,在GuiceContainer的jersey- guice实施中,这看起来像是硬连接为DefaultResourceConfig():
@Override protected ResourceConfig getDefaultResourceConfig(Map<String, Object> props, WebConfig webConfig) throws ServletException { return new DefaultResourceConfig(); }
我应该在这里子类GuiceContainer吗?还是我缺少其他魔术注释?
这似乎是一件很普通的事情-我对使用这种guice组合被证明多么困难感到惊讶。
我陷入了典型的困境-注释-奥秘,在这里我实际上应该做的事几乎无法追查。Spring用户只是报告说注册了组件,而容器只是将其拾取。
您确实应该阅读出色的Guice文档。Guice非常易于使用,它具有很少的基本概念。您的问题在于您混合了Jersey JAX- RS依赖项注入和Guice依赖项注入。如果正在使用,GuiceContainer则声明将对 所有 DI 使用Guice ,因此必须使用Guice而不是JAX-RS添加绑定。
GuiceContainer
例如,您不需要ContextResolver,Provider而应该使用普通的Guice :
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,但仅将Jersey与Jackson配合使用是不够的。您将需要某种MessageBodyReader/ MessageBodyWriter,例如JacksonJsonProvider。您将需要其他提供者:
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
@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而不是plain ServletModule,它为您提供了许多有用的绑定。
ServletModule
JerseyServletModule