
# ApplicationEvent

`ApplicationEvent` is the optional base class of events; this page also covers `ApplicationEventPublisher`, which sends events, and the listener types that receive them.

## Why use it

You need these types when you publish events, or when an `@EventListener` method is not the right form of listener.

- **`ApplicationEventPublisher`**: inject it into a bean that announces something. Every application context is a publisher, and the context is the bean injected for this type.
- **`ApplicationEvent`**: extend it when listeners need the `source` (the object that raised the event) and the `timestamp`. Otherwise a plain class or a record is enough.
- **`PayloadApplicationEvent<T>`**: the envelope the context puts around a published object that is not an `ApplicationEvent`. Listeners of `T` receive the object itself. Listen to the envelope only when you also want its source and timestamp.
- **`ApplicationListener<E>`**: a bean that listens to one event type by implementing an interface. Use it when a class exists only to listen, or when code is ported from Java. An `@EventListener` method is shorter.
- **`GenericApplicationListener`** and **`SmartApplicationListener`**: listeners that decide per event, or by event and source type, whether to handle it.
- **`context.addListener<E>(...)`**: a listener for code that is not a bean, such as a Flutter widget or a test. It returns a `ListenerRegistration`; call `remove()` to stop listening.

## Example

```dart
import 'package:spring_core_dart/spring_core_dart.dart';

// An event with a source and a timestamp.
class OrderShipped extends ApplicationEvent {
  OrderShipped(super.source, this.id);
  final String id;
}

@Service()
class ShippingService {
  ShippingService(this.publisher);
  final ApplicationEventPublisher publisher;

  // `this` is recorded as the event's source.
  void ship(String id) => publisher.publishEvent(OrderShipped(this, id));
}

// A class that exists only to listen.
@Component()
@Log()
class ShipmentAudit implements ApplicationListener<OrderShipped> {
  @override
  void onApplicationEvent(OrderShipped event) =>
      log.info('shipped ${event.id} at ${event.timestamp}');
}
```

Listening from code that is not a bean:

```dart
const log = SpringLog('neon.ui');

final context = ApplicationContext.run([appBeans]);

// Stays active until remove() is called, for example in a widget's dispose.
final registration = context.addListener<OrderShipped>(
  (event) => log.info('shipped ${event.id}'),
);
context.getBean<ShippingService>().ship('A-17');
registration.remove();
context.close();
```

A listener that decides per event:

```dart
const log = SpringLog('neon.audit');

// Audits every event except the refresh.
class AuditAll implements GenericApplicationListener {
  @override
  bool supportsEvent(Object event) => event is! ContextRefreshedEvent;

  @override
  void onApplicationEvent(Object event) => log.info('audit: $event');
}

context.addApplicationListener(AuditAll());
```

## Members

| Type | Member | Meaning |
|---|---|---|
| `ApplicationEvent` | `ApplicationEvent(Object source, {DateTime? timestamp})` | Creates an event raised by `source`; `timestamp` defaults to now. |
| `ApplicationEvent` | `source` | The object that raised the event, usually the publishing bean. |
| `ApplicationEvent` | `timestamp` | When the event was created (not when it was received). |
| `PayloadApplicationEvent<T>` | `payload` | The published object. |
| `ApplicationEventPublisher` | `publishEvent<T>(T event)` | Delivers `event` to every listener that accepts it. A non-`ApplicationEvent` is wrapped in a `PayloadApplicationEvent<T>`. |
| `ApplicationListener<E>` | `onApplicationEvent(E event)` | Called for each event (or published object) of type `E`. |
| `GenericApplicationListener` | `supportsEvent(Object event)` | Whether `onApplicationEvent` should get this event. |
| `SmartApplicationListener` | `supportsEventType(Type)`, `supportsSourceType(Type)` | Decide by the exact runtime types; a mixin with lowest precedence as default order. |
| `ApplicationListenerAdapter` | `of<E>(handler, {order})`, `forListener<E>(listener, {order})` | Turns a function or a non-bean `ApplicationListener` into a listener for `addApplicationListener`. |
| `ApplicationContext` | `addListener<E>(listener, {order})` | Adds a function listener; returns a `ListenerRegistration`. |
| `ListenerRegistration` | `remove()`, `isRemoved` | Stops the listener; later calls do nothing. |

## In Spring (Java)

```java
class OrderShipped extends ApplicationEvent {
  final String id;
  OrderShipped(Object source, String id) { super(source); this.id = id; }
}

@Component
class ShipmentAudit implements ApplicationListener<OrderShipped> {
  public void onApplicationEvent(OrderShipped event) { ... }
}

context.addApplicationListener(ApplicationListener.forPayload(
    (OrderPlaced order) -> log.info("placed " + order.id())));
```

Differences that matter:

- `GenericApplicationListener.supportsEvent` decides on the event instance, not on a `ResolvableType`.
- `addListener` returns a `ListenerRegistration`. Spring has no handle; you keep the listener and call `removeApplicationListener`.
- A listener object given to `registerSingleton` that is an `ApplicationListener<E>` must be wrapped with `ApplicationListenerAdapter.forListener<E>`, because Dart cannot read `E` from the object at run time.

## See also

- [Events](index.md)
- [@EventListener](event-listener.md)
- [Context events](context-events.md)
- [ApplicationContext](../beans/application-context.md)
