我在旧版泽西岛(1.19)以及旧杰克逊(1.19.13)的项目中工作。我想切换到新的杰克逊(2.x)反序列化,但仅适用于新的端点(以及逐渐的旧端点),因为一步到杰克逊2和/或泽西2的迁移将非常困难(哦,巨石! )。
我已经看过一些关于如何在泽西岛提供自定义配置的ObjectMapper和杰克逊供应商的话题,或者如何在1.x泽西岛中安装新杰克逊,但这不是我想要的,至少不是全部。
我想象的解决方案是(最好)用@ UseJackson2注释我的新JAX-RS端点,或者让一些基类从正确的包中检索ObjectMapper,对于这个特定的端点并在以后扩展它 - 在其他强制给定端点使用其他(反)序列化提供程序的字通常。
我已经看到了不同配置ObjectMapper的提供程序的例子(就像这里的qazxsw poi),但在我的例子中,ObjectMappers将来自完全不同的包/ maven工件。
你可以做的是创建一个处理2.x版Jackson的Using Jackson in Jersey with multiple configured ObjectMappers。 MessageBodyReader/Writer
和isReadable
方法确定它可以处理哪些实体。您可以检查的是将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提供程序,那么这个解决方案将全部崩溃。解决这个问题的一种方法是使用组合而不是继承,您可以在其中确定在@Jackson2
和readFrom
方法中使用哪个读取器/写入器(1.x或2.x)。 1.x版本也是writeTo
但它使用了JacksonJaxbJsonProvider
包装。从我测试的内容来看,我的提供者总是先被调用,所以这可能不需要。不幸的是,我不能确认这是设计的。
根据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/");
}
}