elasticsearch LocalDate反序列化和序列化错误-Jackson.databind.exc.无效定义异常:无法构造java.time.LocalDate的示例

x6h2sr28  于 2023-02-07  发布在  ElasticSearch
关注(0)|答案(4)|浏览(401)

存储在Elastic中的员工的生日似乎存储为不正确的数据类型。我为Elasticseach客户端设置了对象Map器和注册的JavaTime模块的代码。我尝试从Elasticsearch中提取员工列表,但似乎不起作用,反序列化失败。

Jar Versions:
org.elasticsearch.client:elasticsearch-rest-client -> 6.4.3 (*)
org.elasticsearch.client:elasticsearch-rest-high-level-client -> 6.4.3
org.elasticsearch:elasticsearch -> 6.4.3
org.springframework.data:spring-data-elasticsearch -> 3.1.4.RELEASE
com.fasterxml.jackson.datatype:jackson-datatype-hppc -> 2.9.8
com.fasterxml.jackson.core:jackson-core:2.9.8
com.fasterxml.jackson.core:jackson-databind:2.9.8 (*)
com.fasterxml.jackson.datatype:jackson-datatype-jsr310 -> 2.9.8 (*)
com.fasterxml.jackson.datatype:jackson-datatype-hibernate5 -> 2.9.8
com.fasterxml.jackson.core:jackson-annotations -> 2.9.0
com.fasterxml.jackson.module:jackson-module-afterburner -> 2.9.8
com.fasterxml.jackson.module:jackson-module-parameter-names:2.9.8 (*)
com.fasterxml.jackson.module:jackson-modules-java8:2.9.8

Build.Gradle:

compile "com.fasterxml.jackson.datatype:jackson-datatype-hppc"
    compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310"
    compile "com.fasterxml.jackson.datatype:jackson-datatype-hibernate5"
    compile "com.fasterxml.jackson.core:jackson-annotations"
    compile "com.fasterxml.jackson.core:jackson-databind"
    compile "com.fasterxml.jackson.module:jackson-module-afterburner"
    runtime group: 'com.fasterxml.jackson.module', name: 'jackson-modules-java8', version: '2.9.8', ext: 'pom'
    // https://mvnrepository.com/artifact/com.fasterxml.jackson.module/jackson-module-parameter-names
compile group: 'com.fasterxml.jackson.module', name: 'jackson-module-parameter-names', version: '2.9.8'

compile 'org.elasticsearch:elasticsearch'
    compile 'org.elasticsearch.client:transport'
    compile 'org.elasticsearch.client:elasticsearch-rest-client'
    compile 'org.elasticsearch.client:elasticsearch-rest-high-level-client'

    compile 'org.springframework.data:spring-data-elasticsearch'

application.yml

jackson:
    serialization:
         WRITE_DATES_AS_TIMESTAMPS: false
 jpa: 

    open-in-view: false

弹性配置代码:

@AutoConfigureAfter(value = { JacksonConfiguration.class })
public class ElasticsearchConfiguration {


    RestHighLevelClient client = null; 

    @Bean
    public RestHighLevelClient buildClient() {
        return new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("localhost", 9200, "http"),
                        new HttpHost("localhost", 9201, "http")));
    }

    @Bean
    @Primary
    public ElasticsearchOperations elasticsearchTemplate(final ElasticsearchConverter elasticsearchConverter,
            EntityMapper mapper, Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder ) {
        return new ElasticsearchTemplate((Client) buildClient(), new CustomEntityMapper(new ObjectMapper()));
    }
    //jackson2ObjectMapperBuilder.createXmlMapper(false).build()

    public class CustomEntityMapper implements EntityMapper {

        private ObjectMapper objectMapper;

        public CustomEntityMapper(ObjectMapper objectMapper) {
            this.objectMapper = objectMapper;
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
            objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
            objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
            //objectMapper.registerModule(new JavaTimeModule());
            JavaTimeModule javaTimeModule=new JavaTimeModule();
            // Hack time module to allow 'Z' at the end of string (i.e. javascript json's) 
            javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ISO_DATE_TIME));
            javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ISO_DATE));
            objectMapper.registerModule(javaTimeModule);
            objectMapper.registerModule(new ParameterNamesModule());
            objectMapper.registerModule(new Jdk8Module());
            objectMapper.findAndRegisterModules();
        }

        @Override
        public String mapToString(Object object) throws IOException {
            return objectMapper.writeValueAsString(object);
        }

        @Override
        public <T> T mapToObject(String source, Class<T> clazz) throws IOException {
            return objectMapper.readValue(source, clazz);
        }
    }

}

