使用jackson jsonMap器序列化/反序列化java 8 java.time

nimxete2  于 2021-07-16  发布在  Java
关注(0)|答案(19)|浏览(732)

如何将jackson jsonMap器与java8 localdatetime结合使用?
org.codehaus.jackson.map.jsonmappingexception:无法从json字符串示例化类型[simple type,class java.time.localdatetime]的值;没有单个字符串构造函数/工厂方法(通过引用链:mydto[“field1”]->subdto[“date”])

lb3vh1jj

lb3vh1jj1#

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

z31licg0

z31licg02#

不幸的是,这里提出的解决方案在我的环境中不起作用。但老实说,使用java8时间对象作为dto毕竟不是一个好主意。
我建议改为创建自定义DTO,并且不要依赖不稳定的库,这些库可能在下一个jdk发行版后崩溃。这种方法也符合反腐败层和适配器模式的良好实践。
以下是dto的示例:

public class ReportDTO implements Serializable {

    private YearMonthDTO yearMonth;

    public YearMonthDTO getYearMonth() {
        return yearMonth;
    }

    public void setYearMonth(final YearMonthDTO yearMonth) {
        this.yearMonth = yearMonth;
    }

    public void fromYearMonth(final YearMonth yearMonth) {
        this.yearMonth = new YearMonthDTO(yearMonth.getYear(), 
                              yearMonth.getMonthValue());
    }

}

public static class YearMonthDTO {

    private int year;

    private int monthValue;

    public YearMonthDTO() {

    }

    public YearMonthDTO(int year, int monthValue) {
        this.year = year;
        this.monthValue = monthValue;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getMonthValue() {
        return monthValue;
    }

    public void setMonthValue(int monthValue) {
        this.monthValue = monthValue;
    }

}

当然,这取决于你的情况,以及你需要做的工作量。与任何模式一样,此解决方案并不适用于所有情况。
不管怎样,目前最好的答案似乎已经行不通了。我没有尝试其他解决方案,但我决定在我的简单案例中不依赖任何库。

7fyelxc5

7fyelxc53#

<dependency>
            <groupId>com.fasterxml.jackson.module</groupId>
            <artifactId>jackson-module-parameter-names</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jdk8</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
        </dependency>

添加这些依赖项并启用这些模块。这应该会有帮助

private static final ObjectMapper mapper = new ObjectMapper().findAndRegisterModules();
cbeh67ev

cbeh67ev4#

你只需要知道Jackson的文件https://www.baeldung.com/jackson-serialize-dates
快帮我解决了这个问题。

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

3gtaxfhh5#

如果您考虑使用fastjson,您可以解决您的问题,请注意版本

<dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.56</version>
 </dependency>
jfewjypa

jfewjypa6#

如果任何人在使用时有问题 SpringBoot 下面是我如何在不添加新依赖项的情况下修复问题的。
Spring 2.1.3 jackson期望日期字符串 2019-05-21T07:37:11.000 在这个 yyyy-MM-dd HH:mm:ss.SSS 要反序列化的格式 LocalDateTime . 确保日期字符串将日期和时间与 T 不是和 space . 秒( ss )和毫秒( SSS )可能会被忽略。

@JsonProperty("last_charge_date")
public LocalDateTime lastChargeDate;
slmsl1lt

slmsl1lt7#

对于那些谁使用Spring Boot2.x
无需执行上述任何操作—Java8LocalDateTime是现成的序列化/反序列化。我必须在1.x中完成以上所有操作,但是在boot2.x中,它可以无缝地工作。
在springboot中也可以看到这个参考jsonjava8localdatetime格式

inkz8wg9

inkz8wg98#

如果您遇到这个问题是因为graphqljava工具和试图封送java Instant 从日期字符串中,您需要设置schemaparser以使用具有特定配置的objectmapper:
在graphqlschemabuilder类中,插入objectmapper并添加以下模块:

ObjectMapper objectMapper = 
    new ObjectMapper().registerModule(new JavaTimeModule())
            .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

并将其添加到选项中:

final SchemaParserOptions options = SchemaParserOptions.newOptions()
            .objectMapperProvider(fieldDefinition -> objectMapper)
            .typeDefinitionFactory(new YourTypeDefinitionFactory())
            .build();

看到了吗https://github.com/graphql-java-kickstart/graphql-spring-boot/issues/32

l7wslrjt

l7wslrjt9#

如果您使用的是spring boot,并且offsetdatetime有这个问题,那么需要使用registermodules,正如上面@greperor所回答的(5月28日16时13分04分回答),但是请注意有一个区别。不需要添加上面提到的依赖项,因为我猜spring boot已经有了它。我在springboot上遇到了这个问题,它在没有添加依赖项的情况下对我有效。

ykejflvf

ykejflvf10#

你可以把这个放在你的房间里 application.yml 用于解析instant time(java8中的日期api)的文件:

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

pnwntuvh11#

这里不需要使用自定义序列化程序/反序列化程序。使用jackson-modules-java8的datetime模块:
数据类型模块,使jackson能够识别java8日期和时间api数据类型(jsr-310)。
此模块增加了对许多类的支持:
期间
瞬间
本地日期时间
本地日期
本地时间
月日
偏移日期时间
业余时间
期间

年月
分区日期
区域ID
区域偏移

brjng4g3

brjng4g312#

如果您使用的是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;
    }
}
kxeu7u2r

kxeu7u2r13#

这只是一个例子,如何使用它在一个单元测试,我黑调试这个问题。关键成分是 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());
    }

}
gt0wga4j

gt0wga4j14#

如果你不能使用 jackson-modules-java8 无论出于什么原因,您都可以将instant字段(反)序列化为 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);
    }
}

例子:

@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
wvt8vs2t

wvt8vs2t15#

如果您使用的是jersey,则需要按照其他建议添加maven依赖项(jackson-datatype-jsr310),并注册对象Map器示例,如下所示:

@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时,您需要添加以下Map器:

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

相关问题