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

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

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

pnwntuvh

pnwntuvh1#

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

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

gv8xihay

gv8xihay2#

更新:出于历史原因留下这个答案,但我不建议这样做。请看上面接受的答案。
告诉jackson使用自定义[反]序列化类进行Map:

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

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

zqdjd7g9

zqdjd7g93#

如果您使用的是fasterxml的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>>() {
            });
u0njafvf

u0njafvf4#

此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)
dtcbnfnu

dtcbnfnu5#

我在使用SpringBoot时也遇到了类似的问题。使用spring boot 1.5.1.release,我所要做的就是添加依赖项:

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

wvt8vs2t6#

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

gt0wga4j7#

如果你不能使用 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
kxeu7u2r

kxeu7u2r8#

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

}
brjng4g3

brjng4g39#

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

lb3vh1jj10#

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

ykejflvf

ykejflvf11#

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

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

l7wslrjt12#

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

inkz8wg9

inkz8wg913#

如果您遇到这个问题是因为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

slmsl1lt

slmsl1lt14#

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

jfewjypa

jfewjypa15#

如果任何人在使用时有问题 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;

相关问题