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

Ale*_*lor 203 jackson java-time

如何将Jackson JSON映射器与Java 8 LocalDateTime一起使用?

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

Mat*_*all 258

这里不需要使用自定义序列化器/反序列化器.使用jackson-modules-java8的datetime模块:

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

该模块增加了对很多类的支持:

  • 持续时间
  • 瞬间
  • LocalDateTime
  • LOCALDATE的
  • 当地时间
  • 月日
  • OffsetDateTime
  • OffsetTime
  • YearMonth
  • ZonedDateTime
  • 了zoneid
  • ZoneOffset

  • 哦,是的!我虽然这不起作用,因为我没有意识到必须对映射器对象执行这些自定义之一:`registerModule(new JSR310Module())`或`findAndRegisterModules()`.请参阅https://github.com/FasterXML/jackson-datatype-jsr310,以下是如何使用Spring框架自定义映射器对象:http://stackoverflow.com/questions/7854030/configurating-objectmapper-in-spring (51认同)
  • JSR310Module已经过时了,而是使用JavaTimeModule (31认同)
  • @MattBall我建议补充说,除了使用jackson-datatype-jsr310之外,还需要在对象映射器中注册JavaTimeModule:`objectMapper.registerModule(new JavaTimeModule());`.无论是序列化还是反序列化. (12认同)
  • 不能用我试过的最简单的一个,`OffsetDateTime`` @ Test``public void testJacksonOffsetDateTimeDeserializer()抛出IOException {``ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());``String json ="\"2015-10-20T11:00:00-8:30 \"";``mapper.readValue(json,OffsetDateTime.class);``}` (10认同)
  • 如果您使用最新的Spring框架,则不再需要自定义,因为众所周知的Jackson模块如果在类路径中被检测到,现在会自动注册:https://spring.io/blog/2014/12/ 02 /最新杰克逊 - 集成 - 改进 - 在弹簧#杰克逊模块 (9认同)
  • 上述模块已弃用.现在使用[jackson-modules-java8](https://github.com/FasterXML/jackson-modules-java8). (2认同)

Ale*_*lor 71

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

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

@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime ignoreUntil;
Run Code Online (Sandbox Code Playgroud)

提供自定义类:

public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
    @Override
    public void serialize(LocalDateTime arg0, JsonGenerator arg1, SerializerProvider arg2) throws IOException {
        arg1.writeString(arg0.toString());
    }
}

public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
    @Override
    public LocalDateTime deserialize(JsonParser arg0, DeserializationContext arg1) throws IOException {
        return LocalDateTime.parse(arg0.getText());
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • FasterXML**是**杰克逊.http://fasterxml.com https://github.com/fasterxml/jackson (4认同)
  • 原来如此.在我正在研究的项目中有这么多古老的pom条目.所以没有更多的org.codehaus,它现在都是com.fasterxml.谢谢! (4认同)
  • 此外,我无法使用内置的,因为我需要传递格式化程序ISO_DATE_TIME.使用JSR310Module时不确定是否可以这样做. (2认同)

gre*_*ror 48

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

compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.7.3'
Run Code Online (Sandbox Code Playgroud)

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

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();
Run Code Online (Sandbox Code Playgroud)

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

{
    "user_id": 1,
    "score": 9,
    "date_time": "2016-05-28T17:39:44.937"
}
Run Code Online (Sandbox Code Playgroud)

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

objectMapper.readValue(jsonString, new TypeReference<List<User>>() {
            });
Run Code Online (Sandbox Code Playgroud)

  • upvote为`findAndRegisterModules` (9认同)
  • 我还添加了这一行:`objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);` (3认同)
  • findAndRegisterModules()是构建ObjectMapper时缺少的关键部分 (2认同)
  • 那即时呢? (2认同)
  • 这是所需的完整代码: ObjectMapper objectMapper = new ObjectMapper(); objectMapper.findAndRegisterModules(); objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); (2认同)

iTa*_*ake 41

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

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.6.5</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

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

Jackson2ObjectMapperBuilder.json()
    .featuresToDisable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE提示. (5认同)
  • 除了禁用`DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE`之外,我还必须禁用`SerializationFeature.WRITE_DATES_AS_TIMESTAMPS`来开始正常工作. (5认同)

Dav*_*czo 37

您需要知道的一切都在 Jackson 文档中 https://www.baeldung.com/jackson-serialize-dates

Ad.9 很快就解决了我的问题。

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
Run Code Online (Sandbox Code Playgroud)

  • 谢谢戴夫,你让我免于发疯。在我的情况下,声明“jackson-datatype-jsr310”依赖项还不够,您提到的三行代码解决了我的问题。也感谢您发布参考资料。 (2认同)

小智 17

例如,在 Jackson JSR 的新版本中,已registerModule(new JSR310Module())弃用,现在建议使用JavaTimeModule

import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonFactory {
    private static ObjectMapper objectMapper = null;
    public static ObjectMapper getObjectMapper() {
        if (objectMapper == null) {
            objectMapper = new ObjectMapper();
            objectMapper.registerModule(new JavaTimeModule());
        }
        return objectMapper;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 工作完美!添加 objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) (2认同)

Wit*_*rba 16

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

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
Run Code Online (Sandbox Code Playgroud)


Sul*_*Aga 7

如果您正在使用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;
  }
}
Run Code Online (Sandbox Code Playgroud)

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

final ResourceConfig rc = new ResourceConfig().packages("<your package>");
rc
  .register(JacksonObjectMapper.class)
  .register(JacksonJaxbJsonProvider.class);
Run Code Online (Sandbox Code Playgroud)


edu*_*nti 7

如果您使用Jackson Serializer,以下是使用日期模块的方法:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import org.apache.kafka.common.serialization.Serializer;

public class JacksonSerializer<T> implements Serializer<T> {

    private final ObjectMapper mapper = new ObjectMapper()
            .registerModule(new ParameterNamesModule())
            .registerModule(new Jdk8Module())
            .registerModule(new JavaTimeModule());

    @Override
    public byte[] serialize(String s, T object) {
        try {
            return mapper.writeValueAsBytes(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)


Udo*_*Udo 6

如果jackson-modules-java8出于某种原因无法使用,可以long使用@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

例:

@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());
}
Run Code Online (Sandbox Code Playgroud)

产量

{"epochTime":1506432517242}
2017-09-26T13:28:37.242Z
Run Code Online (Sandbox Code Playgroud)


Mir*_*ciu 6

这只是一个如何在我调试此问题的单元测试中使用它的示例。关键成分是

  • mapper.registerModule(new JavaTimeModule());
  • Maven 依赖<artifactId>jackson-datatype-jsr310</artifactId>

代码:

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());
    }

}
Run Code Online (Sandbox Code Playgroud)


Jan*_*ena 6

如果您因 GraphQL Java 工具而遇到此问题并尝试Instant从日期字符串封送 Java,则需要设置 SchemaParser 以使用具有某些配置的 ObjectMapper:

在您的 GraphQLSchemaBuilder 类中,注入 ObjectMapper 并添加以下模块:

        ObjectMapper objectMapper = 
    new ObjectMapper().registerModule(new JavaTimeModule())
            .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
Run Code Online (Sandbox Code Playgroud)

并将其添加到选项中:

final SchemaParserOptions options = SchemaParserOptions.newOptions()
            .objectMapperProvider(fieldDefinition -> objectMapper)
            .typeDefinitionFactory(new YourTypeDefinitionFactory())
            .build();
Run Code Online (Sandbox Code Playgroud)

请参阅https://github.com/graphql-java-kickstart/graphql-spring-boot/issues/32