Jackson 2 错误地序列化 Java java.nio.file.Path

Jackson 2 incorrectly serializing Java java.nio.file.Path

我在 Eclipse 4.6.1 中使用带有 Tomcat 8.5.6 的 RESTEasy 3.1.0.CR3,以及 JSBoss resteasy-jackson2-provider。我有一个简单的 JavaBean FooBar returns 一个字符串 "ID" 和一个 java.nio.file.Path "path".

Jackson 使它很容易序列化为 JSON。在我的 JAX-RS 资源中,我只是指定 @Produces("application/json; charset=UTF-8")。但是 Jackson 没有使用 Path.toString()。相反,它似乎在使用 Path.toURI().toString() 或其他东西:

{
  "id": "foo",
  "path": "file:///C:/Users/jdoe/bar"
}

为什么!??更重要的是,我怎样才能让 Jackson 简单地使用 PathtoString() 版本?

这是我的项目依赖关系树:

+- com.google.code.findbugs:jsr305:jar:3.0.1:provided
+- com.google.guava:guava:jar:20.0:compile
+- javax.ws.rs:javax.ws.rs-api:jar:2.0.1:provided
+- org.jboss.resteasy:resteasy-jaxrs:jar:3.1.0.CR3:compile
|  +- org.jboss.spec.javax.ws.rs:jboss-jaxrs-api_2.0_spec:jar:1.0.1.Beta1:compile
|  +- org.jboss.resteasy:resteasy-jaxrs-services:jar:3.1.0.CR3:compile
|  +- org.jboss.spec.javax.annotation:jboss-annotations-api_1.2_spec:jar:1.0.0.Final:compile
|  +- javax.activation:activation:jar:1.1.1:compile
|  +- org.apache.httpcomponents:httpclient:jar:4.5.2:compile
|  |  +- org.apache.httpcomponents:httpcore:jar:4.4.4:compile
|  |  +- commons-logging:commons-logging:jar:1.2:compile
|  |  \- commons-codec:commons-codec:jar:1.9:compile
|  +- commons-io:commons-io:jar:2.5:compile
|  +- net.jcip:jcip-annotations:jar:1.0:compile
|  \- org.jboss.logging:jboss-logging:jar:3.3.0.Final:compile
+- org.jboss.resteasy:resteasy-servlet-initializer:jar:3.1.0.CR3:compile
+- org.jboss.resteasy:resteasy-jackson2-provider:jar:3.1.0.CR3:compile
|  +- com.fasterxml.jackson.core:jackson-core:jar:2.8.3:compile
|  +- com.fasterxml.jackson.core:jackson-databind:jar:2.8.3:compile
|  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.8.3:compile
|  \- com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:jar:2.8.3:compile
|     +- com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:jar:2.8.3:compile
|     \- com.fasterxml.jackson.module:jackson-module-jaxb-annotations:jar:2.8.3:compile
+- junit:junit:jar:4.12:test
|  \- org.hamcrest:hamcrest-core:jar:1.3:test
\- org.hamcrest:hamcrest-library:jar:1.3:test

请注意, 我可以为我的 FooBar class 添加注释,这是一个领域模型 class应该与 RESTful API 序列化细节无关。

我想要一种简单的方法来连接到 RESTEasy 中的 Jackson2 并修改 Path 属性 值的序列化,而无需修改我的 class 或为我的 [= 编写自定义序列化程序40=].

这个 class 将覆盖默认的 Jackson2JsonProvider 帮助您根据需要配置 ObjectMapper,例如 Path.class 的序列化器从 NioPathSerializer 覆盖到 ToStringSerializer。

@Provider
@Consumes({"application/*+json", "text/json"})
@Produces({"application/*+json", "text/json"})
public class CustomJacksonProvider extends JacksonJsonProvider {

  public CustomJacksonProvider(){
    super(configureMapper(new ObjectMapper()));
  }

  public static ObjectMapper configureMapper(ObjectMapper mapper) {
    SimpleModule m = new SimpleModule("PathToString");
    m.addSerializer(Path.class,new ToStringSerializer());
    mapper.registerModule(m);
    return mapper;
  }

}

或者您也可以将 ContextResolver 用于将使用 ResteasyJackson2Provider(RestEasy default)

@Provider
@Consumes({"application/*+json", "text/json"})
@Produces({"application/*+json", "text/json"})
public class CustomJacksonProvider implements ContextResolver<ObjectMapper> {

  final ObjectMapper mapper;

  public CustomJacksonProvider(){
    mapper = new JsonMapperConfigurator(new ObjectMapper(), JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS)
            .getConfiguredMapper();
    SimpleModule m = new SimpleModule("PathToString");
    m.addSerializer(Path.class, new ToStringSerializer());
  }

  @Override
  public ObjectMapper getContext(Class<?> type) {
    return mapper;
  }
}

无论您使用何种方法,都将此添加给您web.xml

    <context-param>
       <param-name>resteasy.providers</param-name>
       <param-value>package.to.CustomJacksonProvider</param-value>
    </context-param>

如果您没有使用 web.xml 文件,return 您的 JAX-RS 应用程序的 Application.getClasses() 方法中的提供程序 class。

希望这对您有所帮助。

已编辑:

此外,您可能会错过此实现中的 JAXB 注释支持,您必须手动配置它,因为 JacksonJaxbJsonProvider 不会查找 JsonMapperConfigurator 的 Resolver/provider。在 CustomJackosnProviderJacksonJaxbJsonProvider.DEAFULT_ANNOATIONS 中将 JsonMapperConfiguration 与映射器一起使用。理想情况下,由于没有规定提供 JsonMapperConfiguration Resolver/Provider 并且 RestEasy 的 jackson 提供者不公开 arg 构造函数,提供者是最好的选择。既然他们做出了这个决定,理想情况下他们不应该在 ResteasyJackson2Provider 中进行任何定制。此外,ResteasyJackson2Provider 中只有功能是自定义 json 类型和更好的 class 级别的映射器缓存。

根据说明更新了代码