Spring Boot Data REST对接MongoDB遇Binary转UUID转换器缺失问题求助
我有一个基于Spring Boot的标准微服务,采用Spring Data REST对接单个MongoDB固定大小集合(capped collection),文档包含UUID字段。本地构建运行正常,但生产环境Docker中启动时抛出如下错误:
{"timestamp":"2023-01-13T15:10:01.592Z","message":"Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.bson.types.Binary] to type [java.util.UUID]] with root cause", "component":"org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet]","level":"ERROR","stack_trace":"org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.bson.types.Binary] to type [java.util.UUID]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:322)...
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.doConvert(MappingMongoConverter.java:1826)...
at org.springframework.data.mongodb.repository.support.SimpleMongoRepository.findAll(SimpleMongoRepository.java:444)
疑问
- 该如何处理此问题?能否通过Spring配置解决?
- 为何应用启动时会调用
SimpleMongoRepository.findAll()? - 我们有多个对接MongoDB的应用运行正常,为何Spring Data REST会出现此问题?
- 为何构建正常,但容器启动时失败?
相关代码与配置
仓库定义
@RepositoryRestResource( collectionResourceRel = 'events', path = 'events' ) interface EventRepository extends MongoRepository<EventMessage, String> { }
集合配置
class CustomApplicationRunner implements ApplicationRunner { @Autowired MongoTemplate mongoTemplate @Autowired ApplicationProperties configuration @Override void run(ApplicationArguments args) throws Exception { mongoTemplate.writeResultChecking = WriteResultChecking.EXCEPTION if ( !mongoTemplate.collectionExists( EventMessage ) ) { mongoTemplate.createCollection(EventMessage, new CollectionOptions( configuration.mongoCollectionMaxSizeBytes, configuration.mongoCollectionMaxDocuments, configuration.mongoCappedCollection ) ) } } }
开发环境MongoDB配置(application.yml)
mongodb: uri: mongodb://mongodb:27017/development auto-index-creation: true uuid-representation: STANDARD authentication-database: admin
Spring Boot依赖
dependencies { implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-amqp' implementation 'org.springframework.boot:spring-boot-starter-data-mongodb' implementation 'org.springframework.boot:spring-boot-starter-integration' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-data-rest' testImplementation 'org.springframework.boot:spring-boot-starter-test' }
版本信息
- SpringBoot 2.7.7
- Groovy 4.0.6
已做调研
- MongoDB驱动曾有关于Binary与UUID互转的问题,但仅更新了BsonBinary的转换支持,未覆盖
org.bson.types.Binary场景。 - Spring Data MongoDB的相关问题中有人提供了自定义转换器的解决方案,但不确定是否为唯一方案。
1. 问题处理方案(含配置方式)
优先检查配置一致性
首先确认生产环境的uuid-representation配置是否为STANDARD。如果生产环境该配置缺失或值不正确,MongoDB驱动会用旧的UUID存储格式(将UUID转为Binary类型),而Spring Data无法自动转换这种格式到UUID。另外注意Spring Boot 2.x中该配置的正确前缀是spring.data.mongodb,补充生产环境的application.yml配置:
spring: data: mongodb: uuid-representation: STANDARD
自定义转换器(配置无法解决时)
如果配置正确但问题依旧,需要手动添加Binary到UUID的转换器:
import org.bson.types.Binary import org.springframework.core.convert.converter.Converter import org.springframework.data.convert.ReadingConverter import java.util.UUID @ReadingConverter class BinaryToUuidConverter implements Converter<Binary, UUID> { @Override UUID convert(Binary source) { if (source == null) { return null } // 根据实际存储格式调整:如果是UUID直接转的字节,可改用new UUID(bytes[0..7], bytes[8..15]) return UUID.nameUUIDFromBytes(source.getData()) } }
然后注册转换器到Mongo配置:
import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.data.mongodb.core.convert.MongoCustomConversions @Configuration class MongoConfig { @Bean MongoCustomConversions mongoCustomConversions() { return new MongoCustomConversions([new BinaryToUuidConverter()]) } }
2. 启动时调用findAll()的原因
Spring Data REST在启动时会为暴露的Repository生成HAL元数据,其中会尝试获取集合的样本数据来生成响应的Schema(比如/events接口的OPTIONS请求元数据)。如果你的固定大小集合已有数据,启动时Spring Data REST会触发findAll()来获取样本,进而触发类型转换。
3. Spring Data REST单独出问题的原因
其他对接MongoDB的应用可能没有使用Spring Data REST的自动元数据生成逻辑,不会在启动时主动查询集合数据;或者它们的UUID字段是用STANDARD格式存储为BsonBinary,而非旧的Binary类型。而Spring Data REST的启动元数据生成会主动触发数据查询,暴露了转换问题。
4. 构建正常但容器启动失败的原因
构建阶段仅做编译和依赖检查,不会实际连接MongoDB并执行数据查询。容器启动时,应用会初始化Spring上下文、连接MongoDB,同时Spring Data REST触发元数据生成查询,此时才会读取集合中的数据,触发类型转换错误。而本地环境可能集合中没有数据(或数据是用STANDARD格式存储的),所以启动时不会触发转换问题。
内容的提问来源于stack exchange,提问作者Serhii Mormul

