package com.alibaba.fastjson.support.spring; 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 org.springframework.http.HttpHeaders; import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; import org.springframework.http.MediaType; import org.springframework.http.converter.AbstractGenericHttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotWritableException; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.support.config.FastJsonConfig; import com.alibaba.fastjson.util.IOUtils; /** * Fastjson for Spring MVC Converter. * <p> * Compatible Spring MVC version 4.2+ * <p> * support to write JSONP * * <pre> * Configuration in xml: * <code> * <mvc:annotation-driven> * <mvc:message-converters> * <bean * class="com.alibaba.fastjson.support.spring.FastJsonpHttpMessageConverter4"> * <property name="supportedMediaTypes"> * <list> * <value>application/json;charset=UTF-8</value> * </list> * </property> * </bean> * </mvc:message-converters> * </mvc:annotation-driven> * * <bean id="fastJsonpResponseBodyAdvice" class="com.alibaba.fastjson.support.spring.FastJsonpResponseBodyAdvice"> * <constructor-arg> * <list> * <value>callback</value> * <value>jsonp</value> * </list> * </constructor-arg> * </bean> * </code> * </pre> * * <pre> * Configuration in java: * @EnableWebMvc * @Configuration * public class Config extends WebMvcConfigurerAdapter { * @ean * public FastJsonpResponseBodyAdvice fastJsonpResponseBodyAdvice() { * return new FastJsonpResponseBodyAdvice("callback", "jsonp"); * } * * @Override * public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { * converters.add(0, new FastJsonpHttpMessageConverter4()); * super.extendMessageConverters(converters); * } * } * <code> * </code> * </pre> * * @author Jerry.Chen * @since 1.2.20 */ public class FastJsonpHttpMessageConverter4 extends AbstractGenericHttpMessageConverter<Object> { /** * with fastJson config */ private FastJsonConfig fastJsonConfig = new FastJsonConfig(); /** * @return the fastJsonConfig. * @since 1.2.11 */ public FastJsonConfig getFastJsonConfig() { return fastJsonConfig; } /** * @param fastJsonConfig the fastJsonConfig to set. * @since 1.2.11 */ public void setFastJsonConfig(FastJsonConfig fastJsonConfig) { this.fastJsonConfig = fastJsonConfig; } /** * Can serialize/deserialize all types. */ public FastJsonpHttpMessageConverter4() { super(MediaType.ALL); } @Override protected boolean supports(Class<?> paramClass) { return true; } public Object read(Type type, // Class<?> contextClass, // HttpInputMessage inputMessage // ) throws IOException, HttpMessageNotReadableException { InputStream in = inputMessage.getBody(); return JSON.parseObject(in, fastJsonConfig.getCharset(), type, fastJsonConfig.getFeatures()); } @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()); } @Override protected void writeInternal(Object obj, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { HttpHeaders headers = outputMessage.getHeaders(); ByteArrayOutputStream outnew = new ByteArrayOutputStream(); int len = writePrefix(outnew, obj); Object value = obj; if (obj instanceof MappingFastJsonValue) { MappingFastJsonValue container = (MappingFastJsonValue) obj; value = container.getValue(); } len += JSON.writeJSONString(outnew, // fastJsonConfig.getCharset(), // value, // fastJsonConfig.getSerializeConfig(), // fastJsonConfig.getSerializeFilters(), // fastJsonConfig.getDateFormat(), // JSON.DEFAULT_GENERATE_FEATURE, // fastJsonConfig.getSerializerFeatures()); len += writeSuffix(outnew, obj); if (fastJsonConfig.isWriteContentLength()) { headers.setContentLength(len); } OutputStream out = outputMessage.getBody(); outnew.writeTo(out); outnew.close(); } private static final byte[] JSONP_FUNCTION_PREFIX_BYTES = "/**/".getBytes(IOUtils.UTF8); private static final byte[] JSONP_FUNCTION_SUFFIX_BYTES = ");".getBytes(IOUtils.UTF8); /** * 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; } /** * Write a suffix after the main content. */ 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; } return length; } }