首页 文章

使用Jackson JSON映射器序列化/反序列化java 8 java.time

提问于
浏览
161

如何在Java 8 LocalDateTime中使用Jackson JSON映射器?

org.codehaus.jackson.map.JsonMappingException:无法从JSON String实例化类型[simple type,class java.time.LocalDateTime]的值;没有单字符串构造函数/工厂方法(通过引用链:MyDTO [“field1”] - > SubDTO [“date”])

10 回答

  • 184

    这里不需要使用自定义序列化器/反序列化器 . 使用jackson-modules-java8's datetime module

    数据类型模块使Jackson识别Java 8 Date&Time API数据类型(JSR-310) .

    This module adds support for quite a few classes:

    • 持续时间

    • 瞬发

    • LocalDateTime

    • LocalDate

    • LocalTime

    • 月日

    • OffsetDateTime

    • 偏移时间

    • 期间

    • YearMonth

    • ZonedDateTime

    • ZoneId

    • ZoneOffset

  • 0

    更新:出于历史原因留下这个答案,但我不推荐它 . 请参阅上面接受的答案 .

    告诉Jackson使用您的自定义[de]序列化类进行映射:

    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    private LocalDateTime ignoreUntil;
    

    提供自定义类:

    public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
        @Override
        public void serialize(LocalDateTime arg0, JsonGenerator arg1, SerializerProvider arg2) throws IOException, JsonProcessingException {
            arg1.writeString(arg0.toString());
        }
    }
    
    public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
        @Override
        public LocalDateTime deserialize(JsonParser arg0, DeserializationContext arg1) throws IOException, JsonProcessingException {
            return LocalDateTime.parse(arg0.getText());
        }
    }
    

    随机事实:如果我在类之上嵌套并且不使它们成为静态,则错误消息很奇怪: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=UTF-8' not supported

  • 0

    这个maven依赖将解决您的问题:

    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>2.6.5</version>
    </dependency>
    

    我一直在努力的一件事是,在反序列化期间,ZonedDateTime时区被更改为GMT . 事实证明,默认情况下, Jackson 用上下文中的一个替换它 . 为了保持区域1必须禁用此“功能”

    Jackson2ObjectMapperBuilder.json()
        .featuresToDisable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
    
  • 53

    如果您使用的是fastxml的ObjectMapper类,默认情况下ObjectMapper不了解LocalDateTime类,因此,您需要在gradle / maven中添加另一个依赖项:

    compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.7.3'
    

    现在,您需要将此库提供的数据类型支持注册到objectmapper对象,这可以通过以下方式完成:

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.findAndRegisterModules();
    

    现在,在您的jsonString中,您可以轻松地将java.LocalDateTime字段设置如下:

    {
        "user_id": 1,
        "score": 9,
        "date_time": "2016-05-28T17:39:44.937"
    }
    

    通过这一切,您的Json文件到Java对象转换将正常工作,您可以通过以下方式读取该文件:

    objectMapper.readValue(jsonString, new TypeReference<List<User>>() {
                });
    
  • 0

    使用 Spring boot 时遇到了类似的问题 . 使用Spring引导1.5.1.RELEASE我所要做的就是添加依赖:

    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
    </dependency>
    
  • 34

    如果您正在使用Jersey,那么您需要像其他人建议的那样添加Maven依赖项(jackson-datatype-jsr310)并注册您的对象映射器实例,如下所示:

    @Provider
    public class JacksonObjectMapper implements ContextResolver<ObjectMapper> {
    
      final ObjectMapper defaultObjectMapper;
    
      public JacksonObjectMapper() {
        defaultObjectMapper = createDefaultMapper();
      }
    
      @Override
      public ObjectMapper getContext(Class<?> type) {
        return defaultObjectMapper;
      }
    
      private static ObjectMapper createDefaultMapper() {
        final ObjectMapper mapper = new ObjectMapper();    
        mapper.registerModule(new JavaTimeModule());
        return mapper;
      }
    }
    

    在您的资源中注册Jackson时,您需要像这样添加此映射器:

    final ResourceConfig rc = new ResourceConfig().packages("<your package>");
    rc
      .register(JacksonObjectMapper.class)
      .register(JacksonJaxbJsonProvider.class);
    
  • 33

    如果您出于任何原因无法使用 jackson-modules-java8 ,您可以使用 @JsonIgnore@JsonGetter@JsonSetter 尽快(取消)序列化即时字段:

    public class MyBean {
    
        private Instant time = Instant.now();
    
        @JsonIgnore
        public Instant getTime() {
            return this.time;
        }
    
        public void setTime(Instant time) {
            this.time = time;
        }
    
        @JsonGetter
        private long getEpochTime() {
            return this.time.toEpochMilli();
        }
    
        @JsonSetter
        private void setEpochTime(long time) {
            this.time = Instant.ofEpochMilli(time);
        }
    }
    

    例:

    @Test
    public void testJsonTime() throws Exception {
        String json = new ObjectMapper().writeValueAsString(new MyBean());
        System.out.println(json);
        MyBean myBean = new ObjectMapper().readValue(json, MyBean.class);
        System.out.println(myBean.getTime());
    }
    

    产量

    {"epochTime":1506432517242}
    2017-09-26T13:28:37.242Z
    
  • 14

    这只是一个例子,如何在我讨厌调试此问题的单元测试中使用它 . 关键因素是

    • mapper.registerModule(new JavaTimeModule());
      杰克森-datype-jsr310的
    • maven依赖

    代码:import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.testng.Assert; import org.testng.annotations.Test;

    import java.io.IOException;
    import java.io.Serializable;
    import java.time.Instant;
    
    class Mumu implements Serializable {
        private Instant from;
        private String text;
    
        Mumu(Instant from, String text) {
            this.from = from;
            this.text = text;
        }
    
        public Mumu() {
        }
    
        public Instant getFrom() {
            return from;
        }
    
        public String getText() {
            return text;
        }
    
        @Override
        public String toString() {
            return "Mumu{" +
                    "from=" + from +
                    ", text='" + text + '\'' +
                    '}';
        }
    }
    public class Scratch {
    
    
        @Test
        public void JacksonInstant() throws IOException {
            ObjectMapper mapper = new ObjectMapper();
            mapper.registerModule(new JavaTimeModule());
    
            Mumu before = new Mumu(Instant.now(), "before");
            String jsonInString = mapper.writeValueAsString(before);
    
    
            System.out.println("-- BEFORE --");
            System.out.println(before);
            System.out.println(jsonInString);
    
            Mumu after = mapper.readValue(jsonInString, Mumu.class);
            System.out.println("-- AFTER --");
            System.out.println(after);
    
            Assert.assertEquals(after.toString(), before.toString());
        }
    
    }
    
  • 4

    我用这种时间格式: "{birthDate": "2018-05-24T13:56:13Z}" 从json反序列化为java.time.Instant(见截图)

    enter image description here

  • 2

    您可以在 application.yml 文件中设置此项以解析即时时间,即java8中的Date API:

    spring.jackson.serialization.write-dates-as-timestamps=false
    

相关问题