Mongo 4 ChangeStreamDocument<POJO>编译正常但运行时无法转为Morphia POJO
解决方案
原因分析
编译时编译器基于泛型声明认为getFullDocument()返回POJO.class,但Mongo驱动默认不会自动将ChangeStream中的Document实例转换为带有Morphia注解的POJO,运行时实际返回的是org.bson.Document,因此抛出类型转换异常。
优雅实现方案
方案1:利用Morphia Datastore手动转换
既然POJO已使用Morphia注解,直接借助Morphia的Datastore或Mapper完成Document到POJO的转换,这是最直接的方式:
// 假设已初始化Morphia的Datastore实例 private final Datastore datastore; private final Consumer<ChangeStreamDocument<Document>> log = el -> { LOG.info("{} deserialized Changestream Doc with wrapper: {}", this.collection, el.toString()); Document rawDoc = el.getFullDocument(); LOG.info("{} actual document object: {}", this.collection, rawDoc); // 用Morphia转换为POJO POJO pojo = datastore.getMapper().map(rawDoc, POJO.class); LOG.info("{} class of document object: {}", this.collection, pojo.getClass()); LOG.info("{} id of POJO document as fetched through POJO getter: {}", this.collection, pojo.getId()); };
注意将泛型从ChangeStreamDocument<POJO>改为ChangeStreamDocument<Document>,避免编译时的泛型误导,再显式完成类型转换。
方案2:配置Mongo驱动CodecRegistry集成Morphia
通过自定义CodecRegistry,让Mongo驱动自动将ChangeStream中的Document反序列化为Morphia注解的POJO,无需手动转换:
// 初始化Morphia和Mongo客户端时配置CodecRegistry Morphia morphia = new Morphia(); morphia.mapPackage("your.pojo.package"); // 扫描你的POJO所在包 MongoClientSettings settings = MongoClientSettings.builder() .codecRegistry(MongoClientSettings.getDefaultCodecRegistry()) // 添加Morphia的CodecProvider .codecRegistry(MorphiaCodecProvider.create(morphia).getCodecRegistry()) .build(); MongoClient mongoClient = MongoClients.create(settings);
之后创建ChangeStream时,泛型指定POJO即可自动反序列化,原Consumer代码可直接保留:
private final Consumer<ChangeStreamDocument<POJO>> log = el -> { LOG.info("{} deserialized Changestream Doc with wrapper: {}", this.collection, el.toString()); POJO pojo = el.getFullDocument(); LOG.info("{} actual document object: {}", this.collection, pojo); LOG.info("{} class of document object: {}", this.collection, pojo.getClass()); LOG.info("{} id of POJO document as fetched through POJO getter: {}", this.collection, pojo.getId()); };
方案3:封装转换工具类
如果不想修改Mongo客户端配置,可封装工具方法统一处理转换,保持Consumer代码简洁:
public class MorphiaConverter { private static final Mapper mapper; static { Morphia morphia = new Morphia(); morphia.mapPackage("your.pojo.package"); mapper = morphia.getMapper(); } public static <T> T convert(Document doc, Class<T> clazz) { return mapper.map(doc, clazz); } } // Consumer中使用 private final Consumer<ChangeStreamDocument<Document>> log = el -> { Document rawDoc = el.getFullDocument(); POJO pojo = MorphiaConverter.convert(rawDoc, POJO.class); // 后续业务逻辑同方案1 };
内容的提问来源于stack exchange,提问作者antonig
相关产品推荐
相关产品推荐

