我正在开发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
(使用过滤器)?
答案 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();
}
}
已过滤的结果: