ekuefler / gwt-supereventbus

High-octane event bus for GWT
https://ekuefler.github.io/gwt-supereventbus
Apache License 2.0
39 stars 2 forks source link

Could supereverntbus be more super in future? #7

Open doggie1989 opened 10 years ago

doggie1989 commented 10 years ago

we need to do interface MyRegistration extends EventRegistration {} 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~!

ekuefler commented 10 years ago

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.

doggie1989 commented 10 years ago

Thanks for your reply.

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

doggie1989 commented 10 years ago

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

ekuefler commented 10 years ago

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

gkdn commented 10 years ago

Not on our radar right now...

JamesXNelson commented 9 years ago

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 config = GWT.create(MyConfig.class); and use the <when-type-assignable class="com.foo.BeanEnhancer" /> to define your generator.