【源碼分析】FastJson全局配置日期格式致使@JSONField(format = "yyyy-MM-dd")註解失效

出現的問題javascript

我全局配置的時間格式是:yyyy-MM-dd HH:mm:ssjava

@JSONField註解配置的時間格式是:yyyy-MM-ddapp

最終的返回結果是:yyyy-MM-dd HH:mm:sside

問題:爲啥不是以註解定義的時間格式爲主呢?

先說答案,後面再分析:
源碼分析

FastJson的全局配置日期格式會致使@JSONField註解失效this

使用建議:spa

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

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

 

1、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);
    }
}

 

2、使用@JSONField註解的Java Bean代碼以下

@Data
public class UserCardInfoResponseModel {

    @JSONField(format = "yyyy-MM-dd") private Date validStartDate;

}

 

3、源碼分析

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(); } } }

 

4、保留下分析源碼抓取的調用棧,方便下次閱讀源碼

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, 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) {}
相關文章
相關標籤/搜索