Skip to content

liachmodded/LambdaEvents

 
 

Repository files navigation

LambdaEvents

Fast and modular event library for Java.

Releases

To use LambdaEvents with Gradle/Maven you can follow the instructions on my maven server.

Gradle Template

repositories {
    maven {
        url "https://maven.lenni0451.net/releases"
    }
}

dependencies {
    implementation "net.lenni0451:LambdaEvents:x.x.x"
}

Maven Template

<repository>
    <id>lenni0451-maven-releases</id>
    <name>Lenni0451 Maven Repository</name>
    <url>https://maven.lenni0451.net/releases</url>
</repository>

<dependency>
    <groupId>net.lenni0451</groupId>
    <artifactId>LambdaEvents</artifactId>
    <version>x.x.x</version>
</dependency>

You should check the maven server for the latest version.

Jar File

You can download the jar file from my Jenkins server.
Since LambdaEvents has no dependencies you don't need to download any other jar files.

Usage

LambdaManager

To use LambdaEvents you need to create an instance of the LambdaManager class.
It is the main class of the library used to register and call events.

LambdaManager eventManager = LambdaManager.basic(generator);

Or for a thread safe version:

LambdaManager eventManager = LambdaManager.threadSafe(generator);

There is no global instance to prevent event conflicts.

Generator

Because of the dynamic nature of LambdaEvents you need to provide an IGenerator implementation.
It is used to generate the caller which calls the event listener.
The following implementations are provided:

  • ReflectionGenerator
  • MethodHandleGenerator
  • LambdaMetaFactoryGenerator

Check out the JMH Benchmark section for performance comparisons.

The MethodHandleGenerator and the LambdaMetaFactoryGenerator have an optional MethodHandles.Lookup parameter.

To create your own implementation you need to implement the IGenerator interface.
The generate method is used to generate a caller for handler which take the event as a parameter.
The generateVirtual method is used to generate a caller for handler which don't take the event as a parameter.

Events

In LambdaEvents there is no need to implement an interface or extend a class to create an event.
You can pass any object as an event. Remember that the class is used to identify the event type. Inheritance is not checked and treated as a different event type.

Registering

LambdaEvents has 6 different ways to listen to events:

Type Description
Static methods A static method annotated with @EventHandler
Virtual methods A virtual/non-static method annotated with @EventHandler
(static) Runnable field A runnable field annotated with @EventHandler
(static) Consumer field A consumer field annotated with @EventHandler
Independent Runnable A runnable which is passed to the register method
Independent Consumer A consumer which is passed to the register method

All register/unregister methods have an optional event class parameter to specify the type of the event to register/unregister.
This parameter is required when registering an independent event handler.

Runnable fields or Consumer fields without type parameters require the event type(s) to be added to the @EventHandler(events = {Event.class}) annotation.
Methods are required to not have any parameters or to have the event type as a parameter. Methods without parameters require the event type(s) to be added to the @EventHandler(events = {Event.class}) annotation.
Independent Runnables or Consumers require the event type(s) to be passed to the register method.

Static event handler

To register static event handler (methods and fields) you need to call the register method of the LambdaManager instance passing the owner class.

eventManager.register(Example.class);

Virtual event handler

To register virtual event handler (methods and fields) you need to call the register method of the LambdaManager instance passing the owner object.

eventManager.register(new Example());

Independent event handler

To register independent event handler (runnables and consumers) you need to call the register method of the LambdaManager instance passing the handler, priority and event type(s).

//Runnable
Runnable handler = () -> System.out.println("called");
eventManager.register(handler, 0, Event.class);

//Consumer
Consumer<Event> handler = e -> System.out.println("called " + e);
eventManager.register(handler, 0, Event.class);

Unregistering

To unregister event handler you have to call the respective unregister method of the LambdaManager instance in the same way you registered them.

//Static
eventManager.unregister(Example.class);

//Virtual
eventManager.unregister(oldExampleInstance);

//Independent
eventManager.unregister(handler, Event.class);

Calling

To call an event you need to call the call method of the LambdaManager instance passing the event object.

eventManager.call(new Event());

Priority

LambdaEvents supports priorities for event handlers which is used to determine the execution order.
The higher the priority is, the earlier the event handler is called.

Cancelling

Events

Since there is no requirement for an event to implement an interface or extend a class you have to implement the cancellation yourself.
Example:

public class Event {
    private boolean cancelled = false;

    public boolean isCancelled() {
        return this.cancelled;
    }

    public void setCancelled(final boolean cancelled) {
        this.cancelled = cancelled;
    }
}

public class Caller {
    public static void callEvent(final LambdaManager eventManager) {
        Event event = eventManager.call(new Event());
        if (event.isCancelled()) {
            return;
        }
        //Continue the method
        //...
    }
}

Call chain

To cancel the event call chain and prevent following event handlers from being executed you can throw the StopCall.INSTANCE exception.

Exception handling

Registration

If an exception is thrown during the registration process, the exception will be thrown to the caller.

Calling

If an exception is thrown by an event handler, the ExceptionHandler of the LambdaManager instance will be called.
It receives the handler, the event and the thrown exception as parameters.
By default the ExceptionHandler will print the stack trace of the exception to the console (System.err).

JMH Benchmark

The Benchmark shows the average time it takes to call an event 100_000 times.
The lower the time is, the better the performance of the generator is.

Benchmark Mode Cnt Score Error Units
CallBenchmark.callLambdaMetaFactory avgt 4 2092914,322 145474,182 ns/op
CallBenchmark.callMethodHandles avgt 4 3568765,480 91089,783 ns/op
CallBenchmark.callReflection avgt 4 2597966,622 122017,888 ns/op

About

Fast and modular event library for Java

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Java 100.0%