Skip to content

Allow EntityMetamodel to be decorated without breaking ID resolution - #4772

Merged
smcvb merged 1 commit into
mainfrom
enhancement/entity-metamodel-plain
Jul 23, 2026
Merged

Allow EntityMetamodel to be decorated without breaking ID resolution#4772
smcvb merged 1 commit into
mainfrom
enhancement/entity-metamodel-plain

Conversation

@hjohn

@hjohn hjohn commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Problem

AnnotatedEventSourcedEntityModule contained a hard cast to AnnotatedEntityMetamodel<E> when building the EntityIdResolver. This made the EntityMetamodel component impossible to decorate or replace: any plain wrapper would cause a ClassCastException at startup. The root cause was that EntityIdResolverDefinition.createIdResolver required AnnotatedEntityMetamodel<E> as a parameter, leaking an annotation-specific concrete type into what should be a generic SPI.

Solution

Representation info (the mapping from message QualifiedName to expected payload Class) is now sourced from the AnnotatedEntityMetamodel built and cached by AnnotatedEventSourcedEntityModule itself, rather than from whatever component ends up registered in configuration. A new RepresentationConvertingEntityIdResolver wraps the delegate resolver and applies payload conversion using this cached provider before delegating ID extraction. The EntityMetamodel component in configuration is passed to EntityIdResolverDefinition.createIdResolver as the plain EntityMetamodel<E> interface — no cast required — and since AnnotatedEntityIdResolverDefinition only needs to perform annotation-based ID extraction (the conversion step having moved to the wrapper), it simplifies to returning an AnnotationBasedEntityIdResolver directly.

Impact

EntityIdResolverDefinition.createIdResolver now accepts EntityMetamodel<E> instead of AnnotatedEntityMetamodel<E>, which is a minor breaking change for any custom implementations of the interface. AnnotatedEntityMetamodel is marked @Internal as it is no longer part of the public API surface. AnnotatedEntityIdResolver is deprecated as its responsibility has been absorbed by the new wrapper class.

@hjohn
hjohn requested a review from a team as a code owner July 22, 2026 11:20
@hjohn
hjohn requested review from MateuszNaKodach, jangalinski and laura-devriendt-lemon and removed request for a team July 22, 2026 11:20
@hjohn hjohn self-assigned this Jul 22, 2026
@hjohn hjohn added Priority 2: Should High priority. Ideally, these issues are part of the release they’re assigned to. Type: Enhancement Use to signal an issue enhances an already existing feature of the project. labels Jul 22, 2026
@hjohn hjohn added this to the Release 5.3.0 milestone Jul 22, 2026
configuration.getComponent(MessageConverter.class),
new AnnotationBasedEntityIdResolver<>()
);
return new AnnotationBasedEntityIdResolver<>();

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class is basically now 100% indentical to AnnotationBasedEntityIdResolverDefinition -- I guess we could remove one of them...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See this comment for my opinion on this.

@hjohn
hjohn force-pushed the enhancement/entity-metamodel-plain branch from 32eaea1 to 15a4697 Compare July 22, 2026 11:33

@smcvb smcvb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bunch of nits, as always. Biggest pointer is the removal. I think we should deprecate it instead with a clear explanation why. Other than that, I see how this will resolve #4765 without the additional interface, which is great!

* @author Mitchell Herrijgers
* @since 5.0.0
*/
public class AnnotatedEntityIdResolver<ID> implements EntityIdResolver<ID>, DescribableComponent {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather have us mark this as @Deprecated since 5.3.0, with a bit of JavaDoc attached to it why.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is deprecated now :)

configuration.getComponent(MessageConverter.class),
new AnnotationBasedEntityIdResolver<>()
);
return new AnnotationBasedEntityIdResolver<>();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See this comment for my opinion on this.

import static org.junit.jupiter.api.Assertions.*;

@ExtendWith(MockitoExtension.class)
class AnnotatedEntityIdResolverTest {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't remove the class but deprecate it instead, I think we should keep the test as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test is back!

*/
<E, ID> EntityIdResolver<ID> createIdResolver(
Class<E> entityType,
Class<ID> idType,
AnnotatedEntityMetamodel<E> entityMetamodel,
EntityMetamodel<E> entityMetamodel,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although an API change, I think this change is fair to make. I mean, any AnnotatedEntityMetamodel anybody might have passed was already an EntityMetamodel implementation. Thus any custom EntityIdResolverDefinition a user may have created (although I doubt it that this happened) that did expect the AnnotatedEntityMetamodel could still cast themselves to resolve it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, if anyone did implement it, they would have to change their signature, but that would be a trivial fix.

@hjohn
hjohn force-pushed the enhancement/entity-metamodel-plain branch from 15a4697 to f284a21 Compare July 23, 2026 09:46

@smcvb smcvb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concerns have been addressed, hence I'm approving this pull request.

@smcvb
smcvb merged commit 2f4a4d4 into main Jul 23, 2026
7 checks passed
@smcvb
smcvb deleted the enhancement/entity-metamodel-plain branch July 23, 2026 11:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Priority 2: Should High priority. Ideally, these issues are part of the release they’re assigned to. Type: Enhancement Use to signal an issue enhances an already existing feature of the project.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants