使用 LocalDateTime 字段将 JSON 反序列化为对象

Lis*_*sek 1 java json jackson

我要放弃了。我已经浏览了所有可能的 SO 页面,但我无法让它工作。

我有一个ConfigKeyVal这样的课程:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class ConfigKeyValue {

    private String name;
    private NssConfigDto value;
}
Run Code Online (Sandbox Code Playgroud)

Config类如下所示:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class Config {

    private String name;
    private String source;
    private String destination;
    private int cycle;
    private LocalDateTime fixedTime;
    private LocalDateTime submitDate;
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试将ConfigKeyVal(顶部的)对象的JSON 数组直接反序列化到我的 ArrayList 中。

public class ConfigKeyValueList extends ArrayList<ConfigKeyValue> {
    public ConfigKeyValueList() {
        super();
    }
}
Run Code Online (Sandbox Code Playgroud)

像这样:

final Data values = result.results().get("attributes"); // this is an array of ConfigKeyValue objects
ObjectMapper mapper = new ObjectMapper();
ConfigKeyValueList configKeyValueList = new ConfigKeyValueList();
try {
    configKeyValueList = mapper.readValue(values.asText(), ConfigKeyValueList.class);
} catch (IOException e) {
    e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)

我试过使用,mapper.registerModule(new JavaTimeModule());但这没有帮助。我是否必须为此编写自己的解串器,或者是否有有效的工具而我做错了?

我得到的错误是: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of java.time.LocalDateTime: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?))

我在我的 gradle 文件中使用这些 jackson 依赖项:

compile group: 'com.fasterxml.jackson.module', name: 'jackson-module-parameter-names', version: '2.9.6'
compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jdk8', version: '2.9.6'
compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.9.6'
Run Code Online (Sandbox Code Playgroud)

编辑:这就是 JSON 的样子

[
    {
        "name": "kek1",
        "value": {
            "name": "kek1",
            "source": "source",
            "destination": "dest",
            "cycle": 1,
            "fixedTime": {
                "year": 2017,
                "month": "APRIL",
                "dayOfYear": 95,
                "dayOfWeek": "WEDNESDAY",
                "dayOfMonth": 5,
                "monthValue": 4,
                "hour": 4,
                "minute": 20,
                "second": 0,
                "nano": 0,
                "chronology": {
                    "id": "ISO",
                    "calendarType": "iso8601"
                }
            },
            "submitDate": {
                "year": 2017,
                "month": "APRIL",
                "dayOfYear": 95,
                "dayOfWeek": "WEDNESDAY",
                "dayOfMonth": 5,
                "monthValue": 4,
                "hour": 4,
                "minute": 20,
                "second": 0,
                "nano": 0,
                "chronology": {
                    "id": "ISO",
                    "calendarType": "iso8601"
                }
            }
        }
    },
    {
        "name": "kek2",
        "value": {
            "name": "kek2",
            "source": "source",
            "destination": "dest",
            "cycle": 1,
            "fixedTime": {
                "year": 2017,
                "month": "APRIL",
                "dayOfYear": 93,
                "dayOfWeek": "MONDAY",
                "dayOfMonth": 3,
                "monthValue": 4,
                "hour": 5,
                "minute": 10,
                "second": 0,
                "nano": 0,
                "chronology": {
                    "id": "ISO",
                    "calendarType": "iso8601"
                }
            },
            "submitDate": {
                "year": 2017,
                "month": "APRIL",
                "dayOfYear": 93,
                "dayOfWeek": "MONDAY",
                "dayOfMonth": 3,
                "monthValue": 4,
                "hour": 5,
                "minute": 10,
                "second": 0,
                "nano": 0,
                "chronology": {
                    "id": "ISO",
                    "calendarType": "iso8601"
                }
            }
        }
    }
]
Run Code Online (Sandbox Code Playgroud)

cas*_*lin 5

首先,我不建议像这样序列化日期。我强烈建议您遵守标准并使用ISO 8601,该标准得到RFC 3339xkcd 1179 的认可:

xkcd 1179:ISO 8601


如果您可以控制 JSON 序列化

如果您使用Spring Data MongoDB,您可以使用它MongoCustomConversions来处理来自DateLocalDateTime为您的转换:

@Configuration
public class MongoConfiguration {

    @Bean
    public MongoCustomConversions customConversions() {
        List<Converter<?, ?>> converters = new ArrayList<>();
        converters.add(new DateToLocalDateTimeConverter());
        converters.add(new LocalDateTimeToDateConverter());
        return new MongoCustomConversions(converters);
    }

    class DateToLocalDateTimeConverter implements Converter<Date, LocalDateTime> {

        @Override
        public LocalDateTime convert(Date source) {
            return source == null ? null : 
                LocalDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault());
        }
    }

    class LocalDateTimeToDateConverter implements Converter<LocalDateTime, Date> {

        @Override
        public Date convert(LocalDateTime source) {
            return source == null ? null : Date.from(source.toInstant());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以LocalDateTime在你的 bean 中使用你的,让 Jackson 和JavaTimeModule处理序列化/反序列化:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

// Serialize
List<ConfigKeyValue> list = null;
String json = mapper.writeValueAsString(list);

// Deserialize
TypeReference<List<ConfigKeyValue>> typeRef = new TypeReference<>() {};
list = mapper.readValue(json, typeRef);
Run Code Online (Sandbox Code Playgroud)

用你拥有的东西工作

如果您无法控制 JSON,那么您将需要一个自定义的 deserializer。实现可以是这样的:

public class CustomLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

    @Override
    public LocalDateTime deserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException {

        JsonNode tree = jp.getCodec().readTree(jp);
        int year = tree.get("year").asInt();
        int month = tree.get("monthValue").asInt();
        int dayOfMonth = tree.get("dayOfMonth").asInt();
        int hour = tree.get("hour").asInt();
        int minute = tree.get("minute").asInt();
        int second = tree.get("second").asInt();
        int nano = tree.get("nano").asInt();

        return LocalDateTime.of(year, month, dayOfMonth, hour, minute, second, nano);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后注释您的字段以使用上面定义的反序列化器:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class Config {

    // Other fields

    @JsonDeserialize(using = CustomLocalDateTimeDeserializer.class)
    private LocalDateTime fixedTime;

    @JsonDeserialize(using = CustomLocalDateTimeDeserializer.class)
    private LocalDateTime submitDate;
}
Run Code Online (Sandbox Code Playgroud)

最后解析你的 JSON 文档:

ObjectMapper mapper = new ObjectMapper();

TypeReference<List<ConfigKeyValue>> typeRef = new TypeReference<>() {};
List<ConfigKeyValue> list = mapper.readValue(json, typeRef);
Run Code Online (Sandbox Code Playgroud)