问题
I have a POJO class which looks like this-
public class CacheEntity<V> {
private String cacheId;
private V value;
public static final String ID_KEY = "cacheId";
public CacheEntity() {
}
public CacheEntity(String cache_id, V value) {
this.cacheId = cache_id;
this.value = value;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
public String getCacheId() {
return cacheId;
}
public void setCacheId(String cacheId) {
this.cacheId = cacheId;
}
}
I am using official driver mongodb-driver-sync version 3.8.1
As mentioned in the documentation here, I am using CodecRegistry with automatic PojoCodecProvider. I am getting the following error when I try to persist this entity.
Exception in thread "main" org.bson.codecs.configuration.CodecConfigurationException: CacheEntity contains generic types that have not been specialised.
Top level classes with generic types are not supported by the PojoCodec.
at org.bson.codecs.pojo.PojoCodecImpl.encode(PojoCodecImpl.java:93)
at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:63)
at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:29)
at com.mongodb.operation.BulkWriteBatch$WriteRequestEncoder.encode(BulkWriteBatch.java:398)
at com.mongodb.operation.BulkWriteBatch$WriteRequestEncoder.encode(BulkWriteBatch.java:377)
at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:63)
at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:29)
at com.mongodb.internal.connection.BsonWriterHelper.writeDocument(BsonWriterHelper.java:75)
at com.mongodb.internal.connection.BsonWriterHelper.writePayload(BsonWriterHelper.java:59)
at com.mongodb.internal.connection.CommandMessage.encodeMessageBodyWithMetadata(CommandMessage.java:143)
at com.mongodb.internal.connection.RequestMessage.encode(RequestMessage.java:138)
at com.mongodb.internal.connection.CommandMessage.encode(CommandMessage.java:57)
at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:244)
at com.mongodb.internal.connection.UsageTrackingInternalConnection.sendAndReceive(UsageTrackingInternalConnection.java:99)
at com.mongodb.internal.connection.DefaultConnectionPool$PooledConnection.sendAndReceive(DefaultConnectionPool.java:444)
at com.mongodb.internal.connection.CommandProtocolImpl.execute(CommandProtocolImpl.java:72)
at com.mongodb.internal.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:200)
at com.mongodb.internal.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:269)
at com.mongodb.internal.connection.DefaultServerConnection.command(DefaultServerConnection.java:131)
at com.mongodb.operation.MixedBulkWriteOperation.executeCommand(MixedBulkWriteOperation.java:418)
at com.mongodb.operation.MixedBulkWriteOperation.executeBulkWriteBatch(MixedBulkWriteOperation.java:256)
at com.mongodb.operation.MixedBulkWriteOperation.access$700(MixedBulkWriteOperation.java:67)
at com.mongodb.operation.MixedBulkWriteOperation$1.call(MixedBulkWriteOperation.java:200)
at com.mongodb.operation.MixedBulkWriteOperation$1.call(MixedBulkWriteOperation.java:191)
at com.mongodb.operation.OperationHelper.withReleasableConnection(OperationHelper.java:419)
at com.mongodb.operation.MixedBulkWriteOperation.execute(MixedBulkWriteOperation.java:191)
at com.mongodb.operation.MixedBulkWriteOperation.execute(MixedBulkWriteOperation.java:67)
at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:193)
at com.mongodb.client.internal.MongoCollectionImpl.executeSingleWriteRequest(MongoCollectionImpl.java:960)
at com.mongodb.client.internal.MongoCollectionImpl.executeReplaceOne(MongoCollectionImpl.java:602)
at com.mongodb.client.internal.MongoCollectionImpl.replaceOne(MongoCollectionImpl.java:578)
at com.mongodb.client.internal.MongoCollectionImpl.replaceOne(MongoCollectionImpl.java:567)
What can I do to make this work? Thank You.
回答1:
There are following options to make it working.
By subclassing
If you subclass with concrete generic type each time, it works:
public class MyClassCacheEntity extends CacheEntity<MyClass> {}
By using BsonDocument
+ Jackson
To avoid subclassing you can try store arbitrary objects as BsonDocument
-s and serialize/deserialize them using Jackson:
public class CacheEntity<V> {
private String cacheId;
private BsonDocument rawValue;
// [...]
// sets the value
public void withValue(T o) {
this.rawValue = BsonDocument.parse(new ObjectMapper().writeValueAsString(o))
}
// recovers the value
public T value(Class<T> clazz) {
return new ObjectMapper().readValue(this.rawValue.toJson(), clazz);
}
}
This works until you avoid getters/setters convention for withValue()
and value()
methods, otherwise Mongo starts to complain about the same generics issue.
Same with pure bson
I think, you can also try to do it the same as above using org.bson.codecs.pojo.PojoCodec
which you can either create or extract from the current mongo codecs registry. If you know in advance and give it the real class, it shouldn't complain about generics.
来源:https://stackoverflow.com/questions/52197137/mongodb-java-perist-pojo-class-with-generic-field