在 spring 数据 elasticsearch 中序列化 AggregatedPage 时出现 jackson 解析错误

Getting jackson parsing error while serializing AggregatedPage in spring data elasticsearch

我正在尝试使用 spring 数据 elasticsearch 在 elasticsearch 中创建一个用于聚合的休息 api 点。我能够在服务层获取数据但是当控制器(即@RestController)试图return它给邮递员时我收到这个错误。

Could not write JSON: For input string: "bHRMZzc5aHdodDF5a0hOck15Lzl1UT09"; nested exception is com.fasterxml.jackson.databind.JsonMappingException: For input string: "bHRMZzc5aHdodDF5a0hOck15Lzl1UT09" (through reference chain: org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl["aggregations"]->org.elasticsearch.search.aggregations.InternalAggregations["asMap"]->java.util.Collections$UnmodifiableMap["memberNumberToken"]->org.elasticsearch.search.aggregations.bucket.terms.StringTerms["buckets"]->java.util.ArrayList[0]->org.elasticsearch.search.aggregations.bucket.terms.StringTerms$Bucket["keyAsNumber"])

我的映射文件是这个

{
  "transactions" : {
        "properties" : {

                "refernceId" : {
                  "type" :"text",
                  "index": true,
                  "store": true
                },
                "postingDate" : { 
                  "type" : "date",
                  "index": true,
                  "store": true,
                  "format" : "yyyy-MM-dd'T'HH:mm:ss'Z'"
                },
                "effectiveDate" : { 
                  "type" : "date",
                  "index": true,
                  "store": true,
                  "format" : "yyyy-MM-dd'T'HH:mm:ss'Z'"
                },
                "effectiveTime" : { 
                  "type" : "text",
                  "index": true,
                  "store": true
                },
                "effectiveEpochTime" : {
                  "type" : "long",
                  "index": true,
                  "store": true
                },
                "transactionAmount" : { 
                  "type" : "double",
                  "index": true,
                  "store": true
                },
                "transactionType" : { 
                  "type" : "keyword",
                  "index": true,
                  "store": true
                },
                "transactionDesc" : { 
                  "type" : "text",
                  "index": true,
                  "store": true
                },
                "transactionMemo" : {
                  "type" : "text",
                  "index": true,
                  "store": true
                },
                "transactionNumber" : { 
                  "type" : "text",
                  "index": true,
                  "store": true
                },
                "transactionTypeCode" : { 
                  "type" : "text",
                  "index": true,
                  "store": true
                },
                "transactionStatus" : {
                  "type" : "keyword",
                  "index": true,
                  "store": true
                },
                "principalAmount" : {
                  "type" : "double",
                  "index": true,
                  "store": true

                },
                "interest" : {
                  "type" : "text",
                  "index": true,
                  "store": true
                },
                "accountNumberToken" : { 
                  "type" : "keyword",
                  "index": true,
                  "store": true
                },
                "memberNumberToken" : {
                  "type" : "keyword",
                  "index": true,
                  "store": true
                },
                "accountType" : {
                  "type" : "keyword",
                  "index": true,
                  "store": true

                 },
                "userSub" : { 
                  "type" : "keyword",
                  "index": true,
                  "store": true
                },
                "tenant" : { 
                  "type" : "keyword",
                  "index": true,
                  "store": true
                }

            }
        }
    }

