Skip to content

Commit

Permalink
Spring support optimize
Browse files Browse the repository at this point in the history
1.优化FastjsonHttpMessageConverter异常信息
使用FastjsonHttpMessageConverter替代以下功能:
2.同时支持 @FastjsonView注解 和 返回JSONP格式。
3.spring4支持: @deprecated FastjsonHttpMessageConverter4 (spring4.x版本中已经在AbstractHttpMessageConverter类提供了 StreamingHttpOutputMessage的支持了,所以不需要这样断裂性的升级)
4.jsonp支持: @deprecated FastJsonpHttpMessageConverter4
其他:
5.jsonp AOP支持 :@deprecated FastJsonpResponseBodyAdvice(无法同时支持响应json和jsonp)  使用JSONPResponseBodyAdvice 和 @REsponseJSONP替代
6.添加了新的功能的单元测试。

建议:
1.FastJsonContainer 作为包保护类使用。
2.@FastjsonView 容易让人认为是AbstractView的子类。  但其实是一个方法级别的自定义序列化参数传递的注解。 同样包括他的AOP处理类 FastJsonViewResponseBodyAdvice。  建议可以做一些名字上的优化。
  • Loading branch information
neil4dong committed Jul 22, 2017
1 parent e886ddc commit 0013704
Show file tree
Hide file tree
Showing 10 changed files with 592 additions and 337 deletions.
@@ -1,6 +1,7 @@
package com.alibaba.fastjson.support.spring;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
Expand All @@ -17,25 +18,38 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* Fastjson for Spring MVC Converter.
* <p>
* Compatible Spring MVC version 4.2- (Below 4.2)
* Compatible Spring MVC version 3.2+
*
* @author VictorZeng
* @see AbstractHttpMessageConverter
* @see GenericHttpMessageConverter
* @since 1.2.10
* <p>
* <p>
* <p>
* Supported return type:
* <p/>
* Simple object: Object
* <p/>
* With property filter :FastJsonContainer[Object]
* <p/>
* Jsonp :MappingFastJsonValue[Object]
* <p/>
* Jsonp with property filter: MappingFastJsonValue[FastJsonContainer[Object]]
*/

