【问题标题】:Throw custom exception while deserializing the Date field using jackson in java在java中使用jackson反序列化日期字段时抛出自定义异常
【发布时间】:2019-08-08 03:20:24
【问题描述】:

DTO:

@Getter
@Setter
@ToString
public class TestDto {

    @NotNull
    private String id;

    @NotNull
    @DateTimeFormat(pattern = "YYYY-MM-DD'T'hh:mm:ss.SSSZ")
    private Instant timestamp;
}

当我给出这个输入时

{"timestamp":"4/23/2018 11:32 PM","id":"132"}

它给出了 BAD_REQUEST(它应该),但我想处理这个格式错误的日期并用我的自定义异常抛出一个异常。

如何添加?

【问题讨论】:

  • 该模式不是一个有效的模式,即使它是,它显然与 JSON 中的日期字符串不匹配。此外, DateTimeFormat 对杰克逊解析日期的说法完全没有影响。这不是 Jackson 注释。
  • 是的,我知道它不匹配。我想为这种无效日期抛出一个自定义异常。
  • 你的意思是像自定义异常这样的 try and catch 块?
  • 啊,对不起,我看错了。 AFAIK,你不能。 Jackson 解析时抛出 Jackson 异常。
  • 如何为这种情况设置另一种状态 - 当输入格式错误时?

标签: java spring-boot jackson


【解决方案1】:

由于尚不支持 OP 请求的功能:https://github.com/FasterXML/jackson-annotations/issues/130

通过对字段 timestamp 使用自定义反序列化器尝试用更长的方法做同样的事情

自定义异常类:

import com.fasterxml.jackson.core.JsonProcessingException;

public class MyException extends JsonProcessingException {
    public MyException(String message) {
        super(message);
    }
}

自定义反序列化器类:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Date;
public class InstantDeserializer extends StdDeserializer<Instant> {

public InstantDeserializer() {
    this(null); 
} 

public InstantDeserializer(Class<?> vc) {
    super(vc); 
}

private SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-DD'T'hh:mm:ss.SSS'Z'");

@Override
public Instant deserialize(JsonParser jp, DeserializationContext ctxt)
  throws IOException, JsonProcessingException {
    JsonNode node = jp.getCodec().readTree(jp);
    Date date = null;
    try {
        date = sdf.parse(node.asText());
    } catch (Exception e) {
        throw new MyException("Instant field deserialization failed");
    }
    return date.toInstant();
}
}

更新了 TestDto 类:

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;

import javax.validation.constraints.NotNull;
import java.time.Instant;

@Getter
@Setter
@ToString
public class TestDto {

    @NotNull
    private String id;

    @NotNull
    @JsonDeserialize(using = InstantDeserializer.class)
    @DateTimeFormat(pattern = "YYYY-MM-DD'T'hh:mm:ss.SSS'Z'")
    private Instant timestamp;
}

输入请求无效:

{"timestamp":"4/23/2018 11:32 PM","id":"132"}

回复:

{
    "timestamp": 1552845180271,
    "status": 400,
    "error": "Bad Request",
    "message": "JSON parse error: Instant field deserialization failed; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Instant field deserialization failed (through reference chain: TestDto[\"timestamp\"])"
}

有效的输入请求:

{"timestamp":"2018-04-23T11:32:22.213Z","id":"132"}

回复:

{
    "id": "132",
    "timestamp": {
        "epochSecond": 1514700142,
        "nano": 213000000
    }
}

如果您不喜欢时间戳字段反序列化的方式并想更改它,this SO 帖子会有所帮助。

【讨论】:

  • 非常感谢! SimpleDateFormat 还有其他替代方法吗?同样,当您返回 Instant.now() 时,这是否会将值设置为该字段?
  • 它也会抛出一个有效日期的异常:2019-03-17T16:51:51.304Z
  • 您使用的 Pattern 有问题,请检查更新的答案
  • 你给的链接,objectMapper在哪里注册的?
  • 由于某些原因,我无法理解为什么,序列化程序停止抛出异常(也尝试过 RuntimeException)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-08
  • 1970-01-01
  • 1970-01-01
  • 2016-02-12
  • 2023-04-01
  • 1970-01-01
相关资源
最近更新 更多