How to create a method that adds a listener and allows adding JAVA code

Tags:



I’ve been trying to make an event system for several days now but I can’t find a way to do the following.

I can’t find a way to make the event interactable from a method, I mean this:

    api.addEventListener (event -> {
        CODE
    );

The operation is simple, I would like that when the event is fired to the listeners in that method, I could add my code.

I am relatively new to Java and still struggle with this kind of thing.

I currently have these 5 classes:

This interface corresponds to the Listener, the one that will receive the event.

    public interface UserCreateMessageListener extends GloballyAttachableListener {
        void fire ();
    }

Implementation of the above.

    public class UserCreateMessageListenerImpl implements UserCreateMessageListener {
        @Override
        public void fire () {
            //CODE
        }
    }

This interface will contain the methods to add listeners and receive the event by adding code (which I intend to look for in the example above)

    public interface GloballyAttachableListener {
        default void addUserCreateMessageEvent (UserCreateMessageListener listener) {
            // I add the listeners to my listener initializer
        }
    }

This class fires events to declared listeners.

    public class Initializer extends ListenerAdapter {
        private static List <UserCreateMessageListener> listeners = new ArrayList <UserCreateMessageListener> ();
    
        public static void addListener (UserCreateMessageListener toAdd) {
            listeners.add (toAdd);
        }
    }
    
    @Override
    public void onMessageReceived (MessageReceivedEvent event) {
        for (UserCreateMessageListener e: listeners) {
            e.fire ();
        }
    }

This class is the class from which I intend to get information and events.

    public interface Api extends GloballyAttachableListener {
    
        default String getPrefix () {
            return ConfigAccessor.getPrefix ();
        }
    
        default long getId () {
            return ConfigAccessor.getId ();
        }
    }

Answer

I recommend that use template classes for object-specific handling.

ListenerAdapter:

public class ListenerAdapter<T> {
    private final List<EventListener<T>> listeners = new ArrayList<>();

    public void addEventListener(EventListener<T> listener) {
        listeners.add(listener);
    }

    public void removeEventListener(EventListener<T> listener) {
        listeners.remove(listener);
    }

    public void fire(T item) {
        listeners.forEach(listener -> listener.consume(item));
    }
}

EventListener:

public interface EventListener<T> {
    void consume(T item);
}

Simple test:

public class User {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

public class Main {
    public static void main(String[] args) {
        ListenerAdapter<User> listenerAdapter = new ListenerAdapter<>();
        listenerAdapter.addEventListener(item -> System.out.println(item.getName()));
        listenerAdapter.fire(new User("john"));
    }
}


Source: stackoverflow