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

时间:2017-11-02 14:16:11

标签: java jackson jersey jax-rs jersey-1.0

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

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

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

我已经看过使用不同配置的ObjectMappers的提供程序的示例(例如此处Using Jackson in Jersey with multiple configured ObjectMappers),但在我的情况下,ObjectMappers将来自完全不同的包/ maven工件。

2 个答案:

答案 0 :(得分:3)

你可以做的是创建一个MessageBodyReader/Writer来处理杰克逊的2.x版本。 isReadableisWritable方法确定它可以处理哪些实体。您可以检查的是将Jersey的ExtendedUriInfo注入提供程序并检查资源类以查找@Jackson2注释。如果注释不存在,则提供者忽略该实体,并且运行时移动到下一个提供者并检查它是否可以处理它;在这种情况下是1.x提供者。

而不是完全创建自己的,你只需要扩展杰克逊已经提供的提供者

<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);
    }
}

然后使用@Jackson2注释您的资源类。

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

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

答案 1 :(得分:1)

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

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/");
  }
}

dependencies {
    compile group: 'org.glassfish.jersey.containers', name: 'jersey-container-grizzly2-http', version: '2.17'
    compile 'org.glassfish.jersey.media:jersey-media-json-jackson:2.17'

    compile group: "org.codehaus.jackson", name: "jackson-mapper-asl", version: "$jackson1_version"
    compile group: "org.codehaus.jackson", name: "jackson-jaxrs", version: "$jackson1_version"
    compile group: "org.codehaus.jackson", name: "jackson-xc", version: "$jackson1_version"

    compile "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jackson2_vervion"
    compile "com.fasterxml.jackson.core:jackson-core:$jackson2_vervion"
    compile "com.fasterxml.jackson.core:jackson-annotations:$jackson2_vervion"
}