import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.jaxrs.cfg.AnnotationBundleKey;
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
import com.fasterxml.jackson.jaxrs.json.JsonEndpointConfig;
import com.fasterxml.jackson.jaxrs.util.ClassKey;
import org.jboss.resteasy.annotations.providers.NoJackson;
import org.jboss.resteasy.annotations.providers.jackson.Formatted;
import org.jboss.resteasy.util.DelegatingOutputStream;
import org.jboss.resteasy.util.FindAnnotation;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
/**
* Custom Jackson Provider which ignoring unknown properties,doing not write null value by default.
*
* @author 01375295
*/
@Provider
@Consumes({"application/*+json", "text/json"})
@Produces({"application/*+json", "text/json"})
public class CotpResteasyJackson2Provider extends JacksonJaxbJsonProvider {
public CotpResteasyJackson2Provider() {
super(getObjectMapper(), DEFAULT_ANNOTATIONS);
}
private static synchronized ObjectMapper getObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
/*
该特性决定是否在writeValue()方法之后就调用JsonGenerator.flush()方法。
当我们需要先压缩,然后再flush,则可能需要false。
objectMapper.disable(SerializationFeature.FLUSH_AFTER_WRITE_VALUE);
*/
//setting ignore unknown properties.
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
//setting do not write null value of object.
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.disable(SerializationFeature.WRITE_NULL_MAP_VALUES);
objectMapper.setTimeZone(TimeZone.getDefault());
return objectMapper;
}
@Override
public boolean isReadable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
if (FindAnnotation.findAnnotation(aClass, annotations, NoJackson.class) != null) {
return false;
}
return super.isReadable(aClass, type, annotations, mediaType);
}
@Override
public boolean isWriteable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
if (FindAnnotation.findAnnotation(aClass, annotations, NoJackson.class) != null) {
return false;
}
return super.isWriteable(aClass, type, annotations, mediaType);
}
// Currently we need to override readFrom and writeTo because Jackson 2.2.1 does not cache correctly
// It does not allow to have a ContextResolver that chooses different mappers per Java type.
private static class ClassAnnotationKey {
private AnnotationBundleKey annotations;
private ClassKey classKey;
private int hash;
private ClassAnnotationKey(Class<?> clazz, Annotation[] annotations) {
this.annotations = new AnnotationBundleKey(annotations, AnnotationBundleKey.class);
this.classKey = new ClassKey(clazz);
this.hash = this.annotations.hashCode();
this.hash = 31 * this.hash + this.classKey.hashCode();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o != null && this.getClass() == o.getClass()) {
ClassAnnotationKey that = (ClassAnnotationKey) o;
if (!this.annotations.equals(that.annotations)) {
return false;
} else {
return this.classKey.equals(that.classKey);
}
} else {
return false;
}
}
@Override
public int hashCode() {
return this.hash;
}
}
protected final ConcurrentHashMap<ClassAnnotationKey, JsonEndpointConfig> _readers
= new ConcurrentHashMap<ClassAnnotationKey, JsonEndpointConfig>();
@Override
public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
throws IOException {
ClassAnnotationKey key = new ClassAnnotationKey(type, annotations);
JsonEndpointConfig endpoint;
endpoint = _readers.get(key);
// not yet resolved (or not cached any more)? Resolve!
if (endpoint == null) {
ObjectMapper mapper = locateMapper(type, mediaType);
endpoint = _configForReading(mapper, annotations, type);
_readers.put(key, endpoint);
}
ObjectReader reader = endpoint.getReader();
JsonParser jp = _createParser(reader, entityStream);
// If null is returned, considered to be empty stream
if (jp == null || jp.nextToken() == null) {
return null;
}
// [Issue#1]: allow 'binding' to JsonParser
if (((Class<?>) type) == JsonParser.class) {
return jp;
}
return reader.withType(genericType).readValue(jp);
}
protected final ConcurrentHashMap<ClassAnnotationKey, JsonEndpointConfig> _writers
= new ConcurrentHashMap<ClassAnnotationKey, JsonEndpointConfig>();
@Override
public void writeTo(Object value, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
throws IOException {
entityStream = new DelegatingOutputStream(entityStream) {
@Override
public void flush() throws IOException {
// don't flush as this is a performance hit on Undertow.
// and causes chunked encoding to happen.
}
};
ClassAnnotationKey key = new ClassAnnotationKey(type, annotations);
JsonEndpointConfig endpoint;
endpoint = _writers.get(key);
// not yet resolved (or not cached any more)? Resolve!
if (endpoint == null) {
ObjectMapper mapper = locateMapper(type, mediaType);
endpoint = _configForWriting(mapper, annotations, type);
// and cache for future reuse
_writers.put(key, endpoint);
}
ObjectWriter writer = endpoint.getWriter();
boolean withIndentOutput = false; // no way to replace _serializationConfig
// we can't cache this.
if (annotations != null) {
for (Annotation annotation : annotations) {
if (annotation.annotationType().equals(Formatted.class)) {
withIndentOutput = true;
break;
}
}
}
/* 27-Feb-2009, tatu: Where can we find desired encoding? Within
* HTTP headers?
*/
JsonEncoding enc = findEncoding(mediaType, httpHeaders);
JsonGenerator jg = writer.getFactory().createGenerator(entityStream, enc);
try {
// Want indentation?
if (writer.isEnabled(SerializationFeature.INDENT_OUTPUT) || withIndentOutput) {
jg.useDefaultPrettyPrinter();
}
// 04-Mar-2010, tatu: How about type we were given? (if any)
JavaType rootType = null;
if (genericType != null && value != null) {
/* 10-Jan-2011, tatu: as per [JACKSON-456], it's not safe to just force root
* type since it prevents polymorphic type serialization. Since we really
* just need this for generics, let's only use generic type if it's truly
* generic.
*/
if (genericType.getClass() != Class.class) { // generic types are other impls of 'java.lang.reflect.Type'
/* This is still not exactly right; should root type be further
* specialized with 'value.getClass()'? Let's see how well this works before
* trying to come up with more complete solution.
*/
rootType = writer.getTypeFactory().constructType(genericType);
/* 26-Feb-2011, tatu: To help with [JACKSON-518], we better recognize cases where
* type degenerates back into "Object.class" (as is the case with plain TypeVariable,
* for example), and not use that.
*/
if (rootType.getRawClass() == Object.class) {
rootType = null;
}
}
}
// Most of the configuration now handled through EndpointConfig, ObjectWriter
// but we may need to force root type:
if (rootType != null) {
writer = writer.withType(rootType);
}
value = endpoint.modifyBeforeWrite(value);
writer.writeValue(jg, value);
} finally {
jg.close();
}
}
}
1、在service中加入以上类;
2、在service的META-INF下创建services文件夹
3、在services文件夹下创建javax.ws.rs.ext.Providers文件
4、javax.ws.rs.ext.Providers中写入上述类的引用
引用的依赖:
<!-- 使用json序列化 -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson2-provider</artifactId>
<version>3.0.17.Final</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.0</version>
</dependency>