如何在相同的Jersey JAX-RS应用程序中使用两个版本的Jackson(1.x和2.x)?

问题描述 投票:4回答:2

我在旧版泽西岛(1.19)以及旧杰克逊(1.19.13)的项目中工作。我想切换到新的杰克逊(2.x)反序列化,但仅适用于新的端点(以及逐渐的旧端点),因为一步到杰克逊2和/或泽西2的迁移将非常困难(哦,巨石! )。

我已经看过一些关于如何在泽西岛提供自定义配置的ObjectMapper和杰克逊供应商的话题,或者如何在1.x泽西岛中安装新杰克逊,但这不是我想要的,至少不是全部。

我想象的解决方案是(最好)用@ UseJackson2注释我的新JAX-RS端点,或者让一些基类从正确的包中检索ObjectMapper,对于这个特定的端点并在以后扩展它 - 在其他强制给定端点使用其他(反)序列化提供程序的字通常。

我已经看到了不同配置ObjectMapper的提供程序的例子(就像这里的qazxsw poi),但在我的例子中,ObjectMappers将来自完全不同的包/ maven工件。

java jackson jersey jax-rs jersey-1.0
2个回答
3
投票

你可以做的是创建一个处理2.x版Jackson的Using Jackson in Jersey with multiple configured ObjectMappersMessageBodyReader/WriterisReadable方法确定它可以处理哪些实体。您可以检查的是将Jersey的isWritable注入提供程序并检查ExtendedUriInfo注释的资源类。如果注释不存在,则提供者忽略该实体,并且运行时移动到下一个提供者并检查它是否可以处理它;在这种情况下,1.x提供商。

您只需扩展杰克逊已在其中提供的工件,而不是完全创建自己的工具

@Jackson2

你会扩展<dependency> <groupId>com.fasterxml.jackson.jaxrs</groupId> <artifactId>jackson-jaxrs-json-provider</artifactId> <version>2.9.2</version> </dependency>

JacksonJaxbJsonProvider

然后使用@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Jackson2 { } @Provider @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class MyProvider extends JacksonJaxbJsonProvider { @Context private ExtendedUriInfo info; @Override public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { if (!info.getMatchedMethod().getDeclaringResource().isAnnotationPresent(Jackson2.class)) { return false; } return super.isReadable(type, genericType, annotations, mediaType); } @Override public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { if (!info.getMatchedMethod().getDeclaringResource().isAnnotationPresent(Jackson2.class)) { return false; } return super.isWriteable(type, genericType, annotations, mediaType); } } 注释您的资源类。

我试图让这个工作起来时遇到问题,因为我使用的是Jackson 2.8.4。它接缝整条2.8线都有问题。不知道它是什么,但2.8,我的提供商根本不会注册。我测试了2.2-2.9的次要版本(不包括2.8),它们都有效。

至于优先权,我不确定泽西岛如何确定优先权。如果首先调用1.x提供程序,那么这个解决方案将全部崩溃。解决这个问题的一种方法是使用组合而不是继承,您可以在其中确定在@Jackson2readFrom方法中使用哪个读取器/写入器(1.x或2.x)。 1.x版本也是writeTo但它使用了JacksonJaxbJsonProvider包装。从我测试的内容来看,我的提供者总是先被调用,所以这可能不需要。不幸的是,我不能确认这是设计的。


1
投票

根据Paul Samantha的解决方案,创建2个提供商对我来说很好。

codehaus

public class Main {
  public static void main(final String[] args) {
    ResourceConfig config = new ResourceConfig();
    config.register(Service1.class)
        .register(Service2.class)
        .register(JacksonV1Provider.class)
        .register(JacksonV2Provider.class);
    GrizzlyHttpServerFactory.createHttpServer(URI.create("http://0.0.0.0:8123"), config);
  }
}

@Provider
public class JacksonV1Provider extends org.codehaus.jackson.jaxrs.JacksonJsonProvider {
  @Context
  private ExtendedUriInfo uriInfo;

  @Override
  public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
    return uriInfo.getPath().contains("/v1/");
  }

  @Override
  public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
    return uriInfo.getPath().contains("/v1/");
  }
}

@Provider
public class JacksonV2Provider extends com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider {
  @Context
  private ExtendedUriInfo uriInfo;

  @Override
  public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
    return uriInfo.getPath().contains("/v2/");
  }

  @Override
  public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
    return uriInfo.getPath().contains("/v2/");
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.