gwt-supereventbus icon indicating copy to clipboard operation
gwt-supereventbus copied to clipboard

Could supereverntbus be more super in future?

Open doggie1989 opened this issue 10 years ago • 6 comments

we need to do interface MyRegistration extends EventRegistration<MyClass> {} and eventBus.register(this, (MyRegistration) GWT.create(MyRegistration.class)); before using the @Subscribe. That is boilerplate code like in gwteventbinder the Event need to extend GenericEvent.

I am also using guava EventBus with Spring in server side which let spring auto register

import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe;

import java.lang.annotation.Annotation; import java.lang.reflect.Method;

import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.stereotype.Component;

@Component public class EventBusPostProcessor implements BeanPostProcessor {

@Autowired
private EventBus eventBus;

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
{
    return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
{
    // for each method in the bean
    Method[] methods = bean.getClass().getMethods();

    for (Method method : methods)
    {
        // check the annotations on that method
        Annotation[] annotations = method.getAnnotations();
        for (Annotation annotation : annotations)
        {
            // if it contains the Subscribe annotation
            if (annotation.annotationType().equals(Subscribe.class))
            {
                // register it with the event bus
                eventBus.register(bean);
                // we only need to register once
                return bean;
            }
        }
    }

    return bean;
}

}

Do you know any approach to do this ? for example, with GIN ?

Thank you very much~!

doggie1989 avatar Dec 15 '13 15:12 doggie1989

Unfortunately I'm pretty sure the registration interface is unavoidable based on how GWT works today. The problem is that GWT doesn't support reflection, since the information that would be required isn't included in the compiled javascript. GWT's alternative is to use compile-time code generation via GWT.create, but the only information that can be passed to GWT.create is a single class literal. So if we want to be able to register different sets of handlers for each class (which is pretty unavoidable), we have to define a unique interface for each class so that the code generator can tell what it's supposed to generate. UiBinder and EventBinder both have the same problem.

Ray Cromwell of the GWT team posted a proposal several years ago on ways to relax this constraint and pass additional information to GWT.create, but I don't think there has been any work towards implementing it: http://timepedia.blogspot.com/2009/03/relaxing-constraints-on-gwtcreate.html. I might try bugging the GWT team about that again at some point or take a look at implementing it myself, but until then I'm pretty sure this is the best we can do.

Note that there's one small thing you can do if you're using Gin - if you inject the registration object into your class, it will be GWT.create'd automatically so you don't have to call GWT.create. I've updated the readme to show how to do this.

ekuefler avatar Dec 16 '13 01:12 ekuefler

Thanks for your reply.

Currently,such as gwt Editor ,UiBinder, we cannot avoid writing lots of inner Interfaces in the class...

doggie1989 avatar Dec 22 '13 13:12 doggie1989

Hi Will gwt 3.0 allow us to pass additional information to GWT.create ? any Google inner information? Regards

doggie1989 avatar Aug 12 '14 14:08 doggie1989

I'm not aware of anything - @gkdn might know if there are any plans along these lines.

ekuefler avatar Aug 17 '14 18:08 ekuefler

Not on our radar right now...

gkdn avatar Aug 18 '14 18:08 gkdn

Ahh, xapi does exactly that ("extend" GWT.create...). I actually added the ability to define your own magic methods so you can pass class literals, string/primitive literals, enums and opaque objects into an ast-driven generator. That is how I implemented literal-based reflection; SomeClass.class.getMethod("literalName", LiteralType.class) works by making .getMethod a magic method, which can then examine the instance object (SomeClass.class), and the arguments (JStringLiteral, JArrayType filled with JClassLiterals), to then invoke a generator and replace the JMethodCall with a different generated method.

For reference-based reflection, I have to enhance the class object by embedding runtime maps of methods, fields, constructors and annotations. If the method calls do not have all literals (cannot map back to class literal), then it goes into runtime-reference mode, where the class must be enhanced or else it will fail then. It can get fairly bloated, even with annotations to limit total retention, but it does work. However, I would always recommend pursuing use of compile-time reflection (using a TypeOracle) instead of runtime reflection, as you will get better performance doing so at compile-time.

In this case, I would actually recommend something like an apt annotation processor to generate a factory which does switch(bean.getClass().getName()) { case "all.types.referenced.in.App": }. Of course, this would pull in extra code that you may not need, so it's really up to you... But that is far better than enhancing all possible beans to include all possible methods and annotations... that would get real expensive, real fast.

Or probably the best option, if you use @Configuration objects to declare a bunch of @Bean annotated methods, just make a generator which can run on that config object, inspect all methods annotated with Bean, then inspect all those for types for methods annotated with @Subscribe. BeanEnhancer<MyConfig> config = GWT.create(MyConfig.class); and use the <when-type-assignable class="com.foo.BeanEnhancer" /> to define your generator.

JamesXNelson avatar Mar 30 '15 21:03 JamesXNelson