Skip to content

Handler registration should reject the same command handler from supertypes #4561

@hatzlj

Description

@hatzlj

Basic information

  • Axon Framework version: 5.0 - 5.1
  • JDK version: any
  • Complete executable reproducer if available (e.g. GitHub Repo): n.A.

Steps to reproduce

1.) Create an annotated command handling component inheriting from a supertype.
2.) Implement the same @CommandHandler annotated method in both the supertype and the annotated command handling component
3.) Make the supertype command handling method private

Expected behaviour

Handler detection should throw a DuplicateCommandHandlerSubscriptionException, because the supertype method is not visible to the subtype, so it's not an override and should be recognized as unique handler.

Actual behaviour

AnnotatedHandlerInspector#initializeMessageHandlers uses java.lang.Class#getDeclaredMethods to iterate all methods and detect MessageHandlers for the inspected type.

  • The order of registration is determined by the order of the method references returned by java.lang.Class#getDeclaredMethods
  • when registering a subtype that extends a supertype, after registering all discovered subtype declared methods all supertype methods will be registerd on the subtype as well (regardless of their visibility to the subtype, so also private supertype methods are registered with the subtype). This happens in a separate step after declared handler methods on the actual type are registered.

When creating an annotated message handling component, AnnotatedHandlerInspector#getUniqueHandlers is invoked. Get unique handlers takes the handlers registered for the subtype in order of registration with the AnnotatedHandlerInspector and filters them for duplicates based on the signature (name and parameter types) -> order of registration will always find the subtype method first. Due to how AnnotatedHandlerInspector#initializeMessageHandlers registers the methods declared on the actual type and only after that the supertype methods, the filtering will always prefer the subtype method and deduplicate similar supertype methods.

Thus, no DuplicateCommandHandlerSubscriptionException will be thrown.

Notes

The following table describes the inheritance scenarios for command handlers and their expected outcomes. Fixing this bug covers those cases stating reject as duplicate handler

Base Class Method access modifier Subtype Class Method access modifier Result
public public subtype method overrides – no error
public protected invalid (weaker access privileges)
public package private* invalid (weaker access privileges)
public package private** invalid (weaker access privileges)
public private invalid (weaker access privileges)
protected public subtype method overrides – no error (same as public – public)
protected protected subtype method overrides – no error (same as public – public)
protected package private* invalid (weaker access privileges)
protected package private** invalid (weaker access privileges)
protected private invalid (weaker access privileges)
package private* public subtype method overrides – no error (same as public – public)
package private* protected subtype method overrides – no error (same as public – public)
package private* package private subtype method overrides – no error (same as public – public)
package private* private invalid (weaker access privileges)
package private** public reject as duplicate handler
package private** package private reject as duplicate handler
package private** protected reject as duplicate handler
package private** private reject as duplicate handler
private public reject as duplicate handler
private package private* reject as duplicate handler
private package private** reject as duplicate handler
private protected reject as duplicate handler
private private reject as duplicate handler

* = within same package
** = in different package

Metadata

Metadata

Assignees

No one assigned

    Labels

    Status: ObsoleteUse to signal this issue is no longer necessary.

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions