Unable to read polymorphic types with Morphia with or without the default discriminator
Server Version: 8.0.4 Driver Version: 4.11.5 Morphia Version: 2.4.15
So I have a simple structure:
Interceptor.java
@Entity(discriminatorKey = "type")
public abstract class Interceptor {
@Id
protected String id;
protected String type;
public Interceptor(String type) {
this.type = type;
}
// getters and setters omitted..
}
It's subclasses:
ScriptInterceptor.java
@Entity(discriminator = "script", discriminatorKey = "type")
public class ScriptInterceptor extends Interceptor {
private String language;
private String source;
public ScriptInterceptor() {
super("script");
}
// getters and setters omitted...
}
XsltInterceptor.java
@Entity(discriminator = "xslt", discriminatorKey = "type")
public class XsltInterceptor extends Interceptor {
private String source;
public XsltInterceptor() {
super("xslt");
}
// getters and setters omitted...
}
The document is successfully inserted, but when reading it seems that Morphia is unable to deserialize it. The document looks like this:
The error I'm getting is:
Caused by: org.bson.codecs.configuration.CodecConfigurationException: Failed to decode 'Interceptor'. Decoding errored with: my.package.ScriptInterceptor
............
Caused by: dev.morphia.mapping.MappingException: my.package.ScriptInterceptor
at dev.morphia.mapping.DiscriminatorLookup.lookup(DiscriminatorLookup.java:69)
at dev.morphia.mapping.codec.pojo.EntityDecoder.getCodecFromDocument(EntityDecoder.java:105)
... 84 more
Caused by: java.lang.ClassNotFoundException: my.package.ScriptInterceptor
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
I already tried to use the default discriminator (_t) but I got the very same error.
I'm really confused right now. Why is this happening?
I apologize for the delay. I've been hyperfocused on some things and neglecting responsibilities elsewhere. I'll try to recreate this and see if I can't find an answer for you.
/duplicate 2.5.1, 3.0.0
Issue Duplication Results
Processed by @evanchooly
✅ #3557 created for milestone "2.5.1" ✅ #3558 created for milestone "3.0.0"
Triggered by comment: /duplicate 2.5.1, 3.0.0
There's a few gaps in the description but I think I've filled them in correctly. I can't recreate this locally, so I'm not sure if I really have or not. Here's the test case I used:
public class TestPolymorphicQueries extends TestBase {
@Test
public void testQuery() {
Holder holder = new Holder();
holder.interceptors = new Interceptor[]{
new ScriptInterceptor(),
new XsltInterceptor()
};
getDs().save(holder);
Holder first = getDs().find(Holder.class).first();
assertNotNull(first);
assertEquals(first.interceptors, holder.interceptors);
}
@Entity
static class Holder {
@Id
private ObjectId id;
Interceptor[] interceptors;
}
@Entity(discriminatorKey = "type")
static abstract class Interceptor {
@Id
protected String id;
protected String type;
public Interceptor(String type) {
this.type = type;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Interceptor)) {
return false;
}
Interceptor that = (Interceptor) o;
return Objects.equals(id, that.id) && Objects.equals(type, that.type);
}
@Override
public int hashCode() {
return Objects.hash(id, type);
}
// getters and setters omitted..
}
@Entity(discriminator = "script", discriminatorKey = "type")
static class ScriptInterceptor extends Interceptor {
private String language;
private String source;
public ScriptInterceptor() {
super("script");
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ScriptInterceptor)) {
return false;
}
if (!super.equals(o)) {
return false;
}
ScriptInterceptor that = (ScriptInterceptor) o;
return Objects.equals(language, that.language) && Objects.equals(source, that.source);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), language, source);
}
// getters and setters omitted...
}
@Entity(discriminator = "xslt", discriminatorKey = "type")
static class XsltInterceptor extends Interceptor {
private String source;
public XsltInterceptor() {
super("xslt");
}
@Override
public boolean equals(Object o) {
if (!(o instanceof XsltInterceptor)) {
return false;
}
if (!super.equals(o)) {
return false;
}
XsltInterceptor that = (XsltInterceptor) o;
return Objects.equals(source, that.source);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), source);
}
// getters and setters omitted...
}
}