在Jersey中使用自定义的ObjectWriter

时间:2019-03-11 13:34:44

标签: java json jackson jersey retrofit2

我正在开发REST Web服务。 Jersey是jax-rs提供者,而Jackson是序列化/反序列化的工具。我还基于Retrofit2开发客户端。

我的类层次结构由第三方库提供,所有类均来自根基类BaseObject。这些类中的一些类具有不受欢迎的吸气剂,例如isEmpty,我要在序列化时忽略(请注意,根本不要对它们进行序列化,而在我的情况下在反序列化上使用FAIL_ON_UNKNOWN_PROPERTIES是不够的)。

我已在@JsonFilter上使用Mixins使用了Jackson BaseClass。据我所知,要应用过滤器,必须使用以下内容:

new ObjectMapper().writer(filterProvider).writeValueAsString...

一切正常,到此为止:不需要的属性已从生成的json中成功过滤。

现在,我必须配置Jersey和Retrofit2以使用我自定义的json序列化器/反序列化器。

对于Jersey,可以使用实现Provider的{​​{1}}类并以ContextResolver<ObjectMapper>方法返回自定义的ObjectMapper的类来配置序列化/反序列化。

类似于Retrofit2,通过使用 getContext(Class<?> type),您可以自定义序列化/反序列化。

问题在于 Retrofit.Builder().addConverterFactory(JacksonConverterFactory.create(objectMapper))的类型为new ObjectMapper().writer(filterProvider),而不是类型的ObjectWriter。如何告诉Jersey和Retrofit2使用我的自定义ObjectMapper(使用过滤器)?

1 个答案:

答案 0 :(得分:1)

自Jackson的2.6版本开始,它具有ObjectMapper的'setFilterProvider'方法。 我没有尝试过,但是文档中对此有描述:https://fasterxml.github.io/jackson-databind/javadoc/2.6/com/fasterxml/jackson/databind/ObjectMapper.html#setFilterProvider-com.fasterxml.jackson.databind.ser.FilterProvider-。您可以尝试一下,因为说明适合您的情况。

我使用Jersey 2.7和Jackson 2.9.5构建了一个测试服务。它工作正常,但您必须知道一些技巧来运行它。

在pom.xml中添加Jersey和Jackson:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey</groupId>
            <artifactId>jersey-bom</artifactId>
            <version>${jersey.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet-core</artifactId>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>${jackson.version}</version>
    </dependency>
</dependencies>
<properties>
    <jersey.version>2.7</jersey.version>
    <jackson.version>2.9.5</jackson.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

您必须定义这种依赖性:

    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
    </dependency>

这是强制性的。

在web.xml中,您必须引用服务的配置:

<web-app version="2.5"
     xmlns="http://java.sun.com/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
    <servlet-name>Jersey Web Application</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>org.glassfish.jersey.server.ResourceConfig</param-name>
        <param-value>com.home.MyApplication</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

MyApplication.java:

package com.home;

import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;

import javax.ws.rs.ApplicationPath;

@ApplicationPath("/webapi")
public class MyApplication extends ResourceConfig {

    public MyApplication() {

        register(ObjectMapperProvider.class);
        register(JacksonFeature.class);
        register(MyResource.class);

    }
}

使用自定义ObjectMapperProvider时,您必须注册JacksonFeature.class,因为没有它,Jersey不会使用自定义ObjectMapperProvider。

ObjectMapperProvider.java:

package com.home;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

@Provider
public class ObjectMapperProvider implements ContextResolver<ObjectMapper>{

    final ObjectMapper defaultObjectMapper;

    public ObjectMapperProvider() {
        defaultObjectMapper = createDefaultMapper();
    }

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

    public static ObjectMapper createDefaultMapper() {

        final ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        mapper.setFilters(new SimpleFilterProvider().addFilter("dataFilter", SimpleBeanPropertyFilter.serializeAllExcept("region", "city")));
        return mapper;

    }
}

要定义过滤器,请使用'setFilters'方法。不建议使用此方法,但是泽西岛的名为“ jersey-hk2”的库不知道新方法“ setFilterProvider”,并且会引发异常。使用旧方法,一切正常。

具有@JsonFilter的业务对象:

@JsonFilter("dataFilter")
public class SimpleData {

    @JsonProperty("name")
    String firstName;

    @JsonProperty("secondName")
    String lastName;

    @JsonProperty("country")
    String country;

    @JsonProperty("region")
    String region;

    @JsonProperty("city")
    String city;

    @JsonProperty("genre")
    String genre;

    public SimpleData() {

        this.firstName = "Bryan";
        this.lastName = "Adams";

        this.country = "Canada";
        this.region = "Ontario";
        this.city = "Kingston";
        this.genre = "Rock";

    }

    public String getFirstName() {    return firstName;       }
    public void setFirstName(String firstName) {  this.firstName = firstName;  }
    public String getLastName() {   return lastName;    }
    public void setLastName(String lastName) {  this.lastName = lastName;       }
    public String getCountry() {    return country;    }
    public void setCountry(String country) {  this.country = country;      }
    public String getRegion() {   return region;     }
    public void setRegion(String region) {   this.region = region;       }
    public String getCity() {  return city;     }
    public void setCity(String city) {   this.city = city;     }
    public String getGenre() {   return genre;      }
    public void setGenre(String genre) {    this.genre = genre;     }
}

MyResource.java:

@Path("myresource")
public class MyResource {


    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public SimpleData getIt() {

        return new SimpleData();

    }
}

已过滤的结果:

enter image description here