Skip to content

Proof of Concept: Transformer-less EventBus - #617

Draft
ZZZank wants to merge 8 commits into
CleanroomMC:mainfrom
ZZZank:transformerless-bus
Draft

Proof of Concept: Transformer-less EventBus#617
ZZZank wants to merge 8 commits into
CleanroomMC:mainfrom
ZZZank:transformerless-bus

Conversation

@ZZZank

@ZZZank ZZZank commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

This PR removed two EventBus related transformers: EventSubscriptionTransformer and EventSubscriberTransformer, and added lambda-based listener registration.

Removal of EventSubscriptionTransformer

EventSubscriptionTransformer works by injecting .getListenerList(), .isCancelable(), and .hasResult() implementation for event class, and make use of JVM method dispatch to handle inheritance of event properties.

To get rid of this transformer while still recognize custom implementation, three ClassValue is used for caching the result of three previously mentioned methods, each containing some reflection tricks to use custom implementation when possible. See EventProperties class in this PR for more detail.

Removal of EventSubscriberTransformer

EventSubscriberTransformer scans every method in every class to find those with @SubscribeEvent, then make the method, and the declaring class, public.

To get rid of this transformer, method searching logic in EventBus is rewritten, to include all declared methods as candidate, instead of only public methods. EventListenerFactory is also modified to handle non-public method.

New method searching logic should also be faster when working on static listener class.

Lambda-based listener

Full method:

public <T extends Event> void addListener(
        Class<T> eventType,
        EventPriority priority,
        boolean receiveCanceled,
        Consumer<T> handler
) {}

The "Infer event type from handler" feature is not implemented yet.


Tests mostly written by AI, see this commit


ListenerList result = null;
try {
var method_getListenerList = eventType.getDeclaredMethod("getListenerList");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still need call getListenerList here? another way needed

// walks superclass, until (exclusive) the first method implementation
Class<?> checkEnd = method.getDeclaringClass();
for (var c = type; c != checkEnd; c = c.getSuperclass()) {
if (type.isAnnotationPresent(target)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (type.isAnnotationPresent(target)) {
if (c.isAnnotationPresent(target)) {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants