https://github.com/zeromemes/alpine
A lightweight event system for Java 8+
https://github.com/zeromemes/alpine
eventbus events functional-interfaces java-8 lambda-expressions
Last synced: 7 months ago
JSON representation
A lightweight event system for Java 8+
- Host: GitHub
- URL: https://github.com/zeromemes/alpine
- Owner: ZeroMemes
- License: mit
- Created: 2017-05-28T17:37:45.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2023-07-17T05:05:05.000Z (about 2 years ago)
- Last Synced: 2025-03-16T05:12:24.884Z (7 months ago)
- Topics: eventbus, events, functional-interfaces, java-8, lambda-expressions
- Language: Java
- Homepage:
- Size: 467 KB
- Stars: 92
- Watchers: 4
- Forks: 19
- Open Issues: 6
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Alpine
A lightweight event system for Java 8+[![Releases][releases-badge]](https://github.com/ZeroMemes/Alpine/releases)
[![License][license-badge]](/LICENSE)
[![Status][status-badge]](https://github.com/ZeroMemes/Alpine/actions/workflows/gradle-build.yml)
[![Coverage][coverage-badge]](https://app.codecov.io/gh/ZeroMemes/Alpine)
[![Code Size][codesize-badge]](/)[releases-badge]: https://img.shields.io/github/v/release/ZeroMemes/Alpine?style=flat-square
[license-badge]: https://img.shields.io/github/license/ZeroMemes/Alpine?style=flat-square
[status-badge]: https://img.shields.io/github/actions/workflow/status/ZeroMemes/Alpine/gradle-build.yml?style=flat-square
[coverage-badge]: https://img.shields.io/codecov/c/github/ZeroMemes/Alpine?style=flat-square
[codesize-badge]: https://img.shields.io/github/languages/code-size/ZeroMemes/Alpine?style=flat-square
## Setup
The following setup assumes the usage of the [Impact Development Maven](https://impactdevelopment.github.io/maven) repo.
Alternatively, the [GitHub package](https://github.com/ZeroMemes/Alpine/packages) may be used.### Gradle
```gradle
dependencies {
compile 'com.github.ZeroMemes:Alpine:3.1.0'
}
```### Maven
```xml
com.github.ZeroMemes
Alpine
3.1.0```
## Tutorial
For starters, we must create an EventBus to handle events and their respective listeners.
Alpine provides a default implementation of EventBus that is configurable through a builder, so we'll be using that:```java
public class MyApplication {public static final EventBus EVENT_BUS = EventManager.builder()
.setName("my_application/root") // Descriptive name for the bus
.setSuperListeners() // Enable Listeners to receive subtypes of their target
.build();
}
```
Specifying a name for the bus is required; although, there is no hard restriction on its uniqueness. Additional settings
such as `setSuperListeners` can be seen in the documentation of [`EventBusBuilder`](src/main/java/me/zero/alpine/bus/EventBusBuilder.java).Now to actually receive events that are posted to the event bus, we'll need to create a `Listener` object and supply its
generic argument with the type of event we'd like to receive. One of the ways that this can be done by creating a
`Listener` member variable in a class implementing `Subscriber`, and annotating it with `@Subscribe`. Let's do that
in our existing class:
```java
public class MyApplication implements Subscriber {public static final EventBus EVENT_BUS = ...;
@Subscribe
private Listener stringListener = new Listener<>(str -> {
System.out.println(str);
});
}
```
In order to use our `Listener`, we need to create a new instance of the `Subscriber` implementation and subscribe
it to the event bus.
```java
public class MyApplication implements Subscriber {public static final EventBus EVENT_BUS = ...;
public static void main(String[] args) {
MyApplication app = new MyApplication();
EVENT_BUS.subscribe(app);
}@Subscribe
private Listener stringListener = new Listener<>(str -> {
System.out.println(str);
});
}
```
An alternative to creating a `Subscriber` implementation and using annotated `Listener` fields to receive events
is creating an independent `Listener` instance and subscribing it directly:
```java
public class MyApplication {public static final EventBus EVENT_BUS = ...;
public static void main(String[] args) {
EVENT_BUS.subscribe(new Listener(str -> {
System.out.println(str);
}));
// or, alternatively... (println has a String implementation which will get bound to here)
EVENT_BUS.subscribe(new Listener(System.out::println));
}
}
```
In cases where a method reference (`::`) is used for a `Listener` body and the underlying method's argument isn't the
`Listener` target, a `ClassCastException` can occur during runtime. This is due to incorrect target resolution, and can
be fixed by explicitly specifying the target type:
```java
public class MyApplication {public static final EventBus EVENT_BUS = ...;
public static void main(String[] args) {
// Incorrect, can cause ClassCastException upon runtime depending on EventBus configuration
EVENT_BUS.subscribe(new Listener(Main::supertypeAcceptor));// Correct, explicitly defines the target and no runtime exception or unintended behavior will occur
EVENT_BUS.subscribe(new Listener<>(String.class, Main::supertypeAcceptor));
}// Note the 'Object' argument type, this is what causes the need for an explicit target
private static void supertypeAcceptor(Object o) {
System.out.println(o);
}
}
```
Providing our `Listener` with an event, in this case, any `String`, is straight-forward:
```java
public class MyApplication {public static final EventBus EVENT_BUS = ...;
public static void main(String[] args) {
MyApplication app = new MyApplication();
EVENT_BUS.subscribe(app);
EVENT_BUS.post("Test");
}@Subscribe
private Listener stringListener = new Listener<>(str -> {
// Prints "Test"
System.out.println(str);
});
}
```
Listeners may have filters applied which must pass in order for the body to receive a given event. A listener can have as
many filters as is needed, which are added as the last arguments in the `Listener` constructor.
```java
public class MyApplication {...
@Subscribe
private Listener stringListener = new Listener<>(str -> {
// No output, "Test".length() != 3
System.out.println(str);
}, new LengthOf3Filter()); // <-- Predicate super String>... as last argument to Listener// Create nested class implementation of our filter
public static class LengthOf3Filter implements Predicate {@Override
public boolean test(CharSequence t) {
return t.length() == 3;
}
}
}
```
The complete example class can be found in [Java](example/src/main/java/JavaApplication.java) and [Kotlin](example/src/main/kotlin/KotlinApplication.kt).