如何在jersey2 / hk2应用程序中获取对Jackson Object Mapper的引用

时间:2015-05-15 11:55:13

标签: java json dependency-injection jersey-2.0 hk2

我有一个jersey2应用程序,通过Jackson配置为JSON支持,添加

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>${jersey.version}</version>
</dependency>
POM文件中的

public MyApplication() {
    ...
    register(JacksonFeature.class)
    ...
}

在我的申请中。一切正常,我的资源将反序列化的POJO作为参数

@POST @Consumes(MediaType.APPLICATION_JSON)
public void blah(MyPojo p) {
    ...
}

现在,其中一个资源需要引用杰克逊的ObjectMapper来自行进行反序列化。我尝试过像

这样的事情
@Inject
public MyResource(@Context ObjectMapper mapper) {
    ...
}

@GET
public String foo(@Context ObjectMapper mapper) {
    ...
}

但在这两种情况下,对mapper的引用都为空。如何在我的资源中注入对ObjectMapper的引用?

2 个答案:

答案 0 :(得分:6)

首先,Jackson提供商没有使用默认ObjectMapper。它实际上根本不使用ObjectMapper。它利用其他Jackson API来处理(反)序列化。

如果你想使用/注入一个ObjectMapper个实例,那么你应该为它创建一个Factory

public class ObjectMapperFactory implements Factory<ObjectMapper> {

    final ObjectMapper mapper = new ObjectMapper();

    @Override
    public ObjectMapper provide() {
        return mapper;
    }

    @Override
    public void dispose(ObjectMapper t) {}   
}

然后绑定它

register(new AbstractBinder(){
    @Override
    public void configure() {
        bindFactory(ObjectMapperFactory.class)
            .to(ObjectMapper.class).in(Singleton.class);
    }
});

应该注意的一点是,ObjectMapper的任何配置都是非线程安全。所以说你试图从资源方法配置它,那些操作不是线程安全的。

杰克逊提供商需要注意的另一件事是,如果我们提供ContextResolver,例如mentioned by @Laurentiu L,那么杰克逊提供商将转而使用我们的ObjectMapper。在这种情况下,如果您想使用相同的ObjectMapper,则可以在Factory中进行查找。例如

public class ObjectMapperFactory implements Factory<ObjectMapper> {

    private final Providers providers;
    final ObjectMapper mapper = new ObjectMapper();

    public ObjectMapperFactory(@Context Providers providers) {
        this.providers = providers;
    }

    @Override
    public ObjectMapper provide() {
        ContextResolver<ObjectMapper> resolver = providers.getContextResolver(
                ObjectMapper.class, MediaType.APPLICATION_JSON);
        if (resolver == null) { return mapper; }

        return resolver.getContext(null);
    }

    @Override
    public void dispose(ObjectMapper t) {}   
}

要使上述工作(使用单个ObjectMapper),您需要确保实施ContextResolver<ObjectMapper>,并确保使用相应的{{1}注释ContextResolver }和@Produces媒体类型。

答案 1 :(得分:3)

除了JacksonFeature之外,您还需要为ObjectMapper注册ContextResolver。

来自Documentation 9.1.4.2的简单示例。配置并注册

@Provider
public class MyObjectMapperProvider implements ContextResolver<ObjectMapper> {

    final ObjectMapper defaultObjectMapper;

    public MyObjectMapperProvider() {
        defaultObjectMapper = createDefaultMapper();
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return defaultObjectMapper;
    }

    private static ObjectMapper createDefaultMapper() {
        final ObjectMapper result = new ObjectMapper();
        result.configure(Feature.INDENT_OUTPUT, true);

        return result;
    }

    // ...
}

完整的代码示例 available on Github

您还需要注册

        .register(MyObjectMapperProvider.class)  
相关问题