Annotation Interface Handler
The annotated method is invoked for events that have a type (or
name) matching the given events
(or namedEvents
) element
of the annotation and that are fired on one of
the channels
(or namedChannels
) specified in the annotation.
If neither event classes nor named events are specified in the
annotation, the class of the annotated method’s first parameter (which
must be of type Event
or a derived type) is used as (single)
event class (see the examples in events()
and
namedEvents()
).
Channel matching is performed by matching the event’s channels
(see Event.channels()
) with the channels specified in the
handler. The matching algorithm invokes
isEligibleFor
for each of the
event’s channels with the class (or name, see channels()
and
namedChannels()
) of each of the channels specified
in the handler.
If neither channel classes not named channels are specified in the
handler, or
is specified as one
of the channel classes, the matching algorithm invokes
Channel.Default
.classisEligibleFor
for each of
the event’s channels with the default criterion of the component’s
channel (see Manager.channel()
and
Eligible.defaultCriterion()
) as argument.
Finally, independent of any specified channels, the matching algorithm
invokes isEligibleFor
for each of the event’s channels with the component’s default criterion
as argument unless excludeSelf()
is set. This results in a match
if the component itself is used as one of the event’s channels
(see the description of Eligible
).
If a match is found for a given event’s properties and a handler’s
specified attributes, the handler method is invoked.
The method can have an additional optional parameter of type
Channel
(or a derived type). This parameter does not
influence the eligibility of the method regarding a given event,
it determines how the method is invoked. If the method does not
have a second parameter, it is invoked once if an event
matches. If the parameter exists, the method is invoked once for
each of the event’s channels, provided that the optional parameter’s
type is assignable from the event’s channel.
Because annotation elements accept only literals as values, they
cannot be used to register handlers with properties that are only
known at runtime. It is therefore possible to specify a
Handler
annotation with element dynamic=true
. Such a
handler must be added explicitly by invoking
Handler.Evaluator.add(ComponentType, String, Object)
or
Handler.Evaluator.add(ComponentType, String, Object, Object, int)
,
thus specifying some of the handler’s properties dynamically (i.e.
at runtime).
A special case is the usage of a channel that is only known at
runtime. If there are several handlers for events on such a
channel, a lot of methods will become dynamic. To avoid this,
Component
s support a HandlerDefinition.ChannelReplacements
parameter in their constructor. Using this, it is possible
to specify a specially defined Channel
class in the
annotation that is replaced by a channel that is only known
at runtime.
If a method with a handler annotation is overwritten in a derived class, the annotation is overwritten as well. The annotated method of the base class is no longer invoked as handler and the method of the derived class is only invoked as handler if it defines its own handler annotation.
- See Also:
-
Nested Class Summary
Modifier and TypeClassDescriptionstatic class
This class provides theHandler.Evaluator
for theHandler
annotation provided by the core package.static final class
The default value for thechannels
parameter of the annotation.static final class
The default value for theevents
parameter of the annotation. -
Optional Element Summary
Modifier and TypeOptional ElementDescriptionSpecifies classes of channels that the handler listens on.boolean
Returns true if the annotated method defines a dynamic handler.Specifies classes of events that the handler is to receive.boolean
Excludes the handler from channel matching against its component’s default criterion.String[]
Specifies names ofNamedChannel
s that the handler listens on.String[]
Specifies names ofNamedEvent
s that the handler is to receive.int
Specifies a priority.
-
Element Details
-
events
Specifies classes of events that the handler is to receive.class SampleComponent extends Component { @Handler public void onStart(Start event) { // Invoked for Start events on the component's channel, // event object made available } @Handler(events=Start.class) public void onStart() { // Invoked for Start events on the component's channel, // not interested in the event object } @Handler(events={Start.class, Stop.class}) public void onStart(Event<?> event) { // Invoked for Start and Stop events on the component's // channel, event made available (may need casting to // access specific properties) } }
- Returns:
- the event classes
- Default:
{org.jgrapes.core.annotation.Handler.NoEvent.class}
-
namedEvents
Specifies names ofNamedEvent
s that the handler is to receive.class SampleComponent extends Component { @Handler(namedEvents="Test") public void onTest(Event<?> event) { // Invoked for (named) "Test" events (new NamedEvent("Test")) // on the component's channel, event object made available } }
- Returns:
- the event names
- Default:
{""}
-
channels
Specifies classes of channels that the handler listens on.If none are specified, the component’s channel is used.
class SampleComponent extends Component { @Handler(channels=Feedback.class) public void onStart(Start event) { // Invoked for Start events on the "Feedback" channel // (class Feedback implements Channel {...}), // event object made available } }
Specifying
channels=Channel.class
make the handler listen for all events, independent of the channel that they are fired on.Specifying
channels=Self.class
make the handler listen for events that are fired on the conponent.- Returns:
- the channel classes
- Default:
{org.jgrapes.core.annotation.Handler.NoChannel.class}
-
namedChannels
Specifies names ofNamedChannel
s that the handler listens on.class SampleComponent extends Component { @Handler(namedChannels="Feedback") public void onStart(Start event) { // Invoked for Start events on the (named) channel "Feedback" // (new NamedChannel("Feedback")), event object made available } }
- Returns:
- the channel names
- Default:
{""}
-
priority
int prioritySpecifies a priority.The value is used to sort handlers. Handlers with higher priority are invoked first.
- Returns:
- the priority
- Default:
0
-
dynamic
boolean dynamicReturns true if the annotated method defines a dynamic handler.A dynamic handler must be added to the set of handlers of a component explicitly at run time using
Handler.Evaluator.add(ComponentType, String, Object)
orHandler.Evaluator.add(ComponentType, String, Object, Object, int)
.class SampleComponent extends Component { SampleComponent() { Handler.Evaluator.add(this, "onStartDynamic", someChannel); } @Handler(dynamic=true) public void onStartDynamic(Start event) { // Only invoked if added as handler at runtime } }
- Returns:
- the result
- Default:
false
-
excludeSelf
boolean excludeSelfExcludes the handler from channel matching against its component’s default criterion.The typical use case for this annotation is a converter component that receives events from some source channel and then fires the same kind of events with modified data using itself as the (source) channel. In this case, the events generated by the component must not be processed by the component although they are fired using the component as channel. So while it is useful to be able to target a specific component (using it as channel) in general, it isn’t in this special case and can therefore be turned off with this annotation.
Of course, it would also be possible to work around the ambiguity by firing the conversion results on an extra channel. But it is quite intuitive to use the component itself as (source) channel.
- Returns:
- true, if set
- Default:
false
-