Skip to content

Repository files navigation

Alpine

A lightweight event system for Java 8+

ReleasesLicenseStatusCoverageCode Size

Setup

The following setup assumes the usage of the Impact Development Maven repo. Alternatively, the GitHub package may be used.

Gradle

dependencies {
compile 'com.github.ZeroMemes:Alpine:3.1.0'
}

Maven

<dependency>
<groupId>com.github.ZeroMemes</groupId>
<artifactId>Alpine</artifactId>
<version>3.1.0</version>
</dependency>

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:

publicclassMyApplication {
publicstaticfinalEventBusEVENT_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.

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:

publicclassMyApplicationimplementsSubscriber {
publicstaticfinalEventBusEVENT_BUS = ...;
@SubscribeprivateListener<String> stringListener = newListener<>(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.

publicclassMyApplicationimplementsSubscriber {
publicstaticfinalEventBusEVENT_BUS = ...;
publicstaticvoidmain(String[] args) {
MyApplicationapp = newMyApplication();
EVENT_BUS.subscribe(app);
}
@SubscribeprivateListener<String> stringListener = newListener<>(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:

publicclassMyApplication {
publicstaticfinalEventBusEVENT_BUS = ...;
publicstaticvoidmain(String[] args) {
EVENT_BUS.subscribe(newListener<String>(str -> {
System.out.println(str);
}));
// or, alternatively... (println has a String implementation which will get bound to here)EVENT_BUS.subscribe(newListener<String>(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:

publicclassMyApplication {
publicstaticfinalEventBusEVENT_BUS = ...;
publicstaticvoidmain(String[] args) {
// Incorrect, can cause ClassCastException upon runtime depending on EventBus configurationEVENT_BUS.subscribe(newListener<String>(Main::supertypeAcceptor));
// Correct, explicitly defines the target and no runtime exception or unintended behavior will occurEVENT_BUS.subscribe(newListener<>(String.class, Main::supertypeAcceptor));
}
// Note the 'Object' argument type, this is what causes the need for an explicit targetprivatestaticvoidsupertypeAcceptor(Objecto) {
System.out.println(o);
}
}

Providing our Listener with an event, in this case, any String, is straight-forward:

publicclassMyApplication {
publicstaticfinalEventBusEVENT_BUS = ...;
publicstaticvoidmain(String[] args) {
MyApplicationapp = newMyApplication();
EVENT_BUS.subscribe(app);
EVENT_BUS.post("Test");
}
@SubscribeprivateListener<String> stringListener = newListener<>(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.

publicclassMyApplication {
...
@SubscribeprivateListener<String> stringListener = newListener<>(str -> {
// No output, "Test".length() != 3System.out.println(str);
}, newLengthOf3Filter()); // <-- Predicate<? super String>... as last argument to Listener// Create nested class implementation of our filterpublicstaticclassLengthOf3FilterimplementsPredicate<CharSequence> {
@Overridepublicbooleantest(CharSequencet) {
returnt.length() == 3;
}
}
}

The complete example class can be found in Java and Kotlin.

About

A lightweight event system for Java 8+

Topics

Resources

Stars

93 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages