2017年9月27日 星期三

Jackson @JsonFormat.lenient Date validate

前幾天遇到了Jackson convert String to Date 的問題,因為字串轉日期預設是寬容的 ( lenient = true ),所以會在盡量不出錯 ( ParseException ) 的狀況下容錯,但這樣卻會造成資料內容錯誤,例如:輸入字串 "2017-02-29",會輸出 Wed Mar 01 00:00:00 CST 2017

先介紹一下專案環境

  • Jersey2. RESTful Web Service.
  • Swagger. Autogenerate Document.
  • Gradle. Build, Test, Dependent management

build.gralde

compile group: 'org.glassfish.jersey.containers', name: 'jersey-container-servlet-core', version: '2.25.1'
compile group: 'org.glassfish.jersey.ext', name: 'jersey-spring3', version: '2.25.1'
compile group: 'org.glassfish.jersey.media', name: 'jersey-media-json-jackson', version: '2.25.1'
compile group: 'io.swagger', name: 'swagger-core', version: '1.5.13'
compile group: 'io.swagger', name: 'swagger-jersey2-jaxrs', version: '1.5.13'

Solution

@JsonFormat(lenient = false)

可以參考 這裡,簡單來說,這個問題在 2016/11/4 就已經有人提 Issue 出來,並在同年 11/16 就已加入 2.9 版;只要將 jackson-annotations:2.8.5 升級至 2.9.0,@JsonFormat annotation 即可設定 lenient attribute。
但這裡遇到個問題,可以參考 這裡,升版後,會出現以下錯誤;因為 Swagger-core 1.5.13 depends on Jackson 2.8.5. 但 2.9.0 的某個 Method 被拿掉了。(這個問題後來在 Jackson 2.9.1 修復了)
java.lang.NoSuchMethodError: com.fasterxml.jackson.databind.introspect.AnnotatedMember.annotations()Ljava/lang/Iterable;

@JsonDeserialize(using = DateDeserializer.class)

後來考慮到 Jackson 2.9.x 穩定性問題,怕又會有什麼奇怪的錯誤,所以在不升版的情況下,繼承 JsonDeserializer 實作 Date 型態的反序列化,範例如下:
public class DateDeserializer extends JsonDeserializer {

    @Override
    public Date deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        sdf.setLenient(false);
        String text = parser.getText();
        try {
            Date date = sdf.parse(text);
            return date;
        } catch (ParseException e) {
            throw new RuntimeException("Date Parse 錯誤! 請檢查格式與合法性");
        }
    }

}

沒有留言:

張貼留言