Make EntityModel decoratable - #4765
Conversation
The `AnnotatedEntityMetamodel` is casting the `EntityEvolver` to an implementation; the `AnnotatedEntityMetamodel`. It's doing this because the AnnotatedEntityIdResolver needs access to the type information, which is an annotation-specific concern and should not be on the EntityEvolver interface. The result was that the `EntityEvolver` could never be decorated, as it's impossible to satisfy the cast. This leads to the Platform client having to destruct and re-construct the `EventSourcingRepository`, creating very close coupling for something that should be easy. This PR splits the annotation-specific functionality, the providing of class information about handlers, to the `RepresentationResolvingEntityEvolver`. Now, the `EntityEvolver` can be decorated, as long as decorators implement `RepresentationResolvingEntityEvolver` as well. The module configuration is no longer bound to an implementation, but to an interface, removing the brittle re-construct logic for Platform
hatzlj
left a comment
There was a problem hiding this comment.
some small findings and one design question regarding the breaking change, but none is blocking in my opinion
| return definition.createIdResolver(entityType, idType, representationResolvingEntityEvolver, c); | ||
| } | ||
| // Not possible, except when decorating, as this is a component configured by this module. | ||
| throw new IllegalArgumentException("The EntityMetamodel does not implement RepresentationResolvingEntityEvolver. Make sure that all decorators implement and delegate this interface."); |
There was a problem hiding this comment.
probably switch to AxonConfigurationException,
| throw new IllegalArgumentException("The EntityMetamodel does not implement RepresentationResolvingEntityEvolver. Make sure that all decorators implement and delegate this interface."); | |
| throw new AxonConfigurationException("The EntityMetamodel does not implement RepresentationResolvingEntityEvolver. Make sure that all decorators implement and delegate this interface."); |
There was a problem hiding this comment.
Good one, will adjust
| * {@link QualifiedName}. This is useful for components that provide annotation-based usage of entities as it provides | ||
| * information on the wanted Java class (the representation) by the user. | ||
| * | ||
| * @param <E> The entity type this evolver applies to. |
There was a problem hiding this comment.
we decided to use fragment style consistently some time ago
| * @param <E> The entity type this evolver applies to. | |
| * @param <E> the entity type this evolver applies to |
There was a problem hiding this comment.
Oh wow that's a 180 form when I was in the Framework team! Will adjust
| * @param qualifiedName The {@link QualifiedName} of the handler to look for. | ||
| * @return The {@link Class} of the expected representation for handlers of the given {@code qualifiedName}, or | ||
| * {@code null} if no such representation is found. | ||
| */ |
There was a problem hiding this comment.
we decided to use fragment style some time ago
| * @param qualifiedName The {@link QualifiedName} of the handler to look for. | |
| * @return The {@link Class} of the expected representation for handlers of the given {@code qualifiedName}, or | |
| * {@code null} if no such representation is found. | |
| */ | |
| * @param qualifiedName the {@link QualifiedName} of the handler to look for | |
| * @return the {@link Class} of the expected representation for handlers of the given {@code qualifiedName}, or | |
| * {@code null} if no such representation is found |
| var component = (AnnotatedEntityMetamodel<E>) c.getComponent(EntityMetamodel.class, entityName()); | ||
| return definition.createIdResolver(entityType, idType, component, c); | ||
| var component = c.getComponent(EntityMetamodel.class, entityName()); | ||
| if(component instanceof RepresentationResolvingEntityEvolver representationResolvingEntityEvolver) { |
There was a problem hiding this comment.
| if(component instanceof RepresentationResolvingEntityEvolver representationResolvingEntityEvolver) { | |
| if (component instanceof RepresentationResolvingEntityEvolver representationResolvingEntityEvolver) { |
| EntityIdResolver<ID> delegate) { | ||
| this.idType = Objects.requireNonNull(idType, "The idType should not be null."); | ||
| this.metamodel = Objects.requireNonNull(metamodel, "The metamodel should not be null,"); | ||
| this.entityEvolver = Objects.requireNonNull(entityEvolver, "The entityEvolver should not be null,"); |
There was a problem hiding this comment.
| this.entityEvolver = Objects.requireNonNull(entityEvolver, "The entityEvolver should not be null,"); | |
| this.entityEvolver = Objects.requireNonNull(entityEvolver, "The entityEvolver should not be null."); |
| Configuration entityConfiguration = | ||
| entityModuleConfiguration(componentRegistry.build(lifecycleRegistry), COURSE_ENTITY_NAME); | ||
|
|
||
| // Sanity check that the decorator actually reached the entity's (nested) EntityMetamodel component — |
There was a problem hiding this comment.
those em-dashes :-)
| // Sanity check that the decorator actually reached the entity's (nested) EntityMetamodel component — | |
| // Sanity check that the decorator actually reached the entity's (nested) EntityMetamodel component, |
|
I'm not fully convinced yet if we should do it like this :) We're still accepting a plain
I think we need to do either:
Any simple |
|
Closing this PR with the status obsolete, due to #4772 taking a different, slightly more optimized path instead. |
The
AnnotatedEntityMetamodelis casting theEntityEvolverto an implementation; theAnnotatedEntityMetamodel. It's doing this because the AnnotatedEntityIdResolver needs access to the type information, which is an annotation-specific concern and should not be on the EntityEvolver interface.The result was that the
EntityEvolvercould never be decorated, as it's impossible to satisfy the cast. This leads to the Platform client having to destruct and re-construct theEventSourcingRepository, creating very close coupling for something that should be easy.This PR splits the annotation-specific functionality, the providing of class information about handlers, to the
RepresentationResolvingEntityEvolver. Now, theEntityEvolvercan be decorated, as long as decorators implementRepresentationResolvingEntityEvolveras well. The module configuration is no longer bound to an implementation, but to an interface, removing the brittle re-construct logic for Platform