You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Elasticsearch分页查询全部文档时遭遇JsonMappingException空指针异常

Fixing JsonMappingException (NullPointerException on "facets") in Spring Data Elasticsearch Pagination

I’ve run into this exact issue before—here’s what’s going on and how to fix it:

Root Cause

When you call findAll(Pageable) on your ElasticsearchRepository, Spring Data Elasticsearch returns an AggregatedPageImpl instance by default. This class is built to handle aggregation results (like facets), but when you’re doing a simple fetch-all without any aggregations, the facets field ends up null. Older versions of Spring Data Elasticsearch have a bug where Jackson tries to serialize this null field, triggering the NullPointerException you’re seeing.

Solutions

1. Upgrade Spring Data Elasticsearch (Recommended)

The cleanest fix is to upgrade to a newer version where this issue is resolved. Versions 4.0 and above properly handle the facets field (either marking it as nullable or using a different implementation for non-aggregated queries).

If you’re using Maven, update your dependency in pom.xml:

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-elasticsearch</artifactId>
    <version>4.4.0</version> <!-- Use the latest version compatible with your Spring Boot setup -->
</dependency>

For Gradle:

implementation 'org.springframework.data:spring-data-elasticsearch:4.4.0'

2. Use ElasticsearchOperations to Fetch Pages Without Aggregations

If upgrading isn’t feasible, bypass the repository’s findAll method and use ElasticsearchOperations to run a match-all query, then wrap results in a standard PageImpl (which doesn’t have the problematic facets field).

Modify your ConventionServiceImpl like this:

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
import java.util.stream.Collectors;

@Service
@Transactional
public class ConventionServiceImpl implements ConventionService {

    private final ConventionSearchRepository repository;
    private final ElasticsearchOperations elasticsearchOperations;

    // Constructor injection (preferred over @Autowired)
    public ConventionServiceImpl(ConventionSearchRepository repository, ElasticsearchOperations elasticsearchOperations) {
        this.repository = repository;
        this.elasticsearchOperations = elasticsearchOperations;
    }

    @Override
    public Page<Convention> getAllConventions(Pageable pageable) {
        // Build a match-all query with pagination
        Query query = new NativeSearchQueryBuilder()
                .withQuery(org.springframework.data.elasticsearch.core.query.QueryBuilders.matchAllQuery())
                .withPageable(pageable)
                .build();

        // Execute the query
        SearchHits<Convention> searchHits = elasticsearchOperations.search(query, Convention.class);

        // Convert SearchHits to a list of Convention entities
        var conventions = searchHits.stream()
                .map(SearchHit::getContent)
                .collect(Collectors.toList());

        // Return a standard PageImpl instead of AggregatedPageImpl
        return new PageImpl<>(conventions, pageable, searchHits.getTotalHits());
    }
}

3. Ignore the "facets" Field in Jackson Serialization

If you need to keep using the repository’s findAll method, configure Jackson to ignore the null facets field. Create a Jackson mix-in to exclude the field:

import com.fasterxml.jackson.databind.annotation.JsonIgnoreProperties;

// Mix-in to ignore the facets field in AggregatedPageImpl
@JsonIgnoreProperties(value = {"facets"}, ignoreUnknown = true)
public abstract class AggregatedPageImplMixIn {}

Then register this mix-in in your Jackson configuration:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;

@Configuration
public class JacksonConfig {
    @Bean
    public ObjectMapper elasticsearchObjectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.addMixIn(AggregatedPageImpl.class, AggregatedPageImplMixIn.class);
        return mapper;
    }
}

This tells Jackson to skip the facets field during serialization, preventing the NPE.


内容的提问来源于stack exchange,提问作者Aymen Kanzari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:48:26