Closed Homer1991 closed 4 years ago
Maybe you can help with a workaround because the converters are deleted
Interestingly after adding this:
datastore.getMapper().addInterceptor(new EntityInterceptor() {
@Override
public void preLoad(Object ent, Document document, Mapper mapper) {
System.out.println("test");
}
});
I get the following stack trace:
Exception in thread "main" java.lang.IllegalStateException: unknown type for bson mapping: class java.util.UUID
at dev.morphia.mapping.codec.reader.DocumentReader.getBsonType(DocumentReader.java:347)
at dev.morphia.mapping.codec.reader.ReaderState.getCurrentBsonType(ReaderState.java:97)
at dev.morphia.mapping.codec.reader.DocumentReader.getCurrentBsonType(DocumentReader.java:43)
at dev.morphia.mapping.codec.pojo.EntityDecoder.decodeModel(EntityDecoder.java:63)
at dev.morphia.mapping.codec.pojo.EntityDecoder.decodeProperties(EntityDecoder.java:88)
at dev.morphia.mapping.codec.pojo.EntityDecoder.decodeWithLifecycle(EntityDecoder.java:132)
at dev.morphia.mapping.codec.pojo.EntityDecoder.decode(EntityDecoder.java:38)
at dev.morphia.mapping.codec.pojo.MorphiaCodec.decode(MorphiaCodec.java:70)
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.receiveCommandMessageResponse(InternalStreamConnection.java:308)
at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:258)
at com.mongodb.internal.connection.UsageTrackingInternalConnection.sendAndReceive(UsageTrackingInternalConnection.java:99)
at com.mongodb.internal.connection.DefaultConnectionPool$PooledConnection.sendAndReceive(DefaultConnectionPool.java:500)
at com.mongodb.internal.connection.CommandProtocolImpl.execute(CommandProtocolImpl.java:71)
at com.mongodb.internal.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:224)
at com.mongodb.internal.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:202)
at com.mongodb.internal.connection.DefaultServerConnection.command(DefaultServerConnection.java:118)
at com.mongodb.internal.connection.DefaultServerConnection.command(DefaultServerConnection.java:110)
at com.mongodb.internal.operation.CommandOperationHelper.executeCommand(CommandOperationHelper.java:343)
at com.mongodb.internal.operation.CommandOperationHelper.executeCommand(CommandOperationHelper.java:334)
at com.mongodb.internal.operation.CommandOperationHelper.executeCommandWithConnection(CommandOperationHelper.java:220)
at com.mongodb.internal.operation.FindOperation$1.call(FindOperation.java:631)
at com.mongodb.internal.operation.FindOperation$1.call(FindOperation.java:625)
at com.mongodb.internal.operation.OperationHelper.withReadConnectionSource(OperationHelper.java:462)
at com.mongodb.internal.operation.FindOperation.execute(FindOperation.java:625)
at com.mongodb.internal.operation.FindOperation.execute(FindOperation.java:77)
at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:190)
at com.mongodb.client.internal.MongoIterableImpl.execute(MongoIterableImpl.java:135)
at com.mongodb.client.internal.MongoIterableImpl.iterator(MongoIterableImpl.java:92)
at dev.morphia.query.MorphiaQuery.prepareCursor(MorphiaQuery.java:335)
at dev.morphia.query.MorphiaQuery.iterator(MorphiaQuery.java:202)
at dev.morphia.query.MorphiaQuery.iterator(MorphiaQuery.java:197)
at de.code.common.morphia.test.Test.main(Test.java:54)
And in the debugger i can see that the Document now already has mapped it to UUID:
But in a later step he again tries to map the UUID to BsonBinary
I also tried adding the UUID Codec but this makes no difference:
CodecRegistry codecRegistry = CodecRegistries.fromRegistries(
CodecRegistries.fromProviders(new UuidCodecProvider(UuidRepresentation.STANDARD)),
MongoClientSettings.getDefaultCodecRegistry());
final Datastore datastore = Morphia.createDatastore(
MongoClients.create(MongoClientSettings.builder()
.applyConnectionString(new ConnectionString("mongodb://127.0.0.1/"))
.uuidRepresentation(UuidRepresentation.STANDARD).codecRegistry(codecRegistry).build()),
"morphia_example");
UUIDs should work out of the box in 2.0 since Morphia just delegates to the driver's codecs. Check the guide for more information: https://mongodb.github.io/mongo-java-driver/4.1/upgrading/
I'm facing a similar issue where I have an enum field inside an entity. Maybe it's related to the above issue.. That enum has to decode/encode using a final field inside the enum and not the name of the enum. With @Converters was working but with the new way of codecs it does not, but perhaps I'm doing something wrong. What I did is I created a codec CustomEnumCodec by extending the EnumCodec and I have applied it in the following way.
final CodecRegistry codecRegistry = CodecRegistries
.fromRegistries(MongoClientSettings.getDefaultCodecRegistry(),
CodecRegistries.fromCodecs(new CustomEnumCodec()));
MongoClientSettings.builder().codecRegistry(codecRegistry);
Is that correct?
It's not about handeling UUID
. The problem is that the field is not recognized as type UUID
:
For example here:
@Entity
public class GenericEntity<T> {
@Id
protected T id;
protected T test;
protected UUID test2;
}
The field test2
works as intended. The problem is the recognition of generic types.
Also as i mentioned here the driver seems to do everything correctly the field comes back as UUID but morphia then can not handle it: https://github.com/MorphiaOrg/morphia/issues/1481#issuecomment-684782384
@evanchooly do you have any idea what the problem is here?
I started digging in to this last night actually. I have beginnings of an idea but I'll have to dig in a bit deeper.
Nice thanks for looking into this.
@evanchooly
I'm not sure if this a valid solution, but i figured out that after reversing the hirarchy set in dev.morphia.mapping.codec.pojo.EntityModelBuilder.java:241 protected void configure()
the mapping works as expected. I used the 2.0.x
branch.
protected void configure() {
TypeData<?> parentClassTypeData = null;
Set<Class<?>> classes = buildHierarchy(type);
Map<String, TypeParameterMap> propertyTypeParameterMap = new HashMap<>();
List<Class<?>> classesArray = new ArrayList<Class<?>>(classes);
Collections.reverse(classesArray);
List<Annotation> annotations = new ArrayList<>();
for (Class<?> klass : classesArray) {
List<String> genericTypeNames = processTypeNames(klass);
annotations.addAll(List.of(klass.getDeclaredAnnotations()));
processFields(klass, parentClassTypeData, genericTypeNames, propertyTypeParameterMap);
parentClassTypeData = TypeData.newInstance(klass.getGenericSuperclass(), klass);
}
annotations(annotations);
}
and my testcase in the dev.morphia.test.TestMapping
looks like
@Test
public void testRecursiveGeneric() {
getMapper().map(SpecificEntity.class);
SpecificEntity beforeDb = new SpecificEntity();
beforeDb.setId(UUID.randomUUID());
beforeDb.setTest(UUID.randomUUID());
beforeDb.setTest2(UUID.randomUUID());
getDs().save(beforeDb);
SpecificEntity fromDB = getDs().find(SpecificEntity.class).filter(Filters.eq("_id", beforeDb.getId()))
.iterator().next();
assertEquals(beforeDb.getId(), fromDB.getId());
assertEquals(beforeDb.getTest(), fromDB.getTest());
assertEquals(beforeDb.getTest2(), fromDB.getTest2());
}
@Entity
public static class GenericEntity<T> {
@Id
protected T id;
protected T test;
protected UUID test2;
public T getId() {
return id;
}
public void setId(T id) {
this.id = id;
}
public T getTest() {
return test;
}
public void setTest(T test) {
this.test = test;
}
public UUID getTest2() {
return test2;
}
public void setTest2(UUID test2) {
this.test2 = test2;
}
}
@Entity
public static class SpecificEntity extends GenericEntity<UUID> {
}
That is, more or less, what I'd discovered last night, too, before I was too tired to finish testing. :) Nice work.
Mapping does not work with generic types Using generic types in the
@Entity
does not work. The UUID gets correctly stored in MongoDB but when reading the Document is not correctly mapped to UUID.To Reproduce Generic Entity:
Specific Entity:
Main-Class:
Output:
Expected behavior Fields are mapped to the correct type.