elasticsearch,jackson,Java,Spring,Spring Boot,elasticsearch,Jackson" /> elasticsearch,jackson,Java,Spring,Spring Boot,elasticsearch,Jackson" />

无法构造'java.time.LocalDate'-Spring boot、elasticseach、jackson的实例

无法构造'java.time.LocalDate'-Spring boot、elasticseach、jackson的实例,java,spring,spring-boot,elasticsearch,jackson,Java,Spring,Spring Boot,elasticsearch,Jackson,我正在使用springboot2.0.0.M7和springbootstarterdataelasticsearch和elasticsearch 5并且通过反序列化LocalDate字段得到了一个错误 我的文档如下所示: @Document(indexName= "myIndex", type = "cluster") public class Cluster { @Id @Field private Long id; @Field private St

我正在使用
springboot2.0.0.M7
springbootstarterdataelasticsearch
elasticsearch 5
并且通过反序列化
LocalDate
字段得到了一个错误

我的文档如下所示:

@Document(indexName= "myIndex", type = "cluster")
public class Cluster {

    @Id
    @Field
    private Long id;
    @Field
    private String name;
    @Field
    private ClusterUrl clusterUrl;
    @Field
    private ClusterVisible clusterVisible;
}
其中ClusterVisible是一个子对象,它包含
LocalDates

public class ClusterVisible {

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd.MM.yyyy")
    private LocalDate start;
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd.MM.yyyy")
    private LocalDate end;
}
因此,我只需查询一个集群Id,就会得到以下异常:

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":12345,"name":"Cluster name ","clusterName":{"de":"Cluster de","it":null,"fr":null},"clusterUrl":{"de":"/url/results","it":null,"fr":null},"clusterVisible":{"start":{"year":2017,"month":"OCTOBER","dayOfMonth":9,"dayOfWeek":"MONDAY","era":"CE","dayOfYear":282,"leapYear":false,"mo"[truncated 252 chars]; line: 1, column: 388] (through reference chain: com.example.elasticsearch5.es.cluster.model.Cluster["clusterVisible"]->com.example.elasticsearch5.es.cluster.model.ClusterVisible["start"])
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
    at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1451)
    at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1027)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1290)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:127)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:127)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2992)
    at org.springframework.data.elasticsearch.core.DefaultEntityMapper.mapToObject(DefaultEntityMapper.java:65)
我已经知道我需要为
java.time api
添加一些jackson依赖项,因此我添加了:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.4</version>
</dependency>
修复此错误时我会错过什么

添加:精确错误发生在
mapper.mapToObject
处。所以我创建了一个
新的DefaultEntityMapper()前面的一些行。这可能是问题所在吗

@Override
public Page<Cluster> findClustersAndScoreByText(String text) {
    QueryBuilder queryBuilder = QueryBuilders.boolQuery()
            .should(QueryBuilders.queryStringQuery(text).lenient(true).defaultOperator(Operator.OR)
                    .field("name")
                    .field("svno"));

    NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(queryBuilder)
            .withPageable(PageRequest.of(0, 100)).build();

    DefaultEntityMapper mapper = new DefaultEntityMapper();
    ResultsExtractor<Page<Cluster>> rs = new ResultsExtractor<Page<Cluster>>() {

        @Override
        public Page<Cluster> extract(SearchResponse response) {
            ArrayList<Cluster> hotels = new ArrayList<>();
            SearchHit[] hits = response.getHits().getHits();
            for (SearchHit hit : hits) {
                try {
                    Cluster cluster = mapper.mapToObject(hit.getSourceAsString(), Cluster.class);
                    cluster.setScore(hit.getScore());
                    hotels.add(cluster);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return new PageImpl<>(hotels, PageRequest.of(0, 100), response.getHits().getTotalHits());
        }
    };

    return elasticsearchTemplate.query(nativeSearchQuery, rs);
}
@覆盖
公共页面findClustersAndScoreByText(字符串文本){
QueryBuilder QueryBuilder=QueryBuilders.boolQuery()
.should(QueryBuilders.queryStringQuery(text).lenient(true).defaultOperator(Operator.OR)
.字段(“名称”)
.字段(“svno”);
NativeSearchQuery NativeSearchQuery=新建NativeSearchQueryBuilder()。withQuery(queryBuilder)
.withPageable(PageRequest.of(01100)).build();
DefaultEntityMapper=新的DefaultEntityMapper();
ResultsExtractor rs=新的ResultsExtractor(){
@凌驾
公共页面摘录(SearchResponse){
ArrayList hotels=新建ArrayList();
SearchHit[]hits=response.getHits().getHits();
for(SearchHit:hits){
试一试{
Cluster Cluster=mapper.mapToObject(hit.getSourceAsString(),Cluster.class);
cluster.setScore(hit.getScore());
酒店。添加(集群);
}捕获(IOE异常){
e、 printStackTrace();
}
}
返回新的PageImpl(hotels,PageRequest.of(01100),response.getHits().getTotalHits());
}
};
返回elasticsearchTemplate.query(nativeSearchQuery,rs);
}

根据ISO 8601,日期/时间格式是“YYYY-MM-DD”,因此您的模式应该是:

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
而不是:

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd.MM.yyyy")
另一种方法是在应用程序中添加.yml

spring:
    jackson:
        serialization:
            WRITE_DATES_AS_TIMESTAMPS: false
或者直接在对象映射器中禁用此功能:

objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)

在LocalDate字段上添加以下注释

@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate start;

需要安装JsonFormat JsonSerialize JsonSerialize

private LocalDate dateOfBirth;

    @PastOrPresent(message = "must be past time or present")
    @Column(name = "date_of_birth", nullable = false, columnDefinition = "DATE")
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy")
    @JsonDeserialize(using = LocalDateDeserializer.class)
    @JsonSerialize(using = LocalDateSerializer.class)
    public LocalDate getDateOfBirth() {
        return dateOfBirth;
    }

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy")
    public void setDateOfBirth(LocalDate dateOfBirth) {
        this.dateOfBirth = dateOfBirth;
    }

您不需要
@JsonFormat
。您只需
DateFormat.date
注释中的参数(kotlin):

@字段(类型=日期,格式=日期)
创建的val:LocalDate=now()
Elasticsearch不使用Jackson,而是使用一个

日期将以弹性格式保存:
2020-01-02
,映射为:

“已创建”:{
“类型”:“日期”,
“格式”:“日期”
}


您的开始和结束数据是对象。。。为什么
pattern=“dd.MM.yyyy”
可以工作?@cricket\u 007应该可以反序列化到前端。但是我删除了它,没有任何更改。错误告诉您localdatetime不存在默认构造函数,它是一个不可变的类,因此它不能只为json中的每个字段调用
setters
。为什么不为该对象编写自己的类?@cricket\u 007如果配置不起作用,我需要编写自己的类。我自动连接了jackson对象映射器,但使用了一个新的映射器,我得到了localdate的另一个异常:
com.fasterxml.jackson.databind.exc.MismatchedInputException:意外标记(开始对象),预期值字符串:预期数组或字符串。
有什么想法吗?
“开始”:{
是一个对象,正如错误所说。
JsonFormat.Shape.STRING
正在尝试解析一个字符串,而您没有该字符串。如果这些字符串是自动生成的存根,则此解决方案将不起作用。@evdelacruz的答案更有效。如何禁用一个请求的序列化,而不是所有请求的序列化?@DimitriKopriwa,ObjectMapper是一个我需要的beans构建在ApplicationContext中,以便根据需要注入。恐怕您需要使用Jackson自定义注释来实现这一点。另一种可能是将字段视为DTO/VO/to中的字符串,然后根据需要在特定场景/请求中对其进行解析。
private LocalDate dateOfBirth;

    @PastOrPresent(message = "must be past time or present")
    @Column(name = "date_of_birth", nullable = false, columnDefinition = "DATE")
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy")
    @JsonDeserialize(using = LocalDateDeserializer.class)
    @JsonSerialize(using = LocalDateSerializer.class)
    public LocalDate getDateOfBirth() {
        return dateOfBirth;
    }

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy")
    public void setDateOfBirth(LocalDate dateOfBirth) {
        this.dateOfBirth = dateOfBirth;
    }