Provide a way to specify a reference to identity using annotation
zambrovski opened this issue · 5 comments
Short
Introduce a new stereotype IdentityRef
expressing a reference to a Identity
as annotation.
Description
I stumbled upon an interesting question implementing command dispatching in CQRS. The command model accessed via aggregate root needs to be able to build an identifier from the context of a command to target the correct aggregate / entity.
A very easy way to target is to specify the target identifier inside the command. Firstly, I thought I could use Identifier
or @Identity
from jmolecules-ddd
for this purpose, but it seems to be very strange... The command itself is an immutable value object and putting a field inside of it marked with @Identity
seems to be confusing... A better approach is to use a different stereotype IdentityRef
(as a annotation) to express the "pointer-to-identity" semantics.
Look on the follow example:
@Command(namespace = "customer", name = "UpdateCustomerProfile")
data class UpdateCustomerProfileCommand(
@IdentityRef
val customerId: CustomerId,
val firstName: FirstName,
val lastName: LastName
)
@AggregateRoot
class CustomerProfile {
@Identity
lateinit var customerId: CustomerId
@CommandHandler(namespace = "customer", name = "UpdateCustomerProfile")
fun handle(command: UpdateCustomerProfileCommand) {
// ...
}
}
Is the Association
marker interface is exactly designed for this? Then I think the definition of the association with an annotation should be possible:
/**
* Marks the reference to identity.
* Carries optional the identity type and the identifiable type.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Documented
public @interface IdentityRef {
/**
* Defines identity type.
*
* @return class defining the identity type.
*/
Class<?> identityType() default void.class;
/**
* Defines the aggregate type.
*
* @return class defining the identifiable type (entity or aggregate).
*/
Class<?> identifiableType() default void.class;
}
You're right. In the type-based model, Association
is what would model this, if you wanted to go beyond declaring the simple identifier field. I guess we could introduce an Association
annotation, too, to keep symmetry between the two models (we already have that for AggregateRoot
, Entity
etc.).
What exactly would the purpose of the identityType
attribute be? Isn't that – by definition – the type of the field?
I agree with everything you wrote. You are absolutely right, the identityType
is not required... Should I provide a PR then? How the annotation should be called? Are you ok with Association` then?
To tell you what I'm currently building: it is Axon Framework byte buddy integration. For support of Axon Framework @TargetAggregateIdentifier
I would use the @Association
annotation then...
I agree with everything you wrote. You are absolutely right, the
identityType
is not required... Should I provide a PR then? How the annotation should be called? Are you ok with Association` then?
I would happily have a look at a PR. Association
is just fine. I am wondering whether we want to be consistent with @Identity
in allowing both annotations on methods, likely the getter, too.
To tell you what I'm currently building: it is Axon Framework byte buddy integration. For support of Axon Framework
@TargetAggregateIdentifier
I would use the@Association
annotation then...
Nice! Looking forward to seeing that PR as well!