Annotation Interface EntityCreator
AnnotationBasedEventSourcedEntityFactory is used by the
EventSourcingRepository. Constructors or methods not annotated with this annotation will not be considered as
a way to create the entity.
Entity creation methods
There are two main ways to create an entity.
First, a constructor or factory method with a payload parameter (or
EventMessage parameter) can be defined, which will be called when the entity
is sourced and at least one event is found in the stream. This allows the entity to be created with non-nullable
properties, based on the origin event. If no event is found, the entity will be null until the first event is
published and the entity is created using this method. This means that, for commands that target an entity that might
not have an origin event, an
creational command
handler should be defined.
Secondly, a constructor or factory method can define no payload. It can still define the identifier as an argument. This will always initialize the entity, even if no events are found in the stream. This is useful for entities that are created without an origin event, such as those with a dynamic boundary.
Parameter types
The constructor or method can declare any number of parameters, as long as they can be resolved by aParameterResolverFactory. If the payload is declared, this should be
the first parameter. Configuration components can be injected, as well as any
message-related parameters. In addition to all regular parameters, the method can also declare the identifier of the
entity as a parameter.
The declared payload parameter is the wanted represented type, and will be injected if the
payloadQualifiedNames() matches with the EventMessage. If a payload
parameter is declared, and the payloadQualifiedNames() is empty, it will be determined based on the
MessageTypeResolver.
You can inject the entity identifier by declaring a parameter with the InjectEntityId annotation. This
annotation is necessary to disambiguate the entity identifier from the payload, as the first parameter without an
annotation is assumed to be the payload.
Factory methods
It's not always possible to only use constructors. For example, when using polymorphic entities, the factory method needs to call the right constructor based on the arguments of the method. This method needs to be static, and return the entity type of one of the declared subtypes.Examples: Mutable entity
In the following example, the entity is created with a constructor that takes the identifier. The instance command handler then be used to handle the create command.
class MutableEntity {
private String identifier;
private Boolean created;
@EntityCreator
public MutableEntity(@InjectEntityId String identifier) {
this.identifier = identifier;
this.created = false;
}
@CommandHandler
public void handle(CreateCommand command, EventAppender appender) {
if(created) {
throw new IllegalStateException("Entity already created");
}
appender.append(new MutableEntityCreatedEvent(identifier));
}
@EventSourcingHandler
public void on(MutableEntityCreatedEvent event) {
this.created = true;
}
}
Examples: Immutable entity
In the following example, the entity is created with a constructor that takes the event. If there is no event, it will not be created. As such, we will need a creational (static) command handler method.
class ImmutableEntity {
private final String identifier;
@EntityCreator
public MutableEntity(ImmutableEntityCreatedEvent createdEvent, @InjectEntityId String identifier) {
this.identifier = createdEvent.identifier();
// Or: this.identifier = identifier
}
@CommandHandler
public static void handle(CreateCommand command, EventAppender appender) {
appender.append(new MutableEntityCreatedEvent(identifier));
}
}
Examples: Polymorphic mutable entities
Polymorphic mutable entities need a factory method that can, based on the identifier, create the right entity. The factory method needs to be static, and be defined on the superclass.
abstract class MutablePolymorphicEntity {
@EntityCreator
public static MutablePolymorphicEntity create(@InjectEntityId MyPolymorphicIdentifier identifier) {
if (identifier.type() == MyPolymorphicIdentifier.Type.TYPE1) {
return new MutablePolymorphicEntityType1(identifier);
} else if (identifier.type() == MyPolymorphicIdentifier.Type.TYPE2) {
return new MutablePolymorphicEntityType2(identifier);
} else {
throw new IllegalArgumentException("Unknown type: " + identifier.type());
}
}
}
Examples: Polymorphic immutable entities
When using immutable polymorphic entities, you can either declare anEntityCreator on superclass with an
event parameter, and call the right constructor. Alternatively, you can declare a constructor on each of the
subclasses, and use the EntityCreator to call the right constructor. For the latter, the event types need to
be unique.
invalid input: '{@code
class MutablePolymorphicEntityType1 extends MutablePolymorphicEntity {
@EntityCreator
public MutablePolymorphicEntityType1(MutablePolymorphicEntityType1CreatedEvent event) {
// Initialize the entity with the event
}
}</pre>
@author Mitchell Herrijgers
@since 5.0.0'-
Optional Element Summary
Optional ElementsModifier and TypeOptional ElementDescriptionString[]The qualified names of the payload types that this factory method can handle.
-
Element Details
-
payloadQualifiedNames
String[] payloadQualifiedNamesThe qualified names of the payload types that this factory method can handle. If a payload parameter is declared, and this value is left at default, the payload's qualified name will be determined based on theMessageTypeResolver.- Returns:
- The qualified names of the payload types that this factory method can handle.
- Default:
{}
-