morphia icon indicating copy to clipboard operation
morphia copied to clipboard

Projections on the discriminator property fail

Open agiannone opened this issue 2 years ago • 9 comments

Describe the bug When creating a projection on a discriminator property, the PathTarget throws a ValidationException because the discriminator is not added to the EntityModel as a PropertyModel. Note that the same issue will be present on any use of the PathTarget that involves the discriminator and doesn't skip validation.

To Reproduce

  1. Create an Entity with a nested interface that uses the discriminator
  2. Query the Entity and add a projection on the discriminator

Expected behavior It should be possible to add a projection on the discriminator property.

** Please complete the following information: **

  • Server Version: 5.x
  • Driver Version: 4.11
  • Morphia Version: 2.4.14

agiannone avatar Mar 15 '24 15:03 agiannone

What's the use case for doing a projection on the discriminator? Such metadata should be ignored/transparent to your application?

evanchooly avatar Mar 15 '24 17:03 evanchooly

I have an Entity which contains a property that is an interface. When I add a projection on the fields of one of the subtypes of the interface, it doesn't include the discriminatorKey to the projection. As a consequence the InstanceCreatorFactory throws out an error as it's can't find a constructor for the interface because the discriminator is missing.

The Projection class does include the following snippet:

if (isIncluding() && entityAnnotation != null && entityAnnotation.useDiscriminator()) { projection.put(mapper.getConfig().discriminatorKey(), 1); }

But this only gets applied to the main Entity and not it's nested interface.

agiannone avatar Mar 15 '24 19:03 agiannone

If you're querying by the interface type, you'll need to enable polymorphic queries.

evanchooly avatar Mar 15 '24 19:03 evanchooly

The parent entity is not an interface, so from what I understood, it wouldn't be considered a polymorphic query.

The query is on the parent entity which is a concrete class, the interface is a property of the entity.

@Entity
public class MyEntity {
  @Id private ObjectId myId;
  @Property private MyInterface prop;
}

@Entity( useDiscriminator = true )
public interface MyInterface {}

@Entity( useDiscriminator = true, discriminator = "mydisc" )
public class MyImpl implements MyInterface {
  @Property private int propA;
   ... more properties
}

The query is on MyEntity and I am adding a projection on the properties in MyImpl e.g. "prop.propA"

In this case the Morphia does not include the discriminatorKey into the projection and so the decoding of the MyInterface property fails.

agiannone avatar Mar 15 '24 21:03 agiannone

What does your query look like?

evanchooly avatar Mar 15 '24 23:03 evanchooly

I've tried to replicate the query as closely as possible in terms of filters and options used. Obviously not all the fields match above, but I've tried to keep the entity and embedded entity references accurate.

Query<MyEntity> query = datastore.find(MyEntity.class)
    .disableValidation()
    .filter( eq( "propertyA", someValue ) )
    .filter( in( "propertyB", listOfValues ) )
    .filter( gte( "datePropertyA", startDate ) )
    .filter( lte( "datePropertyA", endDate ) )
    .filter( ne( "propertyC", otherValue ) );

FindOptions options = new FindOptions()
    .sort( Sort.descending( "datePropertyA" ) )
    .projection().include( "prop.mydisc", "prop.propA" )
    .skip( 0 )
    .limit( 1 );

query.iterator( options ).toList();

agiannone avatar Mar 16 '24 07:03 agiannone

I'm not seeing how/where the discrimininator come in to play. Is the failure you're seeing that the projection doesn't know how to "see past" the interface definition?

evanchooly avatar Mar 17 '24 00:03 evanchooly

If I include the discriminator in the projection, then the PathTarget throws a ValidationException due to an invalid path.

If I don't include the discriminator in that projection, then the InstanceCreatorFactory throws a MappingException with the error "No suitable constructor found for type".

agiannone avatar Mar 17 '24 05:03 agiannone

If you could put together a reproducer I can take a deeper look. I have some ideas about what might be happening here but I can't quite follow your examples here well enough to be confident in recreating your scenario.

evanchooly avatar Mar 17 '24 19:03 evanchooly