diff --git a/src/main/java/net/engio/mbassy/dispatch/IHandlerInvocation.java b/src/main/java/net/engio/mbassy/dispatch/IHandlerInvocation.java index dbae72f..415d0a2 100644 --- a/src/main/java/net/engio/mbassy/dispatch/IHandlerInvocation.java +++ b/src/main/java/net/engio/mbassy/dispatch/IHandlerInvocation.java @@ -1,6 +1,6 @@ package net.engio.mbassy.dispatch; -import java.lang.reflect.Method; +import com.esotericsoftware.reflectasm.MethodAccess; /** * A handler invocation encapsulates the logic that is used to invoke a single @@ -28,7 +28,7 @@ public interface IHandlerInvocation { * type that the handler consumes * @param handler The handler (method) that will be called via reflection */ - void invoke(Object listener, Method handler, Object message) throws Throwable; + void invoke(Object listener, MethodAccess handler, int methodIndex, Object message) throws Throwable; /** * Invoke the message delivery logic of this handler @@ -39,7 +39,7 @@ public interface IHandlerInvocation { * type that the handler consumes * @param handler The handler (method) that will be called via reflection */ - void invoke(Object listener, Method handler, Object message1, Object message2) throws Throwable; + void invoke(Object listener, MethodAccess handler, int methodIndex, Object message1, Object message2) throws Throwable; /** * Invoke the message delivery logic of this handler @@ -50,7 +50,7 @@ public interface IHandlerInvocation { * type that the handler consumes * @param handler The handler (method) that will be called via reflection */ - void invoke(Object listener, Method handler, Object message1, Object message2, Object message3) throws Throwable; + void invoke(Object listener, MethodAccess handler, int methodIndex, Object message1, Object message2, Object message3) throws Throwable; /** * Invoke the message delivery logic of this handler @@ -61,5 +61,5 @@ public interface IHandlerInvocation { * type that the handler consumes * @param handler The handler (method) that will be called via reflection */ - void invoke(Object listener, Method handler, Object... message) throws Throwable; + void invoke(Object listener, MethodAccess handler, int methodIndex, Object... message) throws Throwable; } diff --git a/src/main/java/net/engio/mbassy/dispatch/ReflectiveHandlerInvocation.java b/src/main/java/net/engio/mbassy/dispatch/ReflectiveHandlerInvocation.java index 07d0bb2..b65dd21 100644 --- a/src/main/java/net/engio/mbassy/dispatch/ReflectiveHandlerInvocation.java +++ b/src/main/java/net/engio/mbassy/dispatch/ReflectiveHandlerInvocation.java @@ -1,6 +1,6 @@ package net.engio.mbassy.dispatch; -import java.lang.reflect.Method; +import com.esotericsoftware.reflectasm.MethodAccess; /** * Uses reflection to invoke a message handler for a given message. @@ -17,22 +17,22 @@ public class ReflectiveHandlerInvocation implements IHandlerInvocation { } @Override - public void invoke(final Object listener, Method handler, final Object message) throws Throwable { - handler.invoke(listener, message); + public void invoke(final Object listener, final MethodAccess handler, final int methodIndex, final Object message) throws Throwable { + handler.invoke(listener, methodIndex, message); } @Override - public void invoke(final Object listener, Method handler, final Object message1, final Object message2) throws Throwable { - handler.invoke(listener, message1, message2); + public void invoke(final Object listener, MethodAccess handler, int methodIndex, final Object message1, final Object message2) throws Throwable { + handler.invoke(listener, methodIndex, message1, message2); } @Override - public void invoke(final Object listener, Method handler, final Object message1, final Object message2, final Object message3) throws Throwable { - handler.invoke(listener, message1, message2, message3); + public void invoke(final Object listener, MethodAccess handler, int methodIndex, final Object message1, final Object message2, final Object message3) throws Throwable { + handler.invoke(listener, methodIndex, message1, message2, message3); } @Override - public void invoke(final Object listener, Method handler, final Object... messages) throws Throwable { - handler.invoke(listener, messages); + public void invoke(final Object listener, MethodAccess handler, int methodIndex, final Object... messages) throws Throwable { + handler.invoke(listener, methodIndex, messages); } } diff --git a/src/main/java/net/engio/mbassy/dispatch/SynchronizedHandlerInvocation.java b/src/main/java/net/engio/mbassy/dispatch/SynchronizedHandlerInvocation.java index b0859d5..af6ed34 100644 --- a/src/main/java/net/engio/mbassy/dispatch/SynchronizedHandlerInvocation.java +++ b/src/main/java/net/engio/mbassy/dispatch/SynchronizedHandlerInvocation.java @@ -1,6 +1,6 @@ package net.engio.mbassy.dispatch; -import java.lang.reflect.Method; +import com.esotericsoftware.reflectasm.MethodAccess; /** * Synchronizes message handler invocations for all handlers that specify @Synchronized @@ -19,30 +19,30 @@ public class SynchronizedHandlerInvocation implements IHandlerInvocation { } @Override - public void invoke(final Object listener, Method handler, final Object message) throws Throwable { + public void invoke(final Object listener, final MethodAccess handler, final int methodIndex, final Object message) throws Throwable { synchronized (listener) { - this.delegate.invoke(listener, handler, message); + this.delegate.invoke(listener, handler, methodIndex, message); } } @Override - public void invoke(final Object listener, Method handler, final Object message1, final Object message2) throws Throwable { + public void invoke(final Object listener, MethodAccess handler, int methodIndex, final Object message1, final Object message2) throws Throwable { synchronized (listener) { - this.delegate.invoke(listener, handler, message1, message2); + this.delegate.invoke(listener, handler, methodIndex, message1, message2); } } @Override - public void invoke(final Object listener, Method handler, final Object message1, final Object message2, final Object message3) throws Throwable { + public void invoke(final Object listener, MethodAccess handler, int methodIndex, final Object message1, final Object message2, final Object message3) throws Throwable { synchronized (listener) { - this.delegate.invoke(listener, handler, message1, message2, message3); + this.delegate.invoke(listener, handler, methodIndex, message1, message2, message3); } } @Override - public void invoke(final Object listener, Method handler, final Object... messages) throws Throwable { + public void invoke(final Object listener, MethodAccess handler, int methodIndex, final Object... messages) throws Throwable { synchronized (listener) { - this.delegate.invoke(listener, handler, messages); + this.delegate.invoke(listener, handler, methodIndex, messages); } } } diff --git a/src/main/java/net/engio/mbassy/error/PublicationError.java b/src/main/java/net/engio/mbassy/error/PublicationError.java index 7765896..5bdb551 100644 --- a/src/main/java/net/engio/mbassy/error/PublicationError.java +++ b/src/main/java/net/engio/mbassy/error/PublicationError.java @@ -1,6 +1,5 @@ package net.engio.mbassy.error; -import java.lang.reflect.Method; import java.util.Arrays; /** @@ -20,7 +19,7 @@ public class PublicationError { // Internal state private Throwable cause; private String message; - private Method handler; + private String methodName; private Object listener; private Object[] publishedObjects; @@ -59,12 +58,12 @@ public class PublicationError { return this; } - public Method getHandler() { - return this.handler; + public String getMethodName() { + return this.methodName; } - public PublicationError setHandler(Method handler) { - this.handler = handler; + public PublicationError setMethodName(String methodName) { + this.methodName = methodName; return this; } @@ -122,7 +121,7 @@ public class PublicationError { newLine + "\tmessage='" + this.message + '\'' + newLine + - "\thandler=" + this.handler + + "\tmethod=" + this.methodName + newLine + "\tlistener=" + this.listener + newLine + diff --git a/src/main/java/net/engio/mbassy/listener/MessageHandler.java b/src/main/java/net/engio/mbassy/listener/MessageHandler.java index dbe4af3..219273a 100644 --- a/src/main/java/net/engio/mbassy/listener/MessageHandler.java +++ b/src/main/java/net/engio/mbassy/listener/MessageHandler.java @@ -1,6 +1,5 @@ package net.engio.mbassy.listener; -import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Arrays; @@ -8,6 +7,8 @@ import net.engio.mbassy.annotations.Handler; import net.engio.mbassy.annotations.Synchronized; import net.engio.mbassy.common.ReflectionUtils; +import com.esotericsoftware.reflectasm.MethodAccess; + /** * Any method in any class annotated with the @Handler annotation represents a message handler. The class that contains * the handler is called a message listener and more generally, any class containing a message handler in its class hierarchy @@ -29,7 +30,8 @@ import net.engio.mbassy.common.ReflectionUtils; */ public class MessageHandler { - private final Method handler; + private final MethodAccess handler; + private final int methodIndex; private final Class[] handledMessages; private final boolean acceptsSubtypes; private final MessageListener listenerConfig; @@ -46,9 +48,10 @@ public class MessageHandler { } Class[] handledMessages = handler.getParameterTypes(); - handler.setAccessible(true); - this.handler = handler; + this.handler = MethodAccess.get(handler.getDeclaringClass()); + this.methodIndex = this.handler.getIndex(handler.getName(), handledMessages); + this.acceptsSubtypes = !handlerConfig.rejectSubtypes(); this.listenerConfig = listenerMetadata; this.isSynchronized = ReflectionUtils.getAnnotation(handler, Synchronized.class) != null; @@ -59,10 +62,6 @@ public class MessageHandler { this.isVarArg = handledMessages.length == 1 && handledMessages[0].isArray(); } - public A getAnnotation(Class annotationType){ - return ReflectionUtils.getAnnotation(this.handler,annotationType); - } - public boolean isSynchronized(){ return this.isSynchronized; } @@ -71,10 +70,14 @@ public class MessageHandler { return this.listenerConfig.isFromListener(listener); } - public Method getHandler() { + public MethodAccess getHandler() { return this.handler; } + public int getMethodIndex() { + return this.methodIndex; + } + public Class[] getHandledMessages() { return this.handledMessages; } diff --git a/src/main/java/net/engio/mbassy/subscription/Subscription.java b/src/main/java/net/engio/mbassy/subscription/Subscription.java index 06f678c..24f3c13 100644 --- a/src/main/java/net/engio/mbassy/subscription/Subscription.java +++ b/src/main/java/net/engio/mbassy/subscription/Subscription.java @@ -1,7 +1,6 @@ package net.engio.mbassy.subscription; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.Arrays; import net.engio.mbassy.common.IConcurrentSet; @@ -13,6 +12,8 @@ import net.engio.mbassy.error.ErrorHandlingSupport; import net.engio.mbassy.error.PublicationError; import net.engio.mbassy.listener.MessageHandler; +import com.esotericsoftware.reflectasm.MethodAccess; + /** * A subscription is a thread-safe container that manages exactly one message handler of all registered * message listeners of the same class, i.e. all subscribed instances (excluding subclasses) of a SingleMessageHandler.class @@ -126,27 +127,18 @@ public class Subscription { public void publishToSubscription(ErrorHandlingSupport errorHandler, Object message) { if (this.listeners.size() > 0) { - - /** - * Delivers the given message to the given set of listeners. - * Delivery may be delayed, aborted or restricted in various ways, depending - * on the configuration of the dispatcher - * - * @param publication The message publication that initiated the dispatch - * @param message The message that should be delivered to the listeners - * @param listeners The listeners that should receive the message - */ - Method handler = this.handlerMetadata.getHandler(); + MethodAccess handler = this.handlerMetadata.getHandler(); + int methodIndex = this.handlerMetadata.getMethodIndex(); for (Object listener : this.listeners) { try { - this.invocation.invoke(listener, handler, message); + this.invocation.invoke(listener, handler, methodIndex, message); } catch (IllegalAccessException e) { errorHandler.handlePublicationError(new PublicationError() .setMessage("Error during invocation of message handler. " + "The class or method is not accessible") .setCause(e) - .setHandler(handler) + .setMethodName(handler.getMethodNames()[methodIndex]) .setListener(listener) .setPublishedObject(message)); } catch (IllegalArgumentException e) { @@ -155,7 +147,7 @@ public class Subscription { "Wrong arguments passed to method. Was: " + message.getClass() + "Expected: " + handler.getParameterTypes()[0]) .setCause(e) - .setHandler(handler) + .setMethodName(handler.getMethodNames()[methodIndex]) .setListener(listener) .setPublishedObject(message)); } catch (InvocationTargetException e) { @@ -163,7 +155,7 @@ public class Subscription { .setMessage("Error during invocation of message handler. " + "Message handler threw exception") .setCause(e) - .setHandler(handler) + .setMethodName(handler.getMethodNames()[methodIndex]) .setListener(listener) .setPublishedObject(message)); } catch (Throwable e) { @@ -171,7 +163,7 @@ public class Subscription { .setMessage("Error during invocation of message handler. " + "The handler code threw an exception") .setCause(e) - .setHandler(handler) + .setMethodName(handler.getMethodNames()[methodIndex]) .setListener(listener) .setPublishedObject(message)); } @@ -181,27 +173,18 @@ public class Subscription { public void publishToSubscription(ErrorHandlingSupport errorHandler, Object message1, Object message2) { if (this.listeners.size() > 0) { - - /** - * Delivers the given message to the given set of listeners. - * Delivery may be delayed, aborted or restricted in various ways, depending - * on the configuration of the dispatcher - * - * @param publication The message publication that initiated the dispatch - * @param message The message that should be delivered to the listeners - * @param listeners The listeners that should receive the message - */ - Method handler = this.handlerMetadata.getHandler(); + MethodAccess handler = this.handlerMetadata.getHandler(); + int methodIndex = this.handlerMetadata.getMethodIndex(); for (Object listener : this.listeners) { try { - this.invocation.invoke(listener, handler, message1, message2); + this.invocation.invoke(listener, handler, methodIndex, message1, message2); } catch (IllegalAccessException e) { errorHandler.handlePublicationError(new PublicationError() .setMessage("Error during invocation of message handler. " + "The class or method is not accessible") .setCause(e) - .setHandler(handler) + .setMethodName(handler.getMethodNames()[methodIndex]) .setListener(listener) .setPublishedObject(message1, message2)); } catch (IllegalArgumentException e) { @@ -214,7 +197,7 @@ public class Subscription { handler.getParameterTypes()[1] ) .setCause(e) - .setHandler(handler) + .setMethodName(handler.getMethodNames()[methodIndex]) .setListener(listener) .setPublishedObject(message1, message2)); } catch (InvocationTargetException e) { @@ -222,7 +205,7 @@ public class Subscription { .setMessage("Error during invocation of message handler. " + "Message handler threw exception") .setCause(e) - .setHandler(handler) + .setMethodName(handler.getMethodNames()[methodIndex]) .setListener(listener) .setPublishedObject(message1, message2)); } catch (Throwable e) { @@ -230,7 +213,7 @@ public class Subscription { .setMessage("Error during invocation of message handler. " + "The handler code threw an exception") .setCause(e) - .setHandler(handler) + .setMethodName(handler.getMethodNames()[methodIndex]) .setListener(listener) .setPublishedObject(message1, message2)); } @@ -240,60 +223,51 @@ public class Subscription { public void publishToSubscription(ErrorHandlingSupport errorHandler, Object message1, Object message2, Object message3) { if (this.listeners.size() > 0) { - - /** - * Delivers the given message to the given set of listeners. - * Delivery may be delayed, aborted or restricted in various ways, depending - * on the configuration of the dispatcher - * - * @param publication The message publication that initiated the dispatch - * @param message The message that should be delivered to the listeners - * @param listeners The listeners that should receive the message - */ - Method handler = this.handlerMetadata.getHandler(); + MethodAccess handler = this.handlerMetadata.getHandler(); + int methodIndex = this.handlerMetadata.getMethodIndex(); for (Object listener : this.listeners) { try { - this.invocation.invoke(listener, handler, message1, message2, message3); + this.invocation.invoke(listener, handler, methodIndex, message1, message2, message3); } catch (IllegalAccessException e) { errorHandler.handlePublicationError(new PublicationError() - .setMessage("Error during invocation of message handler. " + - "The class or method is not accessible") - .setCause(e) - .setHandler(handler) - .setListener(listener) - .setPublishedObject(message1, message2, message3)); + .setMessage("Error during invocation of message handler. " + + "The class or method is not accessible") + .setCause(e) + .setMethodName(handler.getMethodNames()[methodIndex]) + .setListener(listener) + .setPublishedObject(message1, message2, message3)); } catch (IllegalArgumentException e) { errorHandler.handlePublicationError(new PublicationError() - .setMessage("Error during invocation of message handler. " + - "Wrong arguments passed to method. Was: " + - message1.getClass() + ", " + - message2.getClass() + ", " + - message3.getClass() - + ". Expected: " + handler.getParameterTypes()[0] + ", " + - handler.getParameterTypes()[1] + ", " + - handler.getParameterTypes()[2] - ) - .setCause(e) - .setHandler(handler) - .setListener(listener) - .setPublishedObject(message1, message2, message3)); + .setMessage("Error during invocation of message handler. " + + "Wrong arguments passed to method. Was: " + + message1.getClass() + ", " + + message2.getClass() + ", " + + message3.getClass() + + ". Expected: " + handler.getParameterTypes()[0] + ", " + + handler.getParameterTypes()[1] + ", " + + handler.getParameterTypes()[2] + ) + .setCause(e) + .setMethodName(handler.getMethodNames()[methodIndex]) + .setListener(listener) + .setPublishedObject(message1, message2, message3)); } catch (InvocationTargetException e) { errorHandler.handlePublicationError(new PublicationError() - .setMessage("Error during invocation of message handler. " + - "Message handler threw exception") - .setCause(e) - .setHandler(handler) - .setListener(listener) - .setPublishedObject(message1, message2, message3)); + .setMessage("Error during invocation of message handler. " + + "Message handler threw exception") + .setCause(e) + .setMethodName(handler.getMethodNames()[methodIndex]) + .setListener(listener) + .setPublishedObject(message1, message2, message3)); } catch (Throwable e) { errorHandler.handlePublicationError(new PublicationError() - .setMessage("Error during invocation of message handler. " + - "The handler code threw an exception") - .setCause(e) - .setHandler(handler) - .setListener(listener) - .setPublishedObject(message1, message2, message3)); + .setMessage("Error during invocation of message handler. " + + "The handler code threw an exception") + .setCause(e) + .setMethodName(handler.getMethodNames()[methodIndex]) + .setListener(listener) + .setPublishedObject(message1, message2, message3)); } } } @@ -301,54 +275,45 @@ public class Subscription { public void publishToSubscription(ErrorHandlingSupport errorHandler, Object... messages) { if (this.listeners.size() > 0) { - - /** - * Delivers the given message to the given set of listeners. - * Delivery may be delayed, aborted or restricted in various ways, depending - * on the configuration of the dispatcher - * - * @param publication The message publication that initiated the dispatch - * @param message The message that should be delivered to the listeners - * @param listeners The listeners that should receive the message - */ - Method handler = this.handlerMetadata.getHandler(); + MethodAccess handler = this.handlerMetadata.getHandler(); + int methodIndex = this.handlerMetadata.getMethodIndex(); for (Object listener : this.listeners) { try { - this.invocation.invoke(listener, handler, messages); + this.invocation.invoke(listener, handler, methodIndex, messages); } catch (IllegalAccessException e) { errorHandler.handlePublicationError(new PublicationError() - .setMessage("Error during invocation of message handler. " + - "The class or method is not accessible") - .setCause(e) - .setHandler(handler) - .setListener(listener) - .setPublishedObject(messages)); + .setMessage("Error during invocation of message handler. " + + "The class or method is not accessible") + .setCause(e) + .setMethodName(handler.getMethodNames()[methodIndex]) + .setListener(listener) + .setPublishedObject(messages)); } catch (IllegalArgumentException e) { errorHandler.handlePublicationError(new PublicationError() - .setMessage("Error during invocation of message handler. " + - "Wrong arguments passed to method. Was: " + Arrays.deepToString(messages) - + "Expected: " + Arrays.deepToString(handler.getParameterTypes())) - .setCause(e) - .setHandler(handler) - .setListener(listener) - .setPublishedObject(messages)); + .setMessage("Error during invocation of message handler. " + + "Wrong arguments passed to method. Was: " + Arrays.deepToString(messages) + + "Expected: " + Arrays.deepToString(handler.getParameterTypes())) + .setCause(e) + .setMethodName(handler.getMethodNames()[methodIndex]) + .setListener(listener) + .setPublishedObject(messages)); } catch (InvocationTargetException e) { errorHandler.handlePublicationError(new PublicationError() - .setMessage("Error during invocation of message handler. " + - "Message handler threw exception") - .setCause(e) - .setHandler(handler) - .setListener(listener) - .setPublishedObject(messages)); + .setMessage("Error during invocation of message handler. " + + "Message handler threw exception") + .setCause(e) + .setMethodName(handler.getMethodNames()[methodIndex]) + .setListener(listener) + .setPublishedObject(messages)); } catch (Throwable e) { errorHandler.handlePublicationError(new PublicationError() - .setMessage("Error during invocation of message handler. " + - "The handler code threw an exception") - .setCause(e) - .setHandler(handler) - .setListener(listener) - .setPublishedObject(messages)); + .setMessage("Error during invocation of message handler. " + + "The handler code threw an exception") + .setCause(e) + .setMethodName(handler.getMethodNames()[methodIndex]) + .setListener(listener) + .setPublishedObject(messages)); } } }