错误:

Caused by: org.springframework.data.elasticsearch.ElasticsearchException: failed to map source [ {"id":73,"name":"K****","birthDate":{"year":2019,"month":"MAY","dayOfYear":150,"leapYear":false,"dayOfMonth":30,"dayOfWeek":"THURSDAY","era":"CE","monthValue":5,"chronology":{"id":"ISO","calendarType":"iso8601"}},"role..}] to class Employee
    at org.springframework.data.elasticsearch.core.AbstractResultMapper.mapEntity(AbstractResultMapper.java:45) ~[spring-data-elasticsearch-3.1.4.RELEASE.jar:3.1.4.RELEASE]
    at org.springframework.data.elasticsearch.core.DefaultResultMapper.mapResults(DefaultResultMapper.java:102) ~[spring-data-elasticsearch-3.1.4.RELEASE.jar:3.1.4.RELEASE]
    at org.springframework.data.elasticsearch.core.ElasticsearchTemplate.queryForPage(ElasticsearchTemplate.java:315) ~[spring-data-elasticsearch-3.1.4.RELEASE.jar:3.1.4.RELEASE]
    at org.springframework.data.elasticsearch.core.ElasticsearchTemplate.queryForPage(ElasticsearchTemplate.java:309) ~[spring-data-elasticsearch-3.1.4.RELEASE.jar:3.1.4.RELEASE]
    at org.springframework.data.elasticsearch.core.ElasticsearchTemplate.queryForPage(ElasticsearchTemplate.java:139) ~[spring-data-elasticsearch-3.1.4.RELEASE.jar:3.1.4.RELEASE]
    at org.springframework.data.elasticsearch.repository.support.AbstractElasticsearchRepository.findAll(AbstractElasticsearchRepository.java:126) ~[spring-data-elasticsearch-3.1.4.RELEASE.jar:3.1.4.RELEASE]
    at org.springframework.data.elasticsearch.repository.support.AbstractElasticsearchRepository.findAll(AbstractElasticsearchRepository.java:120) ~[spring-data-elasticsearch-3.1.4.RELEASE.jar:3.1.4.RELEASE]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_211]
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_211]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_211]
    at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_211]
    at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `java.time.LocalDate` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (String)"{"id":73,"name":"Kelly","birthDate":{"year":2019,"month":"MAY","dayOfYear":150,"leapYear":false,"dayOfMonth":30,"dayOfWeek":"THURSDAY","era":"CE","monthValue":5,"chronology":{"id":"ISO","calendarType":"iso8601"}},"role...}},"lastModifiedBy""[truncated 396 chars]; line: 1, column: 38] (through reference chain: Employee["birthDate"])
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67) ~[jackson-databind-2.9.8.jar:2.9.8]
    at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1452) ~[jackson-databind-2.9.8.jar:2.9.8]
    at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1028) ~[jackson-databind-2.9.8.jar:2.9.8]
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1297) ~[jackson-databind-2.9.8.jar:2.9.8]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326) ~[jackson-databind-2.9.8.jar:2.9.8]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159) ~[jackson-databind-2.9.8.jar:2.9.8]
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:127) ~[jackson-databind-2.9.8.jar:2.9.8]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288) ~[jackson-databind-2.9.8.jar:2.9.8]
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151) ~[jackson-databind-2.9.8.jar:2.9.8]
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013) ~[jackson-databind-2.9.8.jar:2.9.8]
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3004) ~[jackson-databind-2.9.8.jar:2.9.8]
    at org.springframework.data.elasticsearch.core.DefaultEntityMapper.mapToObject(DefaultEntityMapper.java:82) ~[spring-data-elasticsearch-3.1.4.RELEASE.jar:3.1.4.RELEASE]
    at org.springframework.data.elasticsearch.core.AbstractResultMapper.mapEntity(AbstractResultMapper.java:43) ~[spring-data-elasticsearch-3.1.4.RELEASE.jar:3.1.4.RELEASE]
    ... 34 common frames omitted

雇员:

public class Employee extends AbstractAuditingEntity implements Serializable{

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private Long id;

    //Remaining Fields are removed for brevity

抽象审计实体

@MappedSuperclass
@Audited
@EntityListeners({AuditingEntityListener.class, EntityAuditEventListener.class})
public abstract class AbstractAuditingEntity implements Serializable {

    private static final long serialVersionUID = 1L;

    @CreatedBy
    @Column(name = "created_by", nullable = true, length = 50, updatable = false)
    private String createdBy;

    @CreatedDate
    @Column(name = "created_date")
    private LocalDateTime createdDate = LocalDateTime.now();

    @LastModifiedBy
    @Column(name = "last_modified_by", length = 50)
    private String lastModifiedBy;

    @LastModifiedDate
    @Column(name = "last_modified_date")
    private LocalDateTime lastModifiedDate = LocalDateTime.now();
lpwwtiir

lpwwtiir1#

您的问题可能是因为Jackson不支持Java 8 DateTime API,所以您可以添加以下库来添加对它的支持(在pom.xml中添加):

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

并配置对象Map器以使用此库模块,如下所示:

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

使用链接以供参考:https://github.com/FasterXML/jackson-modules-java8

wnavrhmk

wnavrhmk2#

我已经成功地在Spring Data Elasticsearch中使用了java.time类型,配置如下:

@Configuration
@EnableElasticsearchRepositories(basePackages = "org.example.search.repository")
public class ElasticsearchConfig {

    @Bean
    public ElasticsearchTemplate elasticsearchTemplate(Client client) {
        return new ElasticsearchTemplate(client, new CustomEntityMapper());
    }

    static class CustomEntityMapper implements EntityMapper {

        private final ObjectMapper mapper;

        CustomEntityMapper() {
            mapper = new ObjectMapper()
                    .setDefaultPropertyInclusion(Include.NON_NULL)
                    .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                    .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                    .enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
                    .findAndRegisterModules();
        }

        @Override
        public String mapToString(Object object) throws IOException {
            return mapper.writeValueAsString(object);
        }

        @Override
        public <T> T mapToObject(String source, Class<T> clazz) throws IOException {
            return mapper.readValue(source, clazz);
        }
    }
}
3pvhb19x

3pvhb19x3#

这更像是一种解决方法,但可以在相应的localdate/localdatetime字段上添加下面提到的注解。

@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
jjhzyzn0

jjhzyzn04#

对于正在寻找版本ES-8Sping Boot :3.0上的解决方案的用户
创建一个扩展ElasticsearchConfiguration的配置类,并覆盖clientConfiguration和elasticsearchClient创建。
在elasticsearchClient创建过程中,注入配置为使用Java 8时间模块的您自己的objectMapper,这将覆盖默认的objectMapper。

@Override
public ClientConfiguration clientConfiguration() {
    return ClientConfiguration.builder()
            .connectedTo(<Hostname> +":"+ <Port>)
            .usingSsl()
            .withBasicAuth(<Username>, <Password>)
            .build();
}

@Override
public ElasticsearchClient elasticsearchClient(RestClient restClient) {
    Assert.notNull(restClient, "restClient must not be null");

    //Create Java8 time module
    JavaTimeModule module = new JavaTimeModule();
    module.addSerializer(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DateFormat.date_time_no_millis.getPattern())));

    //Register the module with objectMapper
    ObjectMapper objectMapper=new ObjectMapper()
            .registerModule(module);

    //To convert datetime to ISO-8601
    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

    //Creating our own jsonpMapper 
    JsonpMapper jsonpMapper=new JacksonJsonpMapper(objectMapper);

    // Create the transport with a Jackson mapper
    ElasticsearchTransport transport = new RestClientTransport(
            restClient, jsonpMapper);

    // And create the API client
    return  new ElasticsearchClient(transport);
}

Maven依赖项:

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

相关问题