将 json 日期转换为 Jackson 的众多日期之一

Posted

技术标签:

【中文标题】将 json 日期转换为 Jackson 的众多日期之一【英文标题】:converting json date to one of many for Jackson 【发布时间】:2017-05-20 20:44:52 【问题描述】:

我有一个使用 jackson 的 spring boot 1.3.5 应用程序:

“com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.5.0”

我看到的问题是,当用户以不同于预期的格式 (mm/dd/yyyy) 输入值并执行 POST 时,我收到一个令人讨厌的错误返回到 UI(服务器日志中没有显示任何内容):

无法读取文档:无法解析文本“08-21-1999” 索引 2(通过参考链: com.xxx.yyy.MyDTO[\"firstofficevisit\"]);嵌套异常是 com.fasterxml.jackson.databind.JsonMappingException:文本'08-21-1999' 无法在索引 2 处解析(通过参考链: com.xxx.yyy.MyDTO[\"firstofficevisit\"])

这是在 dateOfBirth 工作但 firstofficevisit 抛出上述错误的地方提交的 json:


   "patientId":3,
   "dateOfBirth":"04/11/1984",
   "firstofficevisit":"08-21-1999",
   ...

我的 DTO 上有这个:

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "MM/dd/yyyy")
private LocalDate dateOfBirth;

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "MM/dd/yyyy")
private LocalDate firstofficevisit;

但是,除非提交日期完全一样,否则它会失败。我确实有一个很好的 Java 实用程序来处理日期转换,我想知道是否可以让我的 DTO 使用它:

public class DateUtil 

    private static final Map<String, String> DATE_FORMAT_REGEXPS = new HashMap<String, String>() 
        put("^\\d8$", "yyyyMMdd");
        put("^\\d1,2-\\d1,2-\\d4$", "dd-MM-yyyy");
        put("^\\d4-\\d1,2-\\d1,2$", "yyyy-MM-dd");
        put("^\\d1,2/\\d1,2/\\d4$", "MM/dd/yyyy");
        put("^\\d4/\\d1,2/\\d1,2$", "yyyy/MM/dd");
        put("^\\d1,2\\s[a-z]3\\s\\d4$", "dd MMM yyyy");
        put("^\\d1,2\\s[a-z]4,\\s\\d4$", "dd MMMM yyyy");
        put("^\\d12$", "yyyyMMddHHmm");
        put("^\\d8\\s\\d4$", "yyyyMMdd HHmm");
        put("^\\d1,2-\\d1,2-\\d4\\s\\d1,2:\\d2$", "dd-MM-yyyy HH:mm");
        put("^\\d4-\\d1,2-\\d1,2\\s\\d1,2:\\d2$", "yyyy-MM-dd HH:mm");
        put("^\\d1,2/\\d1,2/\\d4\\s\\d1,2:\\d2$", "MM/dd/yyyy HH:mm");
        put("^\\d4/\\d1,2/\\d1,2\\s\\d1,2:\\d2$", "yyyy/MM/dd HH:mm");
        put("^\\d1,2\\s[a-z]3\\s\\d4\\s\\d1,2:\\d2$", "dd MMM yyyy HH:mm");
        put("^\\d1,2\\s[a-z]4,\\s\\d4\\s\\d1,2:\\d2$", "dd MMMM yyyy HH:mm");
        put("^\\d14$", "yyyyMMddHHmmss");
        put("^\\d8\\s\\d6$", "yyyyMMdd HHmmss");
        put("^\\d1,2-\\d1,2-\\d4\\s\\d1,2:\\d2:\\d2$", "dd-MM-yyyy HH:mm:ss");
        put("^\\d4-\\d1,2-\\d1,2\\s\\d1,2:\\d2:\\d2$", "yyyy-MM-dd HH:mm:ss");
        put("^\\d1,2/\\d1,2/\\d4\\s\\d1,2:\\d2:\\d2$", "MM/dd/yyyy HH:mm:ss");
        put("^\\d4/\\d1,2/\\d1,2\\s\\d1,2:\\d2:\\d2$", "yyyy/MM/dd HH:mm:ss");
        put("^\\d1,2\\s[a-z]3\\s\\d4\\s\\d1,2:\\d2:\\d2$", "dd MMM yyyy HH:mm:ss");
        put("^\\d1,2\\s[a-z]4,\\s\\d4\\s\\d1,2:\\d2:\\d2$", "dd MMMM yyyy HH:mm:ss");
    ;

我的问题是日期以字符串形式出现,并且尝试验证每个排列的有效性和格式充其量是笨拙的,特别是因为我有许多需要这个的日期字段。

所以我不确定最好的方法 - 是否有可能让杰克逊对我的 DateUtil.java 更加宽容(以及如何连接它!)或者有没有办法在客户端强制执行此操作,哪里看起来更自然?您可以分享的任何示例都会有所帮助

【问题讨论】:

【参考方案1】:

无法自动解析任何格式的日期。您将不得不以某种方式在某处列出您想要以特定顺序处理的所有格式。或者如果可能的话,在前端强制执行特定格式。您不必将 json 作为文本进行预处理来解析它。

我知道使用 Java 8 和 Jackson 处理多种日期格式的最简单方法是使用自定义 JsonDeserializer 和多种可选模式。例如

class LocalDateParser extends JsonDeserializer<LocalDate> 

    private final DateTimeFormatter dateFormatter = new DateTimeFormatterBuilder()
            .appendOptional(DateTimeFormatter.ofPattern("MM-dd-yyyy"))
            .appendOptional(DateTimeFormatter.ofPattern("MM/dd/yyyy"))
            .toFormatter();

    @Override
    public LocalDate deserialize(JsonParser jsonparser, DeserializationContext context) throws IOException 
        return LocalDate.parse(jsonparser.getText(), dateFormatter);
    

并像这样注释您的字段:

@JsonDeserialize(using = LocalDateParser.class)
public LocalDate firstofficevisit;

【讨论】:

以上是关于将 json 日期转换为 Jackson 的众多日期之一的主要内容,如果未能解决你的问题,请参考以下文章

Jackson JSON对日期格式的解析设置

使用Jackson时转换JSON时,日期格式设置

Spring boot + Jackson - 始终将日期转换为 UTC

使用 Jackson 将 protobuf 转换为 JSON?

使用 Jackson 将 Map 转换为 JSON

使用Jackson时转换JSON时,日期格式设置