如何使用Guice / Jersey将Jackson ObjectMapper挂钩

时间:2013-05-26 09:01:58

标签: java jersey jackson guice

我似乎无法正确注册我的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;
}

Mapper定义

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的jersey-guice强制执行中成为DefaultResourceConfig():

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

我是否认为GuiceContainer是子类?或者是否有其他一些我缺少的魔法注释?

这似乎是一件相当普遍的事情 - 我很惊讶它与这种guice组合有多么困难。

1 个答案:

答案 0 :(得分:24)

  

我陷入了典型的诡计 - 注释 - 神秘,它在哪里   实际上无法实现我实际应该做的事情。   Spring用户只报告注册组件和容器   只是把它拿起来。

你真的应该阅读excellent Guice documentation。 Guice非常易于使用,它具有非常少量的基本概念。你的问题在于你混合了Jersey JAX-RS依赖注入和Guice依赖注入。如果您正在使用GuiceContainer,那么您声明将使用Guice 用于DI的所有,因此您必须使用Guice而不是JAX-RS添加绑定。

例如,您不需要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(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,它为你提供了很多有用的绑定。