JSON parse error: default constructor not found. class java.time.YearMonth; nested exception is com.alibaba.fastjson.JSONException: default constructor not found. class java.time.YearMonth


java8新出的YearMonth可以方便的用來表示某個月。我的項目中使用springmvc來接收YearMonth類型的數據時發現 x-www-from-urlencoded 格式的數據可以使用"2018-12"的類型接收,但是在post請求中 接收application/json的數據時出現以下錯誤                                              

2020-02-18 11:18:25.284 WARN 16212 --- [nio-8090-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: default constructor not found. class java.time.YearMonth; nested exception is com.alibaba.fastjson.JSONException: default constructor not found. class java.time.YearMonth;

 

通過異常應該是YearMonth沒有公有構造函數 ,fastjson不支持解析YearMonth;案例使用fastjson作為了springmvc的序列化工具,類似如下的配置

@Configuration
public class MyConverter implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
        converters.add(0,fastJsonHttpMessageConverter);
    }
}

通過查看MonthYear確實發現其私有化了構造函數,只留了兩靜態方法

    private YearMonth(int year, int month) {
        this.year = year;
        this.month = month;
    }
    public static YearMonth of(int year, int month) {
        YEAR.checkValidValue(year);
        MONTH_OF_YEAR.checkValidValue(month);
        return new YearMonth(year, month);
    }
    private YearMonth with(int newYear, int newMonth) {
        if (year == newYear && month == newMonth) {
            return this;
        }
        return new YearMonth(newYear, newMonth);
    }

 

 

不過get請求時能獲取得到,說明jackson應該是對其有專門的處理工具的。將springmvc的序列化工具修改為默認的jackson,發現能 將application/json請求中 “2018-12”格式的數據  順利的反序列化YearMonth類型。然后通過查找發現jackson確實帶有YearMonth的序列化反序列化工具

 

 (看來springmvc將jackson作為默認序列化工具還是有原因的。。)

所以解決方法看來也找到了。就是使用默認的jackson作為序列化工具就可以解決了。

當然了,如果項目不好更改,想使用fastjson也有解決辦法。fastjson允許為字段定制反序列化工具,然后對應字段標明使用指定的反序列化類即可  (序列化原理類似)

public class YearMonthDeserializer implements ObjectDeserializer {
    @Override
    public YearMonth deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
        JSONLexer lexer = parser.getLexer();
        String s = lexer.stringVal();
        lexer.nextToken(16);
        return YearMonth.parse(s);
    }

    @Override
    public int getFastMatchToken() {
        return 0;
    }
}

  在需要反序列化的時候對需要的字段加上標注即可

public class AddVO {

    @JSONField(deserializeUsing = YearMonthDeserializer.class)
    private YearMonth yearMonth;

    public YearMonth getYearMonth() {
        return yearMonth;
    }

    public void setYearMonth(YearMonth yearMonth) {
        this.yearMonth = yearMonth;
    }
}

 

 

當然也可以全局處理,在我們配置fastjson作為httpMessageConverter的地方代碼改為如下即可

@Configuration
public class MyConverter implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = fastJsonHttpMessageConverter.getFastJsonConfig();
        fastJsonConfig.getParserConfig().putDeserializer( YearMonth.class,new YearMonthDeserializer());
        converters.add(0,fastJsonHttpMessageConverter);

    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM