Mongodb 多态性 Java 对象无法确定具体 class
Mongodb polymorphism Java object unable to determine concrete class
我在 Micronaut 中使用 Mongodb,读取多态 Java 对象时出错,因为 Mongodb 无法通过其类型确定具体实现 class。
myPet: { "_id" : ObjectId("5f96f4633dbd690c548c2a38"), pets: [{"type" : "Cat" }, {"type" : "Dog" }]}
public class MyPet {
private List<Animal> pets = new ArrayList<Animal>(0);
public List<Animal> getPets() {
return pets;
}
public void setPets(List<Animal> pets) {
this.pets = pets;
}
}
public class Cat implements Animal {
private String type = "Cat";
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
public class Dog implements Animal {
private String type = "Dog";
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
public interface Animal {
String getType();
}
我试过了
MongoCollection<MyPet> myPetColl = db.getCollection("myPet", MyPet.class);
myPetColl.find()
但低于错误
Unexpected error occurred: An exception occurred when decoding using the AutomaticPojoCodec.
Decoding into a 'MyPet' failed with the following exception:
Failed to decode 'MyPet'. Decoding 'content' errored with: Cannot find a public constructor for 'Animal'.
A custom Codec or PojoCodec may need to be explicitly configured and registered to handle this type.
org.bson.codecs.configuration.CodecConfigurationException: An exception occurred when decoding using the AutomaticPojoCodec.
Decoding into a 'MyPet' failed with the following exception:
Failed to decode 'MyPet'. Decoding 'content' errored with: Cannot find a public constructor for 'Animal'.
A custom Codec or PojoCodec may need to be explicitly configured and registered to handle this type.
at org.bson.codecs.pojo.AutomaticPojoCodec.decode(AutomaticPojoCodec.java:40)
at com.mongodb.internal.operation.CommandResultArrayCodec.decode(CommandResultArrayCodec.java:52)
at com.mongodb.internal.operation.CommandResultDocumentCodec.readValue(CommandResultDocumentCodec.java:60)
at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:84)
at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:41)
at org.bson.internal.LazyCodec.decode(LazyCodec.java:48)
at org.bson.codecs.BsonDocumentCodec.readValue(BsonDocumentCodec.java:101)
at com.mongodb.internal.operation.CommandResultDocumentCodec.readValue(CommandResultDocumentCodec.java:63)
at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:84)
at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:41)
at com.mongodb.internal.connection.ReplyMessage.<init>(ReplyMessage.java:51)
at com.mongodb.internal.connection.InternalStreamConnection.getCommandResult(InternalStreamConnection.java:412)
at com.mongodb.internal.connection.InternalStreamConnection.access0(InternalStreamConnection.java:75)
at com.mongodb.internal.connection.InternalStreamConnection.onResult(InternalStreamConnection.java:397)
at com.mongodb.internal.connection.InternalStreamConnection.onResult(InternalStreamConnection.java:375)
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback$MessageCallback.onResult(InternalStreamConnection.java:676)
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback$MessageCallback.onResult(InternalStreamConnection.java:643)
at com.mongodb.internal.connection.InternalStreamConnection.completed(InternalStreamConnection.java:513)
at com.mongodb.internal.connection.InternalStreamConnection.completed(InternalStreamConnection.java:510)
at com.mongodb.internal.connection.AsynchronousChannelStream$BasicCompletionHandler.completed(AsynchronousChannelStream.java:230)
at com.mongodb.internal.connection.AsynchronousChannelStream$BasicCompletionHandler.completed(AsynchronousChannelStream.java:213)
at java.base/sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:127)
at java.base/sun.nio.ch.Invoker.invokeDirect(Invoker.java:158)
at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.implRead(UnixAsynchronousSocketChannelImpl.java:560)
at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:277)
at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:298)
at com.mongodb.internal.connection.AsynchronousSocketChannelStream$AsynchronousSocketChannelAdapter.read(AsynchronousSocketChannelStream.java:136)
at com.mongodb.internal.connection.AsynchronousChannelStream.readAsync(AsynchronousChannelStream.java:109)
at com.mongodb.internal.connection.InternalStreamConnection.readAsync(InternalStreamConnection.java:510)
at com.mongodb.internal.connection.InternalStreamConnection.access00(InternalStreamConnection.java:75)
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback.onResult(InternalStreamConnection.java:633)
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback.onResult(InternalStreamConnection.java:618)
at com.mongodb.internal.connection.InternalStreamConnection.completed(InternalStreamConnection.java:513)
at com.mongodb.internal.connection.InternalStreamConnection.completed(InternalStreamConnection.java:510)
at com.mongodb.internal.connection.AsynchronousChannelStream$BasicCompletionHandler.completed(AsynchronousChannelStream.java:230)
at com.mongodb.internal.connection.AsynchronousChannelStream$BasicCompletionHandler.completed(AsynchronousChannelStream.java:213)
at java.base/sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:127)
at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.finishRead(UnixAsynchronousSocketChannelImpl.java:437)
at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.finish(UnixAsynchronousSocketChannelImpl.java:191)
at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.onEvent(UnixAsynchronousSocketChannelImpl.java:213)
at java.base/sun.nio.ch.KQueuePort$EventHandlerTask.run(KQueuePort.java:312)
at java.base/sun.nio.ch.AsynchronousChannelGroupImpl.run(AsynchronousChannelGroupImpl.java:112)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
有没有办法 return 使用 if-condition:return 正确的 class 类型:
if (obj.type == "狗") return Dog.class else Cat.class
就像杰克逊一样
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "Dog"),
@JsonSubTypes.Type(value = Cat.class, name = "Cat"),
})
您可以使用 @BsonDiscriminator
注释来告诉 MongoDB 驱动程序哪个字段用作鉴别器键。这是一个工作示例:
import org.bson.codecs.pojo.annotations.BsonDiscriminator;
@BsonDiscriminator(key = Animal.DISCRIMINATOR_KEY)
public interface Animal {
String DISCRIMINATOR_KEY = "type";
String getType();
}
public class Cat implements Animal {
@Override
public String getType() {
return Cat.class.getName();
}
}
public class Dog implements Animal {
@Override
public String getType() {
return Dog.class.getName();
}
}
如您所见,我使用完整的 class 名称作为 type
字段的值。不幸的是,自定义鉴别器值(不同于完整 class 名称)现在在 Micronaut MongoDB 客户端中尚不可用。就是因为这个问题,还没解决:https://github.com/micronaut-projects/micronaut-mongodb/issues/10
我在 Micronaut 中使用 Mongodb,读取多态 Java 对象时出错,因为 Mongodb 无法通过其类型确定具体实现 class。
myPet: { "_id" : ObjectId("5f96f4633dbd690c548c2a38"), pets: [{"type" : "Cat" }, {"type" : "Dog" }]}
public class MyPet {
private List<Animal> pets = new ArrayList<Animal>(0);
public List<Animal> getPets() {
return pets;
}
public void setPets(List<Animal> pets) {
this.pets = pets;
}
}
public class Cat implements Animal {
private String type = "Cat";
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
public class Dog implements Animal {
private String type = "Dog";
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
public interface Animal {
String getType();
}
我试过了
MongoCollection<MyPet> myPetColl = db.getCollection("myPet", MyPet.class);
myPetColl.find()
但低于错误
Unexpected error occurred: An exception occurred when decoding using the AutomaticPojoCodec.
Decoding into a 'MyPet' failed with the following exception:
Failed to decode 'MyPet'. Decoding 'content' errored with: Cannot find a public constructor for 'Animal'.
A custom Codec or PojoCodec may need to be explicitly configured and registered to handle this type.
org.bson.codecs.configuration.CodecConfigurationException: An exception occurred when decoding using the AutomaticPojoCodec.
Decoding into a 'MyPet' failed with the following exception:
Failed to decode 'MyPet'. Decoding 'content' errored with: Cannot find a public constructor for 'Animal'.
A custom Codec or PojoCodec may need to be explicitly configured and registered to handle this type.
at org.bson.codecs.pojo.AutomaticPojoCodec.decode(AutomaticPojoCodec.java:40)
at com.mongodb.internal.operation.CommandResultArrayCodec.decode(CommandResultArrayCodec.java:52)
at com.mongodb.internal.operation.CommandResultDocumentCodec.readValue(CommandResultDocumentCodec.java:60)
at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:84)
at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:41)
at org.bson.internal.LazyCodec.decode(LazyCodec.java:48)
at org.bson.codecs.BsonDocumentCodec.readValue(BsonDocumentCodec.java:101)
at com.mongodb.internal.operation.CommandResultDocumentCodec.readValue(CommandResultDocumentCodec.java:63)
at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:84)
at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:41)
at com.mongodb.internal.connection.ReplyMessage.<init>(ReplyMessage.java:51)
at com.mongodb.internal.connection.InternalStreamConnection.getCommandResult(InternalStreamConnection.java:412)
at com.mongodb.internal.connection.InternalStreamConnection.access0(InternalStreamConnection.java:75)
at com.mongodb.internal.connection.InternalStreamConnection.onResult(InternalStreamConnection.java:397)
at com.mongodb.internal.connection.InternalStreamConnection.onResult(InternalStreamConnection.java:375)
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback$MessageCallback.onResult(InternalStreamConnection.java:676)
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback$MessageCallback.onResult(InternalStreamConnection.java:643)
at com.mongodb.internal.connection.InternalStreamConnection.completed(InternalStreamConnection.java:513)
at com.mongodb.internal.connection.InternalStreamConnection.completed(InternalStreamConnection.java:510)
at com.mongodb.internal.connection.AsynchronousChannelStream$BasicCompletionHandler.completed(AsynchronousChannelStream.java:230)
at com.mongodb.internal.connection.AsynchronousChannelStream$BasicCompletionHandler.completed(AsynchronousChannelStream.java:213)
at java.base/sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:127)
at java.base/sun.nio.ch.Invoker.invokeDirect(Invoker.java:158)
at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.implRead(UnixAsynchronousSocketChannelImpl.java:560)
at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:277)
at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:298)
at com.mongodb.internal.connection.AsynchronousSocketChannelStream$AsynchronousSocketChannelAdapter.read(AsynchronousSocketChannelStream.java:136)
at com.mongodb.internal.connection.AsynchronousChannelStream.readAsync(AsynchronousChannelStream.java:109)
at com.mongodb.internal.connection.InternalStreamConnection.readAsync(InternalStreamConnection.java:510)
at com.mongodb.internal.connection.InternalStreamConnection.access00(InternalStreamConnection.java:75)
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback.onResult(InternalStreamConnection.java:633)
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback.onResult(InternalStreamConnection.java:618)
at com.mongodb.internal.connection.InternalStreamConnection.completed(InternalStreamConnection.java:513)
at com.mongodb.internal.connection.InternalStreamConnection.completed(InternalStreamConnection.java:510)
at com.mongodb.internal.connection.AsynchronousChannelStream$BasicCompletionHandler.completed(AsynchronousChannelStream.java:230)
at com.mongodb.internal.connection.AsynchronousChannelStream$BasicCompletionHandler.completed(AsynchronousChannelStream.java:213)
at java.base/sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:127)
at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.finishRead(UnixAsynchronousSocketChannelImpl.java:437)
at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.finish(UnixAsynchronousSocketChannelImpl.java:191)
at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.onEvent(UnixAsynchronousSocketChannelImpl.java:213)
at java.base/sun.nio.ch.KQueuePort$EventHandlerTask.run(KQueuePort.java:312)
at java.base/sun.nio.ch.AsynchronousChannelGroupImpl.run(AsynchronousChannelGroupImpl.java:112)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
有没有办法 return 使用 if-condition:return 正确的 class 类型:
if (obj.type == "狗") return Dog.class else Cat.class
就像杰克逊一样
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "Dog"),
@JsonSubTypes.Type(value = Cat.class, name = "Cat"),
})
您可以使用 @BsonDiscriminator
注释来告诉 MongoDB 驱动程序哪个字段用作鉴别器键。这是一个工作示例:
import org.bson.codecs.pojo.annotations.BsonDiscriminator;
@BsonDiscriminator(key = Animal.DISCRIMINATOR_KEY)
public interface Animal {
String DISCRIMINATOR_KEY = "type";
String getType();
}
public class Cat implements Animal {
@Override
public String getType() {
return Cat.class.getName();
}
}
public class Dog implements Animal {
@Override
public String getType() {
return Dog.class.getName();
}
}
如您所见,我使用完整的 class 名称作为 type
字段的值。不幸的是,自定义鉴别器值(不同于完整 class 名称)现在在 Micronaut MongoDB 客户端中尚不可用。就是因为这个问题,还没解决:https://github.com/micronaut-projects/micronaut-mongodb/issues/10