org.macrocloud.kernel.toolkit.jackson.AbstractReadWriteJackson2HttpMessageConverter Maven / Gradle / Ivy
package org.macrocloud.kernel.toolkit.jackson;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.PrettyPrinter;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import org.macrocloud.kernel.toolkit.utils.Charsets;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.TypeUtils;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
/**
* Title: AbstractReadWriteJackson2HttpMessageConverter.java
* Description:
*/
public abstract class AbstractReadWriteJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
/** The Constant DEFAULT_CHARSET. */
private static final java.nio.charset.Charset DEFAULT_CHARSET = Charsets.UTF_8;
/** The write object mapper. */
private final ObjectMapper writeObjectMapper;
/** The sse pretty printer. */
@Nullable
private PrettyPrinter ssePrettyPrinter;
/**
* 构造函数.
*
* @param readObjectMapper the read object mapper
* @param writeObjectMapper the write object mapper
*/
public AbstractReadWriteJackson2HttpMessageConverter(ObjectMapper readObjectMapper, ObjectMapper writeObjectMapper) {
super(readObjectMapper);
this.writeObjectMapper = writeObjectMapper;
initSsePrettyPrinter();
}
/**
* 构造函数.
*
* @param readObjectMapper the read object mapper
* @param writeObjectMapper the write object mapper
* @param supportedMediaType the supported media type
*/
public AbstractReadWriteJackson2HttpMessageConverter(ObjectMapper readObjectMapper, ObjectMapper writeObjectMapper, MediaType supportedMediaType) {
this(readObjectMapper, writeObjectMapper);
setSupportedMediaTypes(Collections.singletonList(supportedMediaType));
initSsePrettyPrinter();
}
/**
* 构造函数.
*
* @param readObjectMapper the read object mapper
* @param writeObjectMapper the write object mapper
* @param supportedMediaTypes the supported media types
*/
public AbstractReadWriteJackson2HttpMessageConverter(ObjectMapper readObjectMapper, ObjectMapper writeObjectMapper, List supportedMediaTypes) {
this(readObjectMapper, writeObjectMapper);
setSupportedMediaTypes(supportedMediaTypes);
}
/**
* Inits the sse pretty printer.
*/
private void initSsePrettyPrinter() {
setDefaultCharset(DEFAULT_CHARSET);
DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter();
prettyPrinter.indentObjectsWith(new DefaultIndenter(" ", "\ndata:"));
this.ssePrettyPrinter = prettyPrinter;
}
/**
* canWrite.
*
* @param clazz the clazz
* @param mediaType the media type
* @return boolean true, if successful
*/
@Override
public boolean canWrite(@NonNull Class> clazz, @Nullable MediaType mediaType) {
if (!canWrite(mediaType)) {
return false;
}
AtomicReference causeRef = new AtomicReference<>();
if (this.objectMapper.canSerialize(clazz, causeRef)) {
return true;
}
logWarningIfNecessary(clazz, causeRef.get());
return false;
}
/**
* writeInternal.
*
* @param object the object
* @param type the type
* @param outputMessage the output message
* @throws IOException Signals that an I/O exception has occurred.
* @throws HttpMessageNotWritableException the http message not writable exception
*/
@Override
protected void writeInternal(@NonNull Object object, @Nullable Type type, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
MediaType contentType = outputMessage.getHeaders().getContentType();
JsonEncoding encoding = getJsonEncoding(contentType);
JsonGenerator generator = this.writeObjectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding);
try {
writePrefix(generator, object);
Object value = object;
Class> serializationView = null;
FilterProvider filters = null;
JavaType javaType = null;
if (object instanceof MappingJacksonValue) {
MappingJacksonValue container = (MappingJacksonValue) object;
value = container.getValue();
serializationView = container.getSerializationView();
filters = container.getFilters();
}
if (type != null && TypeUtils.isAssignable(type, value.getClass())) {
javaType = getJavaType(type, null);
}
ObjectWriter objectWriter = (serializationView != null ?
this.writeObjectMapper.writerWithView(serializationView) : this.writeObjectMapper.writer());
if (filters != null) {
objectWriter = objectWriter.with(filters);
}
if (javaType != null && javaType.isContainerType()) {
objectWriter = objectWriter.forType(javaType);
}
SerializationConfig config = objectWriter.getConfig();
if (contentType != null && contentType.isCompatibleWith(MediaType.TEXT_EVENT_STREAM) &&
config.isEnabled(SerializationFeature.INDENT_OUTPUT)) {
objectWriter = objectWriter.with(this.ssePrettyPrinter);
}
objectWriter.writeValue(generator, value);
writeSuffix(generator, object);
generator.flush();
} catch (InvalidDefinitionException ex) {
throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
} catch (JsonProcessingException ex) {
throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getOriginalMessage(), ex);
}
}
}