最近在公司接到了多时区改造的一个需求,对于只显示年月日时分秒的变量,类型我定义成了LocalDate,在编写单元测试类的时候发现了一个大坑:
在经过我自测没有任何问题的入参,使用mockmvc测试后,得到的返回结果却是400 - bad request.
通过查看日志,发现是birthday转JSON的时候出了问题。
JSON parse error: Expected array or string.; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Expected array or string.
at [Source: (PushbackInputStream); line: 1, column: 302] (through reference chain: com.xxx.xxx.xxx.web.request.v1.policy.PolicyIssueV1Request["policyHolder"]->com.xxx.xxx.xxx.web.request.v1.policy.PolicyHolderDetailsV1Request["birthday"])
通过debug解析转义出来的json,发现定义为LocalDate类型的变量,被解析为了一串对象:
"birthday": {
"year": 2021,
"month": "MAY",
"monthValue": 5,
"dayOfMonth": 1,
"era": "CE",
"dayOfYear": 121,
"dayOfWeek": "SATURDAY",
"leapYear": false,
"chronology": {
"id": "ISO",
"calendarType": "iso8601"
}
}
我使用的将对象转换为json的方法是:
可是明明非测试类是能跑通的,并且spring解析的时候底层也是用的ObjectMapper,这就很奇怪了。。。
原因在于,在测试类中new出来的ObjectMapper,是不由spring管理的。。。(若未设置jackson.date-format,spring默认的date-format格式:yyyy-MM-dd'T'HH:mm:ss.SSSXXX)
解决方案如下:
(1)将LocalDate类型的对象加上@JsonFormat,这里有个前提,new 出来的objectMapper必须与 @JsonFormat 的包路径相同!
👆上面的ObjectMapper是jackson 2.x中提供的,而下面的ObjectMapper是由jackson 1.9提供的
(2)对new出来的objectMapper设置格式
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
(3)改为
JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect);