当我们知道我们正在使用的特定类型时,我了解如何使用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 无法转换为捕获 #1 的 ? 扩展主界面
在我看来,此功能应该是可能的,因为MongoCollection肯定有关于该类型的信息。传入的对象具有某种类型,我想要该类型的集合并插入它。如果第二个插入被注释掉,则代码将编译。驱动程序引发异常,指出对象没有编解码器;因此,它肯定是从给定的内容中确定要使用的编解码器以获取集合。
更新:我已经尝试了各种 getClass.cast 的转换,各种泛型组合,但这里有一个有效的选项:
MyInterface obj1 = new ImplA();
Class<MyInterface> myC = (Class<MyInterface>) Class.forName(obj1.getClass().getName());
db.getCollection("ImplA",myC).insertOne(obj1);
这可能会引发未找到的类异常,并且看起来不必要地复杂。
尝试使用:db.getCollection("ImplA").withDocumentClass(obj1.getClass()).insertOne(obj1)