我似乎无法正确注册我的 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(),因此永远不会注册映射器。我被困在一个典型的 guice--annotations-mystery 中,几乎无法追踪到我实际应该做的事情。 Spring 用户只是报告注册了组件,而容器只是将其拾取。
This回答讨论覆盖我自己的 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 组合做起来有多么困难。
最佳答案
I'm stuck in a typical guice--annotations-mystery, where it's practically untraceable to what I'm actually supposed to be doing. Spring users just report registering the component, and the container just picks it up.
你真的应该读一读excellent Guice documentation . Guice 非常易于使用,它的基本概念非常少。您的问题在于您混合了 Jersey JAX-RS 依赖注入(inject)和 Guice 依赖注入(inject)。如果您正在使用 GuiceContainer
,那么您声明您将对所有 DI 使用 Guice ,因此您必须添加与 Guice 而不是 JAX-RS 的绑定(bind)。
例如,您不需要 ContextResolver
,您应该使用普通的 Guice 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):
bind(ObjectMapper.class).toProvider(ObjectMapperProvider.class).in(Singleton.class);
这将绑定(bind) ObjectMapper
,但仅将 Jersey 与 Jackson 一起使用是不够的。您将需要某种类型的 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)它:
bind(JacksonJsonProvider.class).toProvider(JacksonJsonProviderProvider.class).in(Singleton.class);
这就是您需要做的全部 - 不需要子类化。
不过,代码大小还有优化空间。如果我是你,我会使用 @Provides
-methods:
@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
,它为你提供了很多有用的绑定(bind)。
关于java - 如何将 Jackson ObjectMapper 与 Guice/Jersey Hook ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16757724/