public class FastJsonHttpMessageConverter //
extends AbstractHttpMessageConverter<Object> //
public class FastJsonHttpMessageConverter extends AbstractHttpMessageConverter<Object>//
implements GenericHttpMessageConverter<Object> {
private Charset charset = Charset.forName("UTF-8");
private Charset charset = Charset.forName("UTF-8");

@Deprecated
protected SerializerFeature[] features = new SerializerFeature[0];
Expand Down Expand Up @@ -130,113 +144,157 @@ public void addSerializeFilter(SerializeFilter filter) {

@Override
protected boolean supports(Class<?> clazz) {

return true;
}


@Override
public boolean canRead(Type type, Class<?> contextClass, MediaType mediaType) {
return super.canRead(contextClass, mediaType);
}

@Override
public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
return super.canWrite(clazz, mediaType);
}

/*
* @see org.springframework.http.converter.GenericHttpMessageConverter#read(java.lang.reflect.Type, java.lang.Class, org.springframework.http.HttpInputMessage)
*/
public Object read(Type type, //
Class<?> contextClass, //
HttpInputMessage inputMessage //
) throws IOException, HttpMessageNotReadableException {
return readType(type, inputMessage);
}

/*
* @see org.springframework.http.converter.GenericHttpMessageConverter.write
*/
public void write(Object o, Type type, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
writeInternal(o, outputMessage);
}


/*
* @see org.springframework.http.converter.AbstractHttpMessageConverter#readInternal(java.lang.Class, org.springframework.http.HttpInputMessage)
*/
@Override
protected Object readInternal(Class<? extends Object> clazz, //
HttpInputMessage inputMessage //
) throws IOException, HttpMessageNotReadableException {

InputStream in = inputMessage.getBody();
return JSON.parseObject(in, fastJsonConfig.getCharset(), clazz, fastJsonConfig.getFeatures());
return readType(clazz, inputMessage);
}

private Object readType(Type type, HttpInputMessage inputMessage) throws IOException {

try {
InputStream in = inputMessage.getBody();
return JSON.parseObject(in, fastJsonConfig.getCharset(), type, fastJsonConfig.getFeatures());
} catch (JSONException ex) {
throw new HttpMessageNotReadableException("JSON parse error: " + ex.getMessage(), ex);
} catch (IOException ex) {
throw new HttpMessageNotReadableException("I/O error while reading input message", ex);
}
}

@Override
protected void writeInternal(Object obj, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
HttpHeaders headers = outputMessage.getHeaders();
protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {

ByteArrayOutputStream outnew = new ByteArrayOutputStream();
try {
HttpHeaders headers = outputMessage.getHeaders();

boolean writeAsToString = false;
if (obj != null) {
String className = obj.getClass().getName();
if ("com.fasterxml.jackson.databind.node.ObjectNode".equals(className)) {
writeAsToString = true;
//获取全局配置的filter
SerializeFilter[] globalFilters = fastJsonConfig.getSerializeFilters();
List<SerializeFilter> allFilters = new ArrayList<SerializeFilter>(Arrays.asList(globalFilters));

//不知道为什么会有这行代码, 但是为了保持和原来的行为一致,还是保留下来
Object value = strangeCodeForJackson(object);

if (value instanceof FastJsonContainer) {
FastJsonContainer fastJsonContainer = (FastJsonContainer) value;
PropertyPreFilters filters = fastJsonContainer.getFilters();
allFilters.addAll(filters.getFilters());
value = fastJsonContainer.getValue();
}
}

if (writeAsToString) {
String text = obj.toString();
OutputStream out = outputMessage.getBody();
out.write(text.getBytes());
if (fastJsonConfig.isWriteContentLength()) {
headers.setContentLength(text.length());
//jsonp,保留对原本直接返回MappingFastJsonValue方法的支持
//更好的方式是直接返回com.alibaba.fastjson.JSONPObject
if (value instanceof MappingFastJsonValue) {
value = ((MappingFastJsonValue) value).getValue();
}
} else {
int len = JSON.writeJSONString(outnew, //


int len = writePrefix(outnew, object);
len += JSON.writeJSONString(outnew, //
fastJsonConfig.getCharset(), //
obj, //
value, //
fastJsonConfig.getSerializeConfig(), //
fastJsonConfig.getSerializeFilters(), //
//fastJsonConfig.getSerializeFilters(), //
allFilters.toArray(new SerializeFilter[allFilters.size()]),
fastJsonConfig.getDateFormat(), //
JSON.DEFAULT_GENERATE_FEATURE, //
fastJsonConfig.getSerializerFeatures());
len += writeSuffix(outnew, object);

if (fastJsonConfig.isWriteContentLength()) {
headers.setContentLength(len);
}

OutputStream out = outputMessage.getBody();
outnew.writeTo(out);
}

outnew.writeTo(outputMessage.getBody());

outnew.close();
} catch (JSONException ex) {
throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex);
} finally {
outnew.close();
}
}

/*
* @see org.springframework.http.converter.GenericHttpMessageConverter#canRead(java.lang.reflect.Type, java.lang.Class, org.springframework.http.MediaType)
*/
public boolean canRead(Type type, Class<?> contextClass, MediaType mediaType) {
return super.canRead(contextClass, mediaType);
private Object strangeCodeForJackson(Object obj) {
if (obj != null) {
String className = obj.getClass().getName();
if ("com.fasterxml.jackson.databind.node.ObjectNode".equals(className)) {
return obj.toString();
}
}
return obj;
}

/*
* @see org.springframework.http.converter.GenericHttpMessageConverter#canWrite(java.lang.reflect.Type, java.lang.Class, org.springframework.http.MediaType)
*/
public boolean canWrite(Type type, Class<?> contextClass, MediaType mediaType) {
return super.canWrite(contextClass, mediaType);
}

/*
* @see org.springframework.http.converter.GenericHttpMessageConverter#read(java.lang.reflect.Type, java.lang.Class, org.springframework.http.HttpInputMessage)
*/
public Object read(Type type, //
Class<?> contextClass, //
HttpInputMessage inputMessage //
) throws IOException, HttpMessageNotReadableException {
private static final byte[] JSONP_FUNCTION_PREFIX_BYTES = "/**/".getBytes(IOUtils.UTF8);
private static final byte[] JSONP_FUNCTION_SUFFIX_BYTES = ");".getBytes(IOUtils.UTF8);

InputStream in = inputMessage.getBody();
return JSON.parseObject(in, fastJsonConfig.getCharset(), type, fastJsonConfig.getFeatures());
/**
* Write a prefix before the main content.
*/
protected int writePrefix(ByteArrayOutputStream out, Object object) throws IOException {
String jsonpFunction = (object instanceof MappingFastJsonValue ? ((MappingFastJsonValue) object)
.getJsonpFunction() : null);
int length = 0;
if (jsonpFunction != null) {
out.write(JSONP_FUNCTION_PREFIX_BYTES);
byte[] bytes = (jsonpFunction + "(").getBytes(IOUtils.UTF8);
out.write(bytes);
length += JSONP_FUNCTION_PREFIX_BYTES.length + bytes.length;
}
return length;
}

/*
* @see org.springframework.http.converter.GenericHttpMessageConverter#write(java.lang.Object, java.lang.reflect.Type, org.springframework.http.MediaType, org.springframework.http.HttpOutputMessage)
/**
* Write a suffix after the main content.
*/
public void write(Object t, //
Type type, //
MediaType contentType, //
HttpOutputMessage outputMessage //
) throws IOException, HttpMessageNotWritableException {

HttpHeaders headers = outputMessage.getHeaders();
if (headers.getContentType() == null) {
if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
contentType = getDefaultContentType(t);
}
if (contentType != null) {
headers.setContentType(contentType);
}
}
if (headers.getContentLength() == -1) {
Long contentLength = getContentLength(t, headers.getContentType());
if (contentLength != null) {
headers.setContentLength(contentLength);
}
protected int writeSuffix(ByteArrayOutputStream out, Object object) throws IOException {
String jsonpFunction = (object instanceof MappingFastJsonValue ? ((MappingFastJsonValue) object)
.getJsonpFunction() : null);
int length = 0;
if (jsonpFunction != null) {
out.write(JSONP_FUNCTION_SUFFIX_BYTES);
length += JSONP_FUNCTION_SUFFIX_BYTES.length;
}
writeInternal(t, outputMessage);
outputMessage.getBody().flush();
return length;
}


}

0 comments on commit 0013704

Please sign in to comment.