一尘不染

如何用Guice / Jersey钩住Jackson ObjectMapper

java

我似乎无法正确注册我的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组合被证明多么困难感到惊讶。


阅读 241

收藏
2020-12-03

共1个答案

一尘不染

我陷入了典型的困境-注释-奥秘,在这里我实际上应该做的事几乎无法追查。Spring用户只是报告说注册了组件,而容器只是将其拾取。

您确实应该阅读出色的Guice文档。Guice非常易于使用,它具有很少的基本概念。您的问题在于您混合了Jersey JAX-
RS依赖项注入和Guice依赖项注入。如果正在使用,GuiceContainer则声明将对 所有 DI 使用Guice
,因此必须使用Guice而不是JAX-RS添加绑定。

例如,您不需要ContextResolverProvider而应该使用普通的Guice :

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。您将需要其他提供者:

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而不是plain ServletModule,它为您提供了许多有用的绑定。

2020-12-03