I’m trying to map objects via Morphia (MongoDB). This works fine, they are correctly in the database and I can load them from the database. But as soon as I restart my application, I get following exception when I try to load them:
Exception in thread "pool-1-thread-1"
org.bson.codecs.configuration.CodecConfigurationException:
Failed to decode 'ClassB'. Decoding errored with:
A class could not be found for the discriminator: 'ClassA'.
Tracestack:
Exception in thread "pool-1-thread-1" org.bson.codecs.configuration.CodecConfigurationException: Failed to decode 'ClassB'. Decoding errored with: A class could not be found for the discriminator: 'ClassA'.
at dev.morphia.mapping.codec.pojo.EntityDecoder.getCodecFromDocument(EntityDecoder.java:110)
at dev.morphia.mapping.codec.pojo.EntityDecoder.getCodecFromDocument(EntityDecoder.java:110)
at dev.morphia.mapping.codec.pojo.EntityDecoder.decode(EntityDecoder.java:46)
at dev.morphia.mapping.codec.pojo.MorphiaCodec.decode(MorphiaCodec.java:66)
at dev.morphia.mapping.codec.CollectionCodec.decode(CollectionCodec.java:56)
at dev.morphia.mapping.codec.MorphiaCollectionCodec.decode(MorphiaCollectionCodec.java:22)
at dev.morphia.mapping.codec.MorphiaCollectionCodec.decode(MorphiaCollectionCodec.java:11)
at org.bson.codecs.DecoderContext.decodeWithChildContext(DecoderContext.java:96)
at dev.morphia.mapping.codec.pojo.EntityDecoder.decodeModel(EntityDecoder.java:66)
at dev.morphia.mapping.codec.pojo.EntityDecoder.decodeProperties(EntityDecoder.java:87)
at dev.morphia.mapping.codec.pojo.EntityDecoder.decode(EntityDecoder.java:43)
at dev.morphia.mapping.codec.pojo.MorphiaCodec.decode(MorphiaCodec.java:66)
at dev.morphia.mapping.codec.pojo.EntityDecoder.decode(EntityDecoder.java:48)
at dev.morphia.mapping.codec.pojo.MorphiaCodec.decode(MorphiaCodec.java:66)
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:87)
at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:42)
at org.bson.internal.LazyCodec.decode(LazyCodec.java:48)
at org.bson.codecs.BsonDocumentCodec.readValue(BsonDocumentCodec.java:104)
at com.mongodb.internal.operation.CommandResultDocumentCodec.readValue(CommandResultDocumentCodec.java:63)
at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:87)
at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:42)
at com.mongodb.internal.connection.ReplyMessage.<init>(ReplyMessage.java:51)
at com.mongodb.internal.connection.InternalStreamConnection.getCommandResult(InternalStreamConnection.java:476)
at com.mongodb.internal.connection.InternalStreamConnection.receiveCommandMessageResponse(InternalStreamConnection.java:366)
at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:279)
at com.mongodb.internal.connection.UsageTrackingInternalConnection.sendAndReceive(UsageTrackingInternalConnection.java:100)
at com.mongodb.internal.connection.DefaultConnectionPool$PooledConnection.sendAndReceive(DefaultConnectionPool.java:490)
at com.mongodb.internal.connection.CommandProtocolImpl.execute(CommandProtocolImpl.java:71)
at com.mongodb.internal.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:253)
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:345)
at com.mongodb.internal.operation.CommandOperationHelper.executeCommand(CommandOperationHelper.java:336)
at com.mongodb.internal.operation.CommandOperationHelper.executeCommandWithConnection(CommandOperationHelper.java:222)
at com.mongodb.internal.operation.FindOperation$1.call(FindOperation.java:658)
at com.mongodb.internal.operation.FindOperation$1.call(FindOperation.java:652)
at com.mongodb.internal.operation.OperationHelper.withReadConnectionSource(OperationHelper.java:583)
at com.mongodb.internal.operation.FindOperation.execute(FindOperation.java:652)
at com.mongodb.internal.operation.FindOperation.execute(FindOperation.java:80)
at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:170)
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:320)
at dev.morphia.query.MorphiaQuery.iterator(MorphiaQuery.java:201)
at dev.morphia.query.MorphiaQuery.iterator(MorphiaQuery.java:196)
at dev.morphia.query.MorphiaQuery.iterator(MorphiaQuery.java:41)
at java.base/java.lang.Iterable.forEach(Iterable.java:74)
at mypacket.DatabaseManager.get(DatabaseManager.java:76)
This exception occurs while loading data. I found out that it only occurs if I don’t save data to the db before. I could break down the problem to following code:
ClassA:
@NoArgsConstructor
@Entity
public class ClassA extends ClassB {
public ClassA(String value) {
super(value);
}
}
ClassB:
@RequiredArgsConstructor
@NoArgsConstructor
@Entity
public class ClassB {
@Id
private int id = 0;
@NonNull
private String value;
}
ContainerClass:
@Entity
public class ContainerClass {
@Id @AutoID
private int id;
@Getter
private List<ClassB> list = new ArrayList<>();
}
DB connection:
datastore = Morphia.createDatastore(MongoClients.create(), "myproject");
Mapper mapper = datastore.getMapper();
mapper.mapPackage("mypacket");
datastore.ensureIndexes();
Saving data:
ContainerClass c = new ContainerClass();
c.getList().add(new ClassA("A class 1"));
c.getList().add(new ClassB("B class 1"));
datastore.save(c);
Loading data:
List<ContainerClass> list = get(ContainerClass.class);
System.out.println("found " + list.size() + " elements");
public static <T> List<T> get(Class<T> clazz) {
List<T> list = new ArrayList<>();
datastore.find(clazz).forEach(e -> list.add(e));
return list;
}
A:
When I save (only one object) before I load all data. This works fine: found X elements
B: When I only try to load data without saving before I get the exception above.
{
"_id": 0,
"_t": "ContainerClass",
"list": [{
"_id": 0,
"_t": "ClassA",
"value": "A class 1"
}, {
"_id": 0,
"_t": "ClassB",
"value": "B class 1"
}]
}
Envirement:
Assess the cause of the problem:
This looks like a bug to me. The affected classes cannot be 'loaded' correctly during the start. Anyhow morphia solves this problem itself temporary as soon as an object has been mapped.
You should always map your entities as part of initialization. Without that, Morphia won't know what to map that discriminator to.