我的 pom 文件:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.tyfone</groupId>
    <artifactId>mcb-search-feature</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>mcb-search-feature Maven Webapp</name>
    <url>http://maven.apache.org</url>

    <properties>
        <jdk.version>1.8</jdk.version>
        <spring.version>5.0.1.RELEASE</spring.version>
        <jstl.version>1.2</jstl.version>
        <servletapi.version>4.0.0</servletapi.version>
        <spring.data.elastic.version>3.0.2.RELEASE</spring.data.elastic.version>
        <slf4j.version>1.7.25</slf4j.version>
        <junit.version>3.8.1</junit.version>

    </properties>

    <dependencies>




        <!-- Spring MVC framework -->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- JSTL -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>${jstl.version}</version>
        </dependency>

        <!-- for compile only, your container should have this -->
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${servletapi.version}</version>
            <scope>provided</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-elasticsearch -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-elasticsearch</artifactId>
            <version>${spring.data.elastic.version}</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-simple -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.25</version>
            <scope>test</scope>
        </dependency>



        <!-- Test -->
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-all</artifactId>
            <version>1.3</version>
            <scope>test</scope>
        </dependency>
        <!-- Testing pojo classes -->
        <dependency>
            <groupId>com.googlecode.openpojo</groupId>
            <artifactId>openpojo</artifactId>
            <version>0.6.0</version>
            <scope>test</scope>
        </dependency>
        <!-- <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> 
            <version>${junit.version}</version> <exclusions> <exclusion> <groupId>org.hamcrest</groupId> 
            <artifactId>hamcrest-core</artifactId> </exclusion> </exclusions> </dependency> -->

        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>


        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-all</artifactId>
            <version>1.9.5</version>
            <scope>test</scope>
        </dependency>


    </dependencies>


    <build>
        <finalName>mcb-search-feature</finalName>
    </build>
</project>

如果还有人感兴趣。有完全相同的问题。这与 Jackson 并不真正知道 AggregatedPage 中包含的正确类型有关。因此,它简单地遍历所有 getter 并在 keyAsNumber 上绊倒,其中键不是数字,在您的情况下为 bHRMZzc5aHdodDF5a0hOck15Lzl1UT09。这最终导致异常。

我最终在 Spring 应用程序启动期间配置 Jackson 以在序列化期间省略 keyAsNumber。

所以这对我有用:

@Configuration
public class JacksonConfig   {

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer changeKeyAsNumber() {
        return new Jackson2ObjectMapperBuilderCustomizer() {

            @Override
            public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
                jacksonObjectMapperBuilder.mixIn(StringTerms.Bucket.class, MixIn.class);
            }
        };
    }

}

abstract class MixIn {
    @JsonIgnore
    abstract public Number getKeyAsNumber();
}

我按照 Amaresh Kulkarni 的建议使用 ParsedStringTerms.ParsedBucket.class 而不是 StringTerms.Bucket.class 使其正常工作。这是完整的 JacksonConfiguraton

@Configuration
public class JacksonConfig   {

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer changeKeyAsNumber() {
        return new Jackson2ObjectMapperBuilderCustomizer() {

            @Override
            public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
                jacksonObjectMapperBuilder.mixIn(ParsedStringTerms.ParsedBucket.class, MixIn.class);
            }
        };
    }

}

abstract class MixIn {
    @JsonIgnore
    abstract public Number getKeyAsNumber();
}

对于搜索后来到这里的任何人: 我 运行 遇到了同样的问题并使用了 WebFlux。看起来它需要一个额外的配置。我合并了 sung sung 的代码和这里的答案:

我完成的代码如下所示:

@Configuration 
public class JacksonConfig{

@Bean
public Jackson2ObjectMapperBuilderCustomizer changeKeyAsNumber() {
    return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.mixIn(ParsedStringTerms.ParsedBucket.class, MixIn.class);
}

@Bean
JavaTimeModule javaTimeModule(){
    return new JavaTimeModule();
}

@Bean
public Jackson2JsonEncoder jackson2JsonEncoder(ObjectMapper objectMapper){
    return new Jackson2JsonEncoder(objectMapper);
}

@Bean
public Jackson2JsonDecoder jackson2JsonDecoder(ObjectMapper objectMapper){
    return new Jackson2JsonDecoder(objectMapper);
}

@Bean
public WebFluxConfigurer webFluxConfigurer(Jackson2JsonEncoder encoder, Jackson2JsonDecoder decoder){
    return new WebFluxConfigurer() {
        @Override
        public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
            configurer.defaultCodecs().jackson2JsonEncoder(encoder);
            configurer.defaultCodecs().jackson2JsonDecoder(decoder);
        }
    };
}

}

abstract class MixIn {
    @JsonIgnore
    abstract public Number getKeyAsNumber();
}