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

How do I get a reference to the Jackson Object Mapper in a jersey2 / hk2 application

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

<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) {
    ...
}

现在,其中一个资源需要引用 Jackson 的 ObjectMapper 才能自行进行一些反序列化。我试过做类似

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

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

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

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

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

@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)  

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

如果你想use/inject一个单一的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 的任何配置 不是线程安全的 。所以说你试图从你的资源方法配置它,那些操作不是线程安全的。

Jackson 提供者需要注意的另一件事是,如果我们提供 ContextResolver,例如 ,那么 Jackson 提供者将切换到使用我们的 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>,并确保用相应的[注释ContextResolver =25=] 和 @Consumes 媒体类型。