Mostly, you want to declare them on the class methods. If you then pass those classes to RRiBbit, it will scan all methods that are returned by the getMethods() method of the Class-object. The getMethods() method returns all publicly available methods of that class. This means all methods with public visibility of the class including the ones inherited from superclasses!
The only exception here is when you use Spring. In this case, RRiBbit does not even need to know about your classes, since Spring is an interface-based framework. All spring proxy stuff, such as AOP and @Transactional, works through Spring proxies that implement the same interfaces as the classes that you declare as beans in your Spring ApplicationContext. For RRiBbit, this means that you have to declare the @Listener annotations on your interfaces, rather than your classes and pass those interface classes to RRiBbit for inspection. RRiBbit will then inspect those interface classes and ask Spring for instances of those interfaces. Spring will then return beans that implement the corresponding interfaces.
In short: put the @Listener annotations on class methods, except when you're using Spring. Put them on interface methods instead.
This could have several causes. Is the corresponding method overridden in a subclass that does not have the @Listener annotation? In Java, method annotations are never inherited, so if you let RRiBbit inspect a subclass that overrides the listener method without @Listener annotation, then this annotation will not be picked up.
Another possible cause is that you have put the @Listener annotation on a class method, but you have passed the corresponding interface class to RRiBbit to inspect. RRiBbit will now inspect all publicly available methods of the interface, not the class and the @Listener annotation is not picked up...
Yes, this is true. Sadly, the java.lang.reflect.Method.invoke() method, that RRiBbit uses internally to execute the listeners, does not support vararg parameters. This seems very confusing at first, since the invoke() method accepts the method parameters as varargs, but these varargs actually correspond to the non varargs parameters of the method that will actually be invoked. Confusing? Here's an example. The signature of the invoke() method is as follows:
java.lang.reflect.Method.invoke(Object target, Object... parameters)
Let's say that we want to execute the following method via reflection (as RRiBbit does when you make it a @Listener):
public void foo(String s, Integer i)
then the 'parameters' variable of the invoke() method corresponds to the s and i parameters of foo. So, this will work:
Method method = ... //foo method.invoke(someTarget, "string", 1);
But this will not work:
public void foo(String s, Integer... i) Method method = ... //foo method.invoke(someTarget, "string", 1, 2, 3);
Maybe in future versions of Java, but not yet, bummer. If you want this, you'll have to call invoke like this:
Method method = ... //foo method.invoke(someTarget, "string", new Integer[]{1, 2, 3});
So, this goes for the send() method of RRiBbit as well, when you want to call a Listener that has varargs, you have to pass in an array with the required parameters...
Yes, this is because generics are erased at compile time by the Java compiler, so at runtime, RRiBbit does not know that you only want lists of Strings and RRiBbit will think that you want just a List. Sadly, there is nothing we can do about generics erasure. You will probably have to use hints to control which Listeners are executed.
Yes, this is correct behaviour. As it says in the Javadoc for RequestResponseBus.sendForNothing(): "Sends a request to all Listeners that match the parameters, ignores the return values and returns nothing."
If you want to invoke Listeners that have a "void" return type, please use sendForSingleOfClass or sendForSingleOfClassWithHint and specify void.class as the return type. You will always get "null" back. Using sendForMultipleOfClass or sendForMultipleOfClassWithHint will also work, but then, you will always get an empty Collection back.
Async calls are calls that return immediately, while the actual processing of a request is still taking place in a separate Thread. RRiBbit does not explicitly support this, but it does not have to either, because Java already supports async calls that work just fine with RRiBbit. A java.util.concurrent.Future object is an object that represents the result of a task that is still executing. It has methods with which you can check whether the task is complete, cancel the task and retrieve the eventual result. If you want an async call with RRiBbit, simply construct a Future object in the listener method and return that as a return value to the caller. Please refer to the javadoc of java.util.concurrent.Future for more information.
When it comes to RRiBbit code, you have methods that call listeners (using rrb.send()) and methods that respond to calls (methods annotated with @Listener). Methods can also do both.
A method that calls listeners can very easily be tested by making sure that the RequestResponseBus in the unit test has appropriate listeners listening to the requests of the method. These can be dummy / mock listeners that return predefined values, that are necessary for the tests. Just create a class with some @Listener methods that return dummy values and use that class in the RequestResponseBus in your unit tests. Alternatively, you can also mock the entire RequestResponseBus using a framework such as Mockito.
A method that responds to requests (meaning it’s annotated with @Listener) can be tested like any other method. You don’t have to use RRiBbit to test it, it’s just another method. The method’s behaviour when called through RRiBbit will be identical to plain method calls.
If you want to test an entire set of classes (and make sure that they all work together and perform the correct requests to RRiBbit), you can just setup the RequestResponseBus and the listeners identically to how they are setup in a real environment (maybe mocking the DB or other external systems). Then, instead of the view layer making the requests to the RequestResponseBus, it will be your unit tests.
A typical characteristic of Event Bus based programming is that you don't care who "catches" the events. The same applies to RRiBbit. Programming this way can make code a lot simpler and more decoupled. However, you don't have to use RRiBbit for every single method invocation. You can for example, split your project up into modules and use regular method calls for inner-module calls and RRiBbit calls for cross-module calls, to keep different modules fully independent.