首页 > 解决方案 > 带有 MongoDB Java 集合的动态 POJO 类型

问题描述

我们知道我们正在使用的特定类型时,我了解如何使用 MongoDB Java 驱动程序来读取和存储 POJO 。在我正在处理的项目中,编解码器提供程序(以及编解码器注册表)是由通过属性传入的类名构建的(有一些硬编码值)。这支持例如仅在进行测试(JUnit)时注销某些消息。

问题是我无法确定如何使用 MongoCollection 使用这种类型。下面是一个基于实际问题的玩具问题(我们有一个通用的“消息”接口,我们希望记录的所有 POJO 都实现该接口。日志记录函数接受该“消息”接口的对象并需要将其插入集合)。

首先我们有我们的界面:

public interface MyInterface {
    int getX();
}

和简单的实现:

public class ImplA implements MyInterface {
    public int getX(){return 1;}
}

然后使用它们的代码:

import com.mongodb.MongoClientSettings;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase;
import org.bson.codecs.pojo.ClassModel;
import org.bson.codecs.pojo.PojoCodecProvider;

import static org.bson.codecs.configuration.CodecRegistries.fromProviders;
import static org.bson.codecs.configuration.CodecRegistries.fromRegistries;

public class Main {

    public static void main(String[] args){
        new Main().run();
    }

    public void run(){
        MongoClient client = MongoClients.create("mongodb://localhost:27018");
        MongoDatabase db = client.getDatabase("db1").withCodecRegistry(fromRegistries(
                MongoClientSettings.getDefaultCodecRegistry(),
                fromProviders(PojoCodecProvider.builder().register(
                        ClassModel.builder(MyInterface.class).enableDiscriminator(true).build(),
                        ClassModel.builder(ImplA.class).enableDiscriminator(true).build()
                ).build())
        ));

        MyInterface obj1 = new ImplA();

        db.getCollection("ImplA",ImplA.class).insertOne((ImplA) obj1);
        db.getCollection("ImplA",obj1.getClass()).insertOne(obj1);
        db.getCollection("ImplA",Object.class).insertOne(obj1);
    }
}

在第一个插入编译时,第二个插入失败并出现以下错误:

错误:错误:行(42)java:不兼容的类型:Main.MyInterface 无法转换为 capture#1 of ?扩展 Main.MyInterface

在我看来,这个功能应该是可能的,因为 MongoCollection 肯定有关于类型的信息。传入的对象具有某种类型,我想要该类型的集合并插入它。如果第二个 insertOne 被注释掉,则代码编译。驱动程序抛出一个异常,说 Object 没有编解码器;因此,它肯定是从给定的内容中确定要使用的编解码器来获取集合。

更新:我曾尝试使用 getClass.cast 进行各种转换,各种泛型组合,但这里有一个可行的选项:

MyInterface obj1 = new ImplA();

Class<MyInterface> myC = (Class<MyInterface>) Class.forName(obj1.getClass().getName());
db.getCollection("ImplA",myC).insertOne(obj1);

这可能会引发类未找到异常,并且看起来不必要地复杂。

标签: javamongodbgenericspojomongodb-java

解决方案


尝试使用: db.getCollection("ImplA").withDocumentClass(obj1.getClass()).insertOne(obj1)


推荐阅读