Java driver- deep polymorphic trees

(Also on java - Maven: Excluding tests from build - Stack Overflow)

I have the following polymorphic structure for objects I want to store in MongoDb:

           InventoryItem (abstract)
             /                   \
      Tracked Item            AmountItem (Abstract)
                                   /             \
                        SimpleAmountItem       ListAmountItem

With: (Full code here (Github))

@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@JsonTypeInfo(
	use = JsonTypeInfo.Id.NAME,
	include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "storedType"
)
@JsonSubTypes({
	@JsonSubTypes.Type(value = SimpleAmountItem.class, name = "AMOUNT_SIMPLE"),
	@JsonSubTypes.Type(value = ListAmountItem.class, name = "AMOUNT_LIST"),
	@JsonSubTypes.Type(value = TrackedItem.class, name = "TRACKED")
})
@BsonDiscriminator
public abstract class InventoryItem<T> extends ImagedMainObject {
	@NonNull
	@NotNull
	private Map<@NonNull ObjectId, @NonNull T> storageMap = new LinkedHashMap<>();
    private final StoredType storedType;
    //...
}


@EqualsAndHashCode(callSuper = true)
@Data
public class TrackedItem extends InventoryItem<Map<@NotBlank String, @NotNull TrackedStored>> {
    //...
}


@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@ValidHeldStoredUnits
public abstract class AmountItem<T> extends InventoryItem<T> {
    //...
}



@EqualsAndHashCode(callSuper = true)
@Data
public class SimpleAmountItem extends AmountItem<AmountStored> {
    //...
}


@EqualsAndHashCode(callSuper = true)
@Data
public class ListAmountItem extends AmountItem<List<@NotNull AmountStored>> {
    //...
}

As shown, TrackedItem can be appropriately handled by Mongo, stored/ retrieved, etc. However, both the ListAmountItem and SimpleAmountItem cannot, with the following error:

Encoding a ListAmountItem: 'ListAmountItem()' failed with the following exception:

Failed to encode 'ListAmountItem'. Encoding 'storageMap' errored with: Can't find a codec for class java.lang.Object.

A custom Codec or PojoCodec may need to be explicitly configured and registered to handle this type.
	at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:105)
	at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:359)
	at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:218)
	at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:519)
	at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
	at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
	at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
	at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
	at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
	at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
	at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:151)
	at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler$1.run(VertxRequestHandler.java:91)
	at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:543)
	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
	at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
	at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: org.bson.codecs.configuration.CodecConfigurationException: An exception occurred when encoding using the AutomaticPojoCodec.
Encoding a ListAmountItem: 'ListAmountItem()' failed with the following exception:

Failed to encode 'ListAmountItem'. Encoding 'storageMap' errored with: Can't find a codec for class java.lang.Object.

It appears that Mongo can reconcile direct/first descendants of a superclass, but not if the inheritance tree gets any deeper than that. Is this as designed, a bug, or something I can tweak to get around?

It appears to me that Mongo gets stuck on trying to reconcile the Simple/ListAmountItems as a plain AmountItem, which makes sense as why it’s failing, but not terribly clear as to how to fix it. The @BsonDiscriminator seems rather simplistic, esp. compared to Jackson.

I’ll note that I am implementing this in Quarkus 2.7.5.Final.

Looks like there might be some support for specifying known types, but I don’t see an analogous java annotation ( Reference → BSON → MappingClasses → Polymorphism )

1 Like

Sorry, wrong SO link in OP: MongoDb Java- deeper polymorph tree - Stack Overflow

Looks like I found a bug- https://jira.mongodb.org/projects/JAVA/issues/JAVA-4578

For now I just flattened my sub-object tree and accepted some duplicate code.

2 Likes

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.