spring-data-elasticsearch

Getting jackson parsing error while serializing AggregatedPage in spring data elasticsearch


I was trying to create a rest api point for aggregation in elasticsearch using spring data elasticsearch. I am able to get the data in service layer but when controller (i.e. @RestController) is trying to return it to postman i am getting this error.

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"])

My Mapping file is this

{
  "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
                }

            }
        }
    }

My pom file :

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

Solution

  • If anyone is still interested. Had the exact same issue. It related to the fact that Jackson doesn't really know the correct types which are contained in AggregatedPage. So it simply runs through all the getters and stumbles over keyAsNumber where the key isn't a number, bHRMZzc5aHdodDF5a0hOck15Lzl1UT09 in your case. This ends up in an exception.

    I ended up in configuring Jackson during the startup of the Spring App to omit keyAsNumber during the serialization.

    So this did the job for me:

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