Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG]Fastjson2 替代SpringWeb 默认的 jackson 后,如果接口返回值类中有 LocalDate 类型的日期字段无法解析 #416

Closed
29794 opened this issue Jun 6, 2022 · 5 comments
Labels
bug Something isn't working
Milestone

Comments

@29794
Copy link

29794 commented Jun 6, 2022

问题描述

Fastjson2 替换 SpringWeb 默认的 jackson 后,如果接口返回值类中有 LocalDate 类型的日期字段无法解析,默认使用了类 com.alibaba.fastjson2.support.config 下的 dateFormat 字段的默认值 yyyy-MM-dd HH:mm:ss 进行日期的格式化

环境信息

请填写以下信息:

  • OS信息:[Windows10 家庭版 Version 21H2 4Core 3.60GHz 16 GB]
  • JDK信息: [Openjdk 1.8.0_321]
  • 版本信息:[Fastjson2 2.0.6]

重现步骤

如何操作可以重现该问题:

  1. 使用 SpringBoot2.6.2 集成 Fastjson2.0.6
  2. 编写一个GET接口,接口返回值为 一个 LocalDate 字段或者一个带有该类型属性的类
  3. 访问该接口是报错 2022-06-06 15:34:54.633 [http-nio-8099-exec-4] ERROR com.medbook.config.ExceptionHandleAdvice - err ==> Could not write JSON: FASTJSON-2.0.6 write JSON errorUnsupported field: HourOfDay; nested exception is com.alibaba.fastjson2.JSONException: FASTJSON-2.0.6 write JSON errorUnsupported field: HourOfDay
    @GetMapping("/testy")
    public ResponseWrapper testWriteLocalDate(){
        return ResponseWrapper.success(LocalDate.now());
    }
    /**
     * Fastjson 配置
     */
    @Bean
    public HttpMessageConverters fastJsonHttpMessageConverters() {
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat,
                SerializerFeature.WriteNullStringAsEmpty,
                SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteMapNullValue);
        List<MediaType> fastMediaTypes = new ArrayList<>();
        fastMediaTypes.add(MediaType.APPLICATION_JSON);
        fastConverter.setSupportedMediaTypes(fastMediaTypes);
        fastConverter.setFastJsonConfig(fastJsonConfig);
        return new HttpMessageConverters(fastConverter);
    }

期待的正确结果

期望获得如 “2022-04-25” 的日期字符串

相关日志输出

2022-06-06 15:34:54.633 [http-nio-8099-exec-4] ERROR com.medbook.config.ExceptionHandleAdvice - err ==> Could not write JSON: FASTJSON-2.0.6 write JSON errorUnsupported field: HourOfDay; nested exception is com.alibaba.fastjson2.JSONException: FASTJSON-2.0.6 write JSON errorUnsupported field: HourOfDay
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: FASTJSON-2.0.6 write JSON errorUnsupported field: HourOfDay; nested exception is com.alibaba.fastjson2.JSONException: FASTJSON-2.0.6 write JSON errorUnsupported field: HourOfDay
at com.alibaba.fastjson2.support.spring.http.converter.FastJsonHttpMessageConverter.writeInternal(FastJsonHttpMessageConverter.java:136)
at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:227)
at com.alibaba.fastjson2.support.spring.http.converter.FastJsonHttpMessageConverter.write(FastJsonHttpMessageConverter.java:83)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:290)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:183)
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:78)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:135)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:655)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at com.medbook.research.filter.CrosFilter.doFilter(CrosFilter.java:26)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:124)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
at org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:97)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:41002)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:750)
Caused by: com.alibaba.fastjson2.JSONException: FASTJSON-2.0.6 write JSON errorUnsupported field: HourOfDay
at com.alibaba.fastjson2.JSON.writeTo(JSON.java:1970)
at com.alibaba.fastjson2.support.spring.http.converter.FastJsonHttpMessageConverter.writeInternal(FastJsonHttpMessageConverter.java:127)
... 60 common frames omitted
Caused by: java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: HourOfDay
at java.time.LocalDate.get0(LocalDate.java:680)
at java.time.LocalDate.getLong(LocalDate.java:659)
at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
at java.time.format.DateTimeFormatterBuilder$NumberPrinterParser.format(DateTimeFormatterBuilder.java:2551)
at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2190)
at java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1746)
at java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1720)
at com.alibaba.fastjson2.writer.ObjectWriterImplLocalDate.write(ObjectWriterImplLocalDate.java:88)
at com.alibaba.fastjson2.writer.ObjectWriter_8.write(Unknown Source)
at com.alibaba.fastjson2.writer.FieldWriterList.writeList(FieldWriterList.java:172)
at com.alibaba.fastjson2.writer.ObjectWriter_7.write(Unknown Source)
at com.alibaba.fastjson2.writer.ObjectWriter_2.write(Unknown Source)
at com.alibaba.fastjson2.JSON.writeTo(JSON.java:1965)
... 61 common frames omitted

附加信息

如果返回值是一个多字段的类,对于 LocalDate 字段,使用了 @JSONField(format = "yyyy-MM-dd") 注解,则有如下报错:
2022-06-06 15:44:16.287 [http-nio-8099-exec-1] ERROR com.medbook.config.ExceptionHandleAdvice - err ==> Could not write JSON: FASTJSON-2.0.6 write JSON errornull; nested exception is com.alibaba.fastjson2.JSONException: FASTJSON-2.0.6 write JSON errornull
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: FASTJSON-2.0.6 write JSON errornull; nested exception is com.alibaba.fastjson2.JSONException: FASTJSON-2.0.6 write JSON errornull
at com.alibaba.fastjson2.support.spring.http.converter.FastJsonHttpMessageConverter.writeInternal(FastJsonHttpMessageConverter.java:136)
at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:227)
at com.alibaba.fastjson2.support.spring.http.converter.FastJsonHttpMessageConverter.write(FastJsonHttpMessageConverter.java:83)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:290)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:183)
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:78)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:135)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:655)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at com.medbook.research.filter.CrosFilter.doFilter(CrosFilter.java:26)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:124)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
at org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:97)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:41002)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:750)
Caused by: com.alibaba.fastjson2.JSONException: FASTJSON-2.0.6 write JSON errornull
at com.alibaba.fastjson2.JSON.writeTo(JSON.java:1970)
at com.alibaba.fastjson2.support.spring.http.converter.FastJsonHttpMessageConverter.writeInternal(FastJsonHttpMessageConverter.java:127)
... 60 common frames omitted
Caused by: java.lang.UnsupportedOperationException: null
at com.alibaba.fastjson2.JSONWriter.writeRaw(JSONWriter.java:557)
at com.alibaba.fastjson2.JSONWriterPretty.writeRaw(JSONWriterPretty.java:133)
at com.alibaba.fastjson2.JSONWriter.writeString(JSONWriter.java:869)
at com.alibaba.fastjson2.JSONWriter.writeDateYYYMMDD10(JSONWriter.java:1271)
at com.alibaba.fastjson2.writer.ObjectWriterImplLocalDate.write(ObjectWriterImplLocalDate.java:60)
at com.alibaba.fastjson2.writer.ObjectWriter_2.write(Unknown Source)
at com.alibaba.fastjson2.writer.ObjectWriter_1.write(Unknown Source)
at com.alibaba.fastjson2.JSON.writeTo(JSON.java:1965)
... 61 common frames omitted

@29794 29794 added the bug Something isn't working label Jun 6, 2022
@29794 29794 changed the title [BUG]Fastjson2 替代SpringWeb 默认的 Jackson [BUG]Fastjson2 替代SpringWeb 默认的 jackson 后,如果接口返回值类中有 LocalDate 类型的日期字段无法解析 Jun 6, 2022
@29794 29794 changed the title [BUG]Fastjson2 替代SpringWeb 默认的 jackson 后,如果接口返回值类中有 LocalDate 类型的日期字段无法解析 [question]Fastjson2 替代SpringWeb 默认的 jackson 后,如果接口返回值类中有 LocalDate 类型的日期字段无法解析 Jun 6, 2022
@29794 29794 changed the title [question]Fastjson2 替代SpringWeb 默认的 jackson 后,如果接口返回值类中有 LocalDate 类型的日期字段无法解析 [BUG]Fastjson2 替代SpringWeb 默认的 jackson 后,如果接口返回值类中有 LocalDate 类型的日期字段无法解析 Jun 6, 2022
@29794
Copy link
Author

29794 commented Jun 6, 2022

可以在 FastJSONConfig 中设置 fastJsonConfig.setDateFormat("yyyy-MM-dd") 来覆盖默认格式化的格式,但是由于还存在 LocalDateTime 类型的字段,格式化后还是会缺失了时分秒的数据

@VictorZeng
Copy link
Collaborator

@ly-az 可以使用 @JSONField 对不同字段指定format格式

@JSONField(format = "yyyy-MM-dd")
private LocalDate localDate;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime localDateTime;

@yangcanlin
Copy link

修复LocalDate使用dateFormat'yyyy-MM-dd HH:mm:ss'报错的问题 #363

2.0.5版本已经修复
我是这样实现的

JSON.register(LocalDateTime.class, MyLocalDateTimeWriter.instance); //实现代码类似第二行
JSON.register(LocalDate.class, MyLocalDateWriter.instance); //下面有实现代码
JSON.register(LocalTime.class, MyLocalTimeWriter.instance); //实现代码类似第二行

class MyLocalDateWriter implements ObjectWriter<LocalDate> {
    static MyLocalDateWriter instance = new MyLocalDateWriter();
    
    @Override
    public void write(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
        if (object == null) {
            jsonWriter.writeNull();
            return;
        }
        LocalDate date = (LocalDate) object;
        // LocalDate date = dateTime.toLocalDate();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String format = formatter.format(date);
        // 优先使用name
        jsonWriter.writeString(format);
    }
}

@wenshao wenshao added this to the 2.0.7 milestone Jun 7, 2022
@wenshao
Copy link
Member

wenshao commented Jun 7, 2022

@wenshao
Copy link
Member

wenshao commented Jun 11, 2022

https://github.com/alibaba/fastjson2/releases/tag/2.0.7
问题已经修复,请用新版本

@wenshao wenshao closed this as completed Jun 11, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants