【源码分析】FastJson全局配置⽇期格式导致
@JSONField(format=yyy。。。
出现的问题
我全局配置的时间格式是:yyyy-MM-dd HH:mm:ss
@JSONField注解配置的时间格式是:yyyy-MM-dd
最终的返回结果是:yyyy-MM-dd HH:mm:ss
问题:为啥不是以注解定义的时间格式为主呢?
先说答案,后⾯再分析:
FastJson的全局配置⽇期格式会导致@JSONField注解失效
使⽤建议:
1.若全局配置了⽇期格式,就不要使⽤@JSONField注解
2.若想使⽤@JSONField注解,就不要全局配置⽇期格式
⼀、FastJson全局配置代码如下
@Configuration
public class FastJsonConverterConfig {
@Bean
public HttpMessageConverters fastJsonHttpMessageConverters() {
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(
SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteNullBooleanAsFalse
// SerializerFeature.WriteDateUseDateFormat
);
fastConverter.setFastJsonConfig(fastJsonConfig);
//全局指定了⽇期格式
fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
//该设置⽬的,为了兼容jackson
fastConverter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON,MediaType.APPLICATION_JSON_UTF8,MediaType.APPLICATION_OCTET_STREAM)); HttpMessageConverter<?> converter = fastConverter;
return new HttpMessageConverters(converter);
}
}
⼆、使⽤@JSONField注解的Java Bean代码如下
@Data
public class UserCardInfoResponseModel {
@JSONField(format = "yyyy-MM-dd")
private Date validStartDate;
}
三、源码分析
1.⾸先我们看下FastJson最终格式化字段值的⽅法,JSONSerializer.writeWithFormat(Object object, String format)
public class JSONSerializer extends SerializeFilterable {
/**
* format就是@JSONField注解中指定的format值
* object就是需要格式化的变量
*/
public final void writeWithFormat(Object object, String format) {
if (object instanceof Date) {
//从当前类获取⼀个DateFormat,DateFormat就是⽤来格式化⽇期的类,再看看DateFormat();的实现
DateFormat dateFormat = DateFormat();
if (dateFormat == null) {
//只有当,当前类中的dateFormat为null时,才会使⽤JSONField注解中的format值初始化⼀个新的DateFormat
//那么我们可以肯定@JSONField注解没⽣效的原因就是,当前类中的dateFormat不为null
dateFormat = new SimpleDateFormat(format, locale);
dateFormat.setTimeZone(timeZone);
}
String text = dateFormat.format((Date) object);
out.writeString(text);
return;
}
if (object instanceof byte[]) {
byte[] bytes = (byte[]) object;
if ("gzip".equals(format) || "gzip,base64".equals(format)) {
GZIPOutputStream gzipOut = null;
try {z
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
if (bytes.length < 512) {
gzipOut = new GZIPOutputStream(byteOut, bytes.length);
} else {
gzipOut = new GZIPOutputStream(byteOut);
}
gzipOut.write(bytes);
gzipOut.finish();
out.ByteArray());
} catch (IOException ex) {
throw new JSONException("write gzipBytes error", ex);
} finally {
IOUtils.close(gzipOut);
}
} else if ("hex".equals(format)) {
out.writeHex(bytes);
} else {
out.writeByteArray(bytes);
}
return;
}
if (object instanceof Collection) {
Collection collection = (Collection) object;
Iterator iterator = collection.iterator();
out.write('[');
for (int i = 0; i < collection.size(); i++) {
Object item = ();
if (i != 0) {
out.write(',');
}
writeWithFormat(item, format);
}
out.write(']');
return;
}
write(object);
}
public DateFormat getDateFormat() {
if (dateFormat == null) {
if (dateFormatPattern != null) {
//第⼀次调⽤该⽅法时,dateformat为null,满⾜第⼀个if条件
//那么只有当dateFormatPattern有值时,才会初始化⼀个dateFormat对象,
//那么问题来了,dateFormatPattern值是从哪⾥来的呢,答案就是从我们的全局配置中来的,我们继续往下看
dateFormat = new SimpleDateFormat(dateFormatPattern, locale);
dateFormat.setTimeZone(timeZone);
}
}
return dateFormat;
}
}
2.其次,我们来看使⽤我们FastJson全局配置的地⽅,FastJsonHttpMessageConverter.writeInternal(Object object, HttpOutputMessage outputMessage);
public class FastJsonHttpMessageConverter extends AbstractHttpMessageConverter<Object>//
implements GenericHttpMessageConverter<Object> {
@Override
protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
ByteArrayOutputStream outnew = new ByteArrayOutputStream();
try {
HttpHeaders headers = Headers();
//获取全局配置的filter
SerializeFilter[] globalFilters = SerializeFilters();
List<SerializeFilter> allFilters = new ArrayList<SerializeFilter>(Arrays.asList(globalFilters));
boolean isJsonp = false;
//不知道为什么会有这⾏代码,但是为了保持和原来的⾏为⼀致,还是保留下来
Object value = strangeCodeForJackson(object);
if (value instanceof FastJsonContainer) {
FastJsonContainer fastJsonContainer = (FastJsonContainer) value;
PropertyPreFilters filters = Filters();
allFilters.Filters());
value = Value();
}
//revise 2017-10-23 ,
// 保持原有的MappingFastJsonValue对象的contentType不做修改保持旧版兼容。
// 但是新的JSONPObject将返回标准的contentType:application/javascript ,不对是否有function进⾏判断
if (value instanceof MappingFastJsonValue) {
if(!StringUtils.isEmpty(((MappingFastJsonValue) value).getJsonpFunction())){
isJsonp = true;
}
} else if (value instanceof JSONPObject) {
isJsonp = true;
}
//我们看这⾥,fastJsonConfig就是我们全局配置的配置类,
//DateFormat()获取的就是我们全局配置的时间格式yyyy-MM-dd HH:mm:ss,然后我们看看JSON.writeJSONString⽅法int len = JSON.writeJSONString(outnew, //
value, //
//SerializeFilters(), //
JSON.DEFAULT_GENERATE_FEATURE, //
if (isJsonp) {
headers.setContentType(APPLICATION_JAVASCRIPT);
}
if (fastJsonConfig.isWriteContentLength()) {
headers.setContentLength(len);
}
outnew.Body());
} catch (JSONException ex) {
throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex);
} finally {
outnew.close();
}
}
}
3.然后,我们看看初始化我们第1步说到类JSONSerializer的地⽅JSON.writeJSONString(....)
public abstract class JSON implements JSONStreamAware, JSONAware {
public static final int writeJSONString(OutputStream os, //
Charset charset, //
Object object, //
SerializeConfig config, //
SerializeFilter[] filters, //
String dateFormat, //
int defaultFeatures, //
< features) throws IOException {
SerializeWriter writer = new SerializeWriter(null, defaultFeatures, features);
try {
//看这⾥,就是⽤来初始化JSONSerializer对象
JSONSerializer serializer = new JSONSerializer(writer, config);java时间日期格式转换
if (dateFormat != null && dateFormat.length() != 0) {
//然后在这⾥,将全局配置的⽇期格式dateFormat,设置到JSONSerializer中的
//到这⾥我们就应该很清楚整个的逻辑了
serializer.setDateFormat(dateFormat);
}
if (filters != null) {
for (SerializeFilter filter : filters) {
serializer.addFilter(filter);
}
}
serializer.write(object);
int len = writer.writeToEx(os, charset);
return len;
} finally {
writer.close();
}
}
}
四、保留下分析源码抓取的调⽤栈,⽅便下次阅读源码
WebMvcMetricsFilter\doFilterInternal
WebMvcMetricsFilter\filterAndRecordMetrics
ApplicationFilterChain\internalDoFilter
WsFilter\doFilter
ApplicationFilterChain\doFilter
ApplicationFilterChain\internalDoFilter
FrameworkServlet\service
FrameworkServlet\doGet
FrameworkServlet\processRequest
DispatcherServlet\doService()
DispatcherServlet\doDispatch\mv = ha.handle(processedRequest, response, Handler()); AbstractHandlerMethodAdapter\handle(84)
RequestMappingHandlerAdapter\handleInternal(761)\mav = invokeHandlerMethod(request, response, handlerMethod); RequestMappingHandlerAdapter\invokeHandlerMethod(835)
ServletInvocableHandlerMethod\invokeAndHandle(99)
HandlerMethodReturnValueHandlerComposite\handleReturnValue(75)
RequestResponseBodyMethodProcessor\handleReturnValue(171)
AbstractMessageConverterMethodProcessor\genericConverter.write(outputValue, declaredType, selectedMediaType, outputMessage);(272) FastJsonHttpMessageConverter\super.write(o, contentType, outputMessage);(184)
AbstractHttpMessageConverter\writeInternal(t, outputMessage);(224)
FastJsonHttpMessageConverter\writeInternal(246)
**** JSON\writeJSONString(821)
===>
JSONSerializer\writeWithFieldName
===>
MapSerializer\write()
===>
JavaBeanSerializer\fieldSerializer.writeValue(serializer, propertyValue);
===>
FieldSerializer\serializer.writeWithFormat(propertyValue, format);
===>
**** JSONSerializer\public final void writeWithFormat(Object object, String format) {}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论