How to use two versions of Jackson (1.x and 2.x) in the same Jersey JAX-RS application?

为君一笑 提交于 2019-12-05 16:28:42

What you can do is create a MessageBodyReader/Writer that handles the 2.x version of Jackson. The isReadable and isWritable methods determine which entities it can handle. What you can do to check is inject Jersey's ExtendedUriInfo into the provider and check the resource class for your @Jackson2 annotation. If the annotation is not present than your provider ignores the entity and the runtime moves on to the next provider and checks if it can handle it; in this case the 1.x provider.

Instead of completely creating your own, you would just extend the provider that Jackson already provides in it artifact

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

You would extend the 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);
    }
}

Then just annotate your resource classes with @Jackson2.

I had problems earlier while trying to get this to work, because I was using Jackson 2.8.4. It seams the whole 2.8 line has a problem. Not sure what it is, but with 2.8, my provider would not register at all. I tested with minor versions 2.2-2.9 (excluding 2.8) and they all work.

As far as priority, I'm not sure about how Jersey determines precedence. If the 1.x provider were to be called first, then this solution would all fall apart. One way around this would be to use composition instead of inheritance, where you would Just determine which reader/writer (1.x or 2.x) to use inside your readFrom and writeTo methods. The 1.x version is also JacksonJaxbJsonProvider but it used the codehaus packaging. From what I tested though, my provider always gets called first, so this may not be needed. Unfortunately, I cannot confirm that this is by design.

Based on the solution of Paul Samsotha, creaing 2 providers worked fine for me.

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"
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!