分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 技术分享

源码分析之FastJson全局配置日期格式导致@JSONField(format = "yyyy-MM-dd")注解失效

发布时间:2023-09-06 02:31责任编辑:顾先生关键词:配置

出现的问题

我全局配置的时间格式是:yyyy-MM-dd HH:mm:ss

@JSONField注解配置的时间格式是:yyyy-MM-dd

最终的返回结果是:yyyy-MM-dd HH:mm:ss

问题:为啥不是以注解定义的时间格式为主呢?

先说答案,后面再分析:

FastJson的全局配置日期格式会导致@JSONField注解失效

使用建议:

1.若全局配置了日期格式,就不要使用@JSONField注解

2.若想使用@JSONField注解,就不要全局配置日期格式

一、FastJson全局配置代码如下

@Configurationpublic 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代码如下

@Datapublic 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就是用来格式化日期的类,再看看this.getDateFormat();的实现  ???????????DateFormat dateFormat = this.getDateFormat(); ???????????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.writeByteArray(byteOut.toByteArray()); ???????????????} 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 = iterator.next(); ???????????????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 = outputMessage.getHeaders(); ???????????//获取全局配置的filter ???????????SerializeFilter[] globalFilters = fastJsonConfig.getSerializeFilters(); ???????????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 = fastJsonContainer.getFilters(); ???????????????allFilters.addAll(filters.getFilters()); ???????????????value = fastJsonContainer.getValue(); ???????????} ???????????//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就是我们全局配置的配置类,
       //fastJsonConfig.getDateFormat()获取的就是我们全局配置的时间格式yyyy-MM-dd HH:mm:ss,然后我们看看JSON.writeJSONString方法 ???????????int len = JSON.writeJSONString(outnew, // ???????????????????fastJsonConfig.getCharset(), // ???????????????????value, // ???????????????????fastJsonConfig.getSerializeConfig(), // ???????????????????//fastJsonConfig.getSerializeFilters(), // ???????????????????allFilters.toArray(new SerializeFilter[allFilters.size()]), ???????????????????fastJsonConfig.getDateFormat(), // ???????????????????JSON.DEFAULT_GENERATE_FEATURE, // ???????????????????fastJsonConfig.getSerializerFeatures()); ???????????if (isJsonp) { ???????????????headers.setContentType(APPLICATION_JAVASCRIPT); ???????????} ???????????if (fastJsonConfig.isWriteContentLength()) { ???????????????headers.setContentLength(len); ???????????} ???????????outnew.writeTo(outputMessage.getBody()); ???????} 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, // ????????????????????????????????????????????SerializerFeature... features) throws IOException { ???????SerializeWriter writer = new SerializeWriter(null, defaultFeatures, features); ???????try {
      //看这里,就是用来初始化JSONSerializer对象 ???????????JSONSerializer serializer = new JSONSerializer(writer, config); ???????????????????????if (dateFormat != null && dateFormat.length() != 0) {
       //然后在这里,将全局配置的日期格式dateFormat,设置到JSONSerializer中的
       //到这里我们就应该很清楚整个的逻辑了 ???????????????serializer.setDateFormat(dateFormat); ???????????????serializer.config(SerializerFeature.WriteDateUseDateFormat, true); ???????????} ???????????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\doFilterInternalWebMvcMetricsFilter\filterAndRecordMetricsApplicationFilterChain\internalDoFilterWsFilter\doFilterApplicationFilterChain\doFilterApplicationFilterChain\internalDoFilterFrameworkServlet\serviceFrameworkServlet\doGetFrameworkServlet\processRequestDispatcherServlet\doService()DispatcherServlet\doDispatch\mv = ha.handle(processedRequest, response, mappedHandler.getHandler());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) {}

源码分析之FastJson全局配置日期格式导致@JSONField(format = "yyyy-MM-dd")注解失效

原文地址:https://www.cnblogs.com/756623607-zhang/p/10312178.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved