如何将MongoDB查询返回的Document转换为Kotlin Person模型类?
MongoDB分页查询转换为自定义Kotlin模型类列表的问题
问题背景
原本可正常运行的MongoDB分页查询Java代码,返回org.bson.Document列表:
List<Document> documents = collection.find() .skip(offset) .limit(limit) .into(new ArrayList<>());
现在希望返回自定义Kotlin模型类Person的列表,Person类定义如下:
@JsonInclude(JsonInclude.Include.NON_NULL) class Person { @JsonProperty("id") var id: Long? = null @JsonProperty("name") var name: String? = null }
但尝试直接修改泛型后出现编译错误:
List<Person> documents = collection.find() .skip(offset) .limit(limit) .into(new ArrayList<Person>());
错误信息:
Inferred type 'A' for type parameter 'A' is not within its bound; should implement 'java.util.Collection<? super org.bson.Document>'
使用的依赖版本:org.mongodb:bson:3.12.1
解决方案
方法1:原生驱动手动转换(最直接)
通过map方法对每个Document做手动转换,将字段值映射到Person对象:
List<Person> personList = collection.find() .skip(offset) .limit(limit) .map(document -> { Person person = new Person(); person.setId(document.getLong("id")); person.setName(document.getString("name")); return person; }) .into(new ArrayList<>());
方法2:借助Spring Data MongoDB自动映射(若使用Spring生态)
如果项目依赖Spring Data MongoDB,直接用MongoTemplate即可完成自动对象转换,无需手动处理字段映射:
List<Person> personList = mongoTemplate.find( Query.query(Criteria.where("").exists(true)) // 无查询条件时保留此写法,有条件则替换为实际查询规则 .skip(offset) .limit(limit), Person.class, "your_collection_name" // 替换为你的集合名称 );
方法3:注册自定义BSON编解码器(持久化映射方案)
通过注册自定义Codec,让MongoDB驱动自动完成Document与Person的双向转换,后续查询可直接返回Person类型:
- 实现
Codec<Person>接口:
public class PersonCodec implements Codec<Person> { private final Codec<Document> documentCodec; public PersonCodec() { this.documentCodec = MongoClient.getDefaultCodecRegistry().get(Document.class); } @Override public Person decode(BsonReader reader, DecoderContext decoderContext) { Document document = documentCodec.decode(reader, decoderContext); Person person = new Person(); person.setId(document.getLong("id")); person.setName(document.getString("name")); return person; } @Override public void encode(BsonWriter writer, Person person, EncoderContext encoderContext) { Document document = new Document(); if (person.getId() != null) { document.put("id", person.getId()); } if (person.getName() != null) { document.put("name", person.getName()); } documentCodec.encode(writer, document, encoderContext); } @Override public Class<Person> getEncoderClass() { return Person.class; } }
- 注册Codec并获取泛型集合:
CodecRegistry codecRegistry = CodecRegistries.fromRegistries( MongoClient.getDefaultCodecRegistry(), CodecRegistries.fromCodecs(new PersonCodec()) ); MongoClient mongoClient = MongoClients.create(MongoClientSettings.builder() .codecRegistry(codecRegistry) .build()); MongoCollection<Person> collection = mongoClient.getDatabase("your_db_name") .getCollection("your_collection_name", Person.class);
- 直接查询返回
Person列表:
List<Person> personList = collection.find() .skip(offset) .limit(limit) .into(new ArrayList<>());
方法4:用Jackson做JSON转换
借助Jackson的ObjectMapper将Document转为JSON字符串后再反序列化为Person对象:
ObjectMapper objectMapper = new ObjectMapper(); List<Person> personList = collection.find() .skip(offset) .limit(limit) .map(document -> { try { return objectMapper.readValue(document.toJson(), Person.class); } catch (JsonProcessingException e) { throw new RuntimeException("Document转Person失败", e); } }) .into(new ArrayList<>());
内容的提问来源于stack exchange,提问作者java12399900
相关产品推荐
相关产品推荐

