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

实现Elasticsearch自定义转换器时遇MappingException问题求助

解决Spring Data Elasticsearch的MappingException问题

最近我在给自定义的TransactionElastic对象实现Elasticsearch转换器时,启动项目直接报错了——抛出MappingException: Couldn't find PersistentEntity for type class TransactionElastic,同时转换器注册日志还提示Registering converter from class com.portal.domain.TransactionElastic to interface java.util.Map as writing converter although it doesn't convert to a store-supported type!。下面是我当时的相关代码和环境信息,折腾一番后终于找到问题根源,分享给大家:


我的配置与代码

配置类

@Configuration
public class ElasticConfig extends AbstractElasticsearchConfiguration {
    @Value("${elasticUrl}")
    private String elasticUrl;

    @Override
    public RestHighLevelClient elasticsearchClient() {
        return RestClients.create(ClientConfiguration.create(elasticUrl)).rest();
    }

    @Bean
    public EntityMapper entityMapper() {
        ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(elasticsearchMappingContext(), new DefaultConversionService());
        entityMapper.setConversions(elasticsearchCustomConversions());
        return entityMapper;
    }

    @Bean
    @Override
    public ElasticsearchCustomConversions elasticsearchCustomConversions() {
        return new ElasticsearchCustomConversions(Arrays.asList(new TransactionToMapConverter(), new MapToTransactionConverter()));
    }
}

写入转换器

@WritingConverter
public class TransactionToMapConverter implements Converter<TransactionElastic, Map<String, Object>> {
    @Override
    public Map<String, Object> convert(TransactionElastic tradeTransaction) {
        Map<String, Object> target = new HashMap<>();
        target.put("id", tradeTransaction.getId());
        target.put("portfolio_name", tradeTransaction.getPortfolioName());
        target.put("settl_date", tradeTransaction.getSettlDate());
        return target;
    }
}

读取转换器

@ReadingConverter
public class MapToTransactionConverter implements Converter<Map<String, Object>, TransactionElastic> {
    @Override
    public TransactionElastic convert(Map<String, Object> map) {
        TransactionElastic t = new TransactionElastic();
        t.setPortfolioName(map.get("portfolio_name").toString());
        t.setId((Long) map.get("id"));
        return t;
    }
}

实体类

@Document(indexName = "transactions")
public class TransactionElastic {
    @Id
    private Long id;
    @Field(name = "portfolio_name", type = FieldType.Text)
    private String portfolioName;
    @Field(name = "settl_date", type = FieldType.Date)
    private Date settlDate;
    @Field(name = "trscn_status", type = FieldType.Text)
    private String trscnStatus;
    // getters and setters 已省略
}

错误堆栈日志

15:49:41.488 [restartedMain] ERROR o.s.boot.SpringApplication - Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'techNeedsController': Unsatisfied dependency expressed through field 'elasticService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'transactionServiceElastic': Unsatisfied dependency expressed through field 'transactionElasticRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionElasticRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.MappingException: Couldn't find PersistentEntity for type class com.portal.domain.TransactionElastic!
...(省略重复堆栈内容)

转换器注册警告日志

o.s.data.convert.CustomConversions - Registering converter from class com.portal.domain.TransactionElastic to interface java.util.Map as writing converter although it doesn't convert to a store-supported type! You might wanna check you annotation setup at the converter implementation.
...(省略其他转换器日志)

环境版本

  • Spring Boot版本:2.2.1
  • Spring Data Elasticsearch版本:3.2.1
  • Elasticsearch版本:6.4.0

问题根源分析

  1. 实体类未被Spring Data扫描识别:虽然给TransactionElastic加了@Document注解,但如果实体所在包不在Spring的自动扫描范围内,Spring Data Elasticsearch无法加载该实体的元数据,自然找不到对应的PersistentEntity。
  2. 自定义EntityMapper破坏默认映射上下文:手动实现的EntityMapper没有正确关联到Spring Data的Elasticsearch映射上下文,导致实体的映射规则无法被正确加载。
  3. 转换器注册依赖实体元数据:因为实体未被识别,转换器注册时无法匹配到对应的存储类型,进而触发警告并引发后续的映射异常。

解决方案

1. 明确指定扫描范围

在配置类或启动类上添加注解,明确指定Repository和实体类的扫描路径,避免Spring漏扫:

@Configuration
@EnableElasticsearchRepositories(basePackages = "com.portal.repository") // 替换为你的Repository所在包
@EntityScan(basePackages = "com.portal.domain") // 替换为你的实体类所在包
public class ElasticConfig extends AbstractElasticsearchConfiguration {
    @Value("${elasticUrl}")
    private String elasticUrl;

    @Override
    public RestHighLevelClient elasticsearchClient() {
        return RestClients.create(ClientConfiguration.create(elasticUrl)).rest();
    }

    @Override
    public ElasticsearchCustomConversions elasticsearchCustomConversions() {
        return new ElasticsearchCustomConversions(Arrays.asList(new TransactionToMapConverter(), new MapToTransactionConverter()));
    }
}

2. 移除自定义的EntityMapper

AbstractElasticsearchConfiguration已经提供了默认的EntityMapper实现,手动定义的Bean会破坏默认的映射上下文关联,直接删除entityMapper()方法即可。

3. 验证Repository接口正确性

确保你的Repository接口正确继承ElasticsearchRepository,泛型参数匹配实体类和主键类型:

public interface TransactionElasticRepository extends ElasticsearchRepository<TransactionElastic, Long> {
    // 自定义查询方法按需添加
}

4. 检查转换器注解

确认转换器上的@WritingConverter和@ReadingConverter来自org.springframework.data.convert包,避免导入错误的注解。

做完以上调整后,重启项目,MappingException和转换器警告都会消失,实体能被正常识别,转换器也可以正常工作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 08:07:41