[alibaba/fastjson]通过 FastJsonConfig 设置 DateFormat 时,不论设置什么值,只要属性类型为 LocalDateTime ,返回的都是 yyyy-MM-dd HH:mm:ss 格式

2024-09-06 335 views
5

fastjson测试版本:1.2.76 jdk版本:OracleJDK 16.0.1 测试代码:

class LocalDateTimeTest {

    @Data
    private class TestModel {
        private LocalDateTime createTime;
    }

    @Test
    void test() throws Exception {
        TestModel model = new TestModel();
        model.setCreateTime(LocalDateTime.now());

        FastJsonConfig config = new FastJsonConfig();

        config.setDateFormat("不论填写什么值都一样,哪怕就是这几个汉字");

        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        converter.setFastJsonConfig(config);

        converter.canRead(TestModel.class, MediaType.APPLICATION_JSON_UTF8);
        converter.canWrite(TestModel.class, MediaType.APPLICATION_JSON_UTF8);

        final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        HttpOutputMessage out = new HttpOutputMessage() {
            public HttpHeaders getHeaders() {
                return new HttpHeaders() {
                    private static final long serialVersionUID = 1L;

                    @Override
                    public MediaType getContentType() {
                        return MediaType.APPLICATION_JSON;
                    }
                };
            }

            public OutputStream getBody() throws IOException {
                return byteOut;
            }
        };

        converter.write(model, TestModel.class, MediaType.APPLICATION_JSON_UTF8, out);

        byte[] bytes = byteOut.toByteArray();
        String jsonString = new String(bytes, "UTF-8");

        System.out.println(jsonString);
    }
}

输出结果:

{"createTime":"2021-06-13 16:08:20"}

回答

9

这里个人感觉是当前fastJson版本的一个缺陷,对应LocalDateTime类型的处理器Jdk8DateCodec,当前并没有支持自定义日期格式,相关代码为: //Jdk8DateCodec 539行附近

if (format == null) { if ((features & mask) != 0 || serializer.isEnabled(SerializerFeature.UseISO8601DateFormat)) { format = formatter_iso8601_pattern; } else if (serializer.isEnabled(SerializerFeature.WriteDateUseDateFormat)) { format = JSON.DEFFAULT_DATE_FORMAT; //当前是走的这个分支,但是这里用默认格式而非识别你传递的类型 } else { int nano = dateTime.getNano(); if (nano == 0) { format = formatter_iso8601_pattern; } else if (nano % 1000000 == 0) { format = formatter_iso8601_pattern_23; } else { format = formatter_iso8601_pattern_29; } } }

解决方式: 1.如果你需要的格式恰好是上面代码里已支持的其他几个格式,可以考虑通过条件控制让代码走对应需要的分支(取巧)

2.如果一定需要自定义格式,可以考虑传递的过程用老的Date类型,Date类型能支持自定义格式(规避这个问题)

其他: 我后面尝试提交一个pr来修复一下这个问题,不过不太确定会否被采纳

8

多谢你的回复,我主要是提个issue,希望能够有个官方的解决方案,我目前是使用暴力解决,部分代码如下

// LocalDateTime 转时间戳
config.getSerializeConfig().put(LocalDateTime.class, (serializer, object, fieldName, fieldType, features) -> {
    if (object == null) {
        serializer.out.writeNull();
        return;
    }
    serializer.out.writeLong(((LocalDateTime) object).atZone(JSON.defaultTimeZone.toZoneId()).toInstant().toEpochMilli());
});
1

棒~,这种写法应该就相当于自定义类型的解析器~,这样对LocalDateTime解析时走你自定义的这个而不是现在不支持自定义的Jdk8DateCodec这个了~ (我之前还以为对于fastJson里定制处理的类型解析不能用这种自定义的写法覆盖,原来我之前理解错了~ 囧)