Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Interfaces like in guava #67

Open
Bellski opened this issue Apr 29, 2014 · 9 comments
Open

Support Interfaces like in guava #67

Bellski opened this issue Apr 29, 2014 · 9 comments

Comments

@Bellski
Copy link

Bellski commented Apr 29, 2014

Hello. Would be great if mbassador supports interfaces
like:
public interface HasSessionEventHandlers {
@handler
public void onBind(BindEvent bindEvent);
}

@bennidi
Copy link
Owner

bennidi commented Apr 30, 2014

Good call! Somehow it didn't occur to me but it obviously makes a lot of sense. I will include that into the next release. That also raises the question of how to deal with conflicting Handler definitions when multiple interfaces define the same handler. I think I would disallow such a configuration with a validation error. Any thoughts on that?

@bennidi bennidi added this to the 1.1.12 milestone Jun 30, 2014
@bennidi bennidi modified the milestones: 1.1.11, 1.1.12 Jul 28, 2014
@ssindelar
Copy link

Since Java 8 this also has the advantage that it would be possible to add handlers using lambda-expressions that implement the annotated interface.

I think just disallowing two @handler definitions on the same method implementation should be sufficient. Otherwise you would need to have some sophisticated overwrite logic.
A simple override mechanic, which maybe worth implementing, would be to just use the lowest @handler annotation in a linear list of overriding methods.

@bennidi
Copy link
Owner

bennidi commented Aug 13, 2014

Agree to the @Handler override logic.
Regarding Java 8: I have not yet paid much attention to the topic.I have been desperately awaiting lambdas and default methods in interfaces and I think it is a great feature but I am currently focusing much moreon Javascript so I don't know,when I will have the time to investigate the possibilities of Java 8 here.

@amal
Copy link

amal commented Nov 18, 2014

Lambdas support is really lacking

@amal
Copy link

amal commented Nov 20, 2014

I've added basic support (no Enveloped) for Java 8 lambdas (FunctionalInterface) and similars from other JVM languages (like Kotlin) with custom MetadataReader.

Code snippet (in Kotlin):

import com.azagroup.anizoptera.common.reflection.invokeMethod
import net.engio.mbassy.common.ReflectionUtils
import net.engio.mbassy.listener.*

public class AzaMetadataReader : MetadataReader()
{
    override fun getMessageListener(target: Class<*>): MessageListener<*>
    {
        val listener = super.getMessageListener(target)
        if (listener.getHandlers().isNotEmpty())
            return listener


        // FunctionalInterface and similars support

        // We support only classes with one method
        val methods = target.getDeclaredMethods().filter { !it.isBridge() }
        if (methods.size() > 1)
            return listener

        // We support only methods with one parameter
        val handler = methods.first()
        if (handler.getParameterCount() != 1)
            return listener

        // Parameter should be specific, not java.lang.Object
        val parameter = handler.getParameterTypes().first()
        if (parameter == javaClass<Any>())
            return listener

        val handlerConfig: Handler = ReflectionUtils.getAnnotation(target, javaClass<Handler>())
            ?: ReflectionUtils.getAnnotation(javaClass<Stub>(), javaClass<Handler>())

        val handlerProperties = MessageHandler.Properties.Create(
            handler, handlerConfig, getFilter0(handlerConfig), listener)

        val handlerMetadata = MessageHandler(handlerProperties)
        listener addHandler handlerMetadata

        return listener
    }


    private fun getFilter0(subscription: Handler): Array<IMessageFilter<*>>?
        // Reflection call to private method, ugly, but working :)
        = invokeMethod("getFilter", subscription) as Array<IMessageFilter<*>>?

    // Stub for clear Handler annotation instance
    private Handler class Stub
}

May be this snippet will help to add support to the very library :)

@bartweber
Copy link

Valuable enhancement!

@chriskingnet
Copy link
Contributor

Hi,

I am a big fan of this library and have used it in multiple projects now. Thanks for all your hard work on it!

I would love to be able to subscribe to event using lambda expressions... so was going to have a go at implementing a solution to this.

Just wondering if there was any more recent thoughts on how to achieve this? Given that I haven't really much experience with the codebase - is this reletively simple to implement? I too like the idea of a simple "latest handler overrides the previous" approach to multiple handler implementations.

Cheers!

@chriskingnet
Copy link
Contributor

chriskingnet commented Aug 25, 2017

Add-on to previous message:

I have a solution for the first part of this (basic interface support). How do you feel about using Java8 idioms within the codebase (I guess it remains supporting 1.6?) But either way adding support for this part seems straight forward.

The second part seems a little trickier. I implemented a simple functional interface, something like:

public interface IListenerFunction<T> {

    @Handler
    void handle(T message);
}

This doesn't seem to play nicely, however, when I override the subscription() method to accept it. I think it has something to do with the typing. I can dig a little deeper, but will wait for some feedback (in case there is a better approach I have missed).

So for now I have a working solution to subscribing using interfaces (however not allowing for enveloping yet), but currently no solution to support lambda.

Sorry if I have not yet understood the code well enough to be asking clear questions! Please let me know if I can clarify further! :)

EDIT: Updated after learning more about implenting a @FunctionalInterface and realising my question was confusing!

@chriskingnet
Copy link
Contributor

I have created a PR (#153) with just the interface support for now, and not followed up on supporting lambda. If get more time I will continue to try and include the lambda support - but thought the interface support might be useful anyway.

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

No branches or pull requests

6 participants