3

Say I have the following code...

@FunctionalInterface
static interface MessageFunction<T> {
    void send(T obj);
}

static @interface Message {
    Class<?> value();
}

static class Foo {

    @Message(String.class)
    MessageFunction<String> bass = (string) -> { 
        // Do Stuff
    };
}

static class MessageManager {

    Map<Class<?>, MessageFunction<?>> messages = new HashMap<>();

    public void register(Object obj) {

        for (Field field : obj.getClass().getDeclaredFields()) {
            Message message = field.getAnnotation(Message.class);
            if (message != null) {
                MessageFunction<?> function;

                try {
                    function = (MessageFunction<?>) field.get(obj);
                } catch (IllegalArgumentException | IllegalAccessException e) {
                    e.printStackTrace();
                    return;
                }

                Method sendMethod;

                try {
                    // Will this work?
                    sendMethod = function.getClass().getDeclaredMethod("send", Object.class);
                } catch (NoSuchMethodException | SecurityException e) {
                    e.printStackTrace();
                    return;
                }

                // How do I do something like this?
                /*if (sendMethod.testParamaters(message.value())) {
                    this.messages.put(message.value(), function);
                }*/
            }
        }
    }
}

public static void main(String[] args) {
    MessageManager manager = new MessageManager();
    manager.register(new Foo());
}

I am reflecting a field that references an @FunctionalInterface of a generic type. Because the method parameter is also generic I have no way of knowing what parameters it accepts, Thus I must pass it along through other means (the annotation).

The issue is that there is the annotation value and the generic type do not have to match and there seems to be no way to check. I wan't it to fail in registration if the type listed in the annotation would not be accepted into the send method.

How would I go about thing this without actually calling the method. Is there a way? Better yet although I know its most likely impossible, is there a way to know what the parameter type is without the annotation?

Soren Endon
  • 41
  • 1
  • 5
  • 1
    Possible duplicate of [Get generic type of class at runtime](http://stackoverflow.com/questions/3403909/get-generic-type-of-class-at-runtime). Basically the answer is "can't be done" for a lambda. – Radiodef Feb 08 '15 at 07:26
  • I am aware of the answers to other questions about getting generic types at run time. However those solutions do not seem to work when dealing with a lambda for a generic functional interface – Soren Endon Feb 08 '15 at 21:43
  • 1
    I discovered [TypeTools](https://github.com/jhalterman/typetools) mentioned is another question on stack over flow. Although it does not directly solve the question I have asked, it has solved my particular issue. – Soren Endon Feb 09 '15 at 06:13

2 Answers2

0

The following is just a suggestion, I have used it in my project. But it is not a perfect solution for the question. May be you can download the source of GenericHibernateDao framework and see the sourcecode of method "getTypeArguments". I think it is so cool!.

// get a class object for your entity
Class clazz = ...
Type type = clazz.getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            Type trueType = ((ParameterizedType)type).getActualTypeArguments()[0];
            Class modelClass = (Class) trueType;
            // Now you can creat an Instance in you generic parameterType
            Object entity  = modelClass.forInstance();
        } 
MageXellos
  • 154
  • 1
  • 9
  • I found something similar to this else ware on stack overflow however it does not work. I think its because the class in question is not a declared class but a lambda. As a result it can not be cast to ParameterizedType. This is just a guess based on my observations, I actually don't know. – Soren Endon Feb 08 '15 at 17:47
0

I do something similar in some of my code Here is a snippet.

Method[] meths = actionClass.getMethods();
                for (Method meth : meths) {
                    Class<?>[] pTypes = meth.getParameterTypes();

                    /*
                     * Filter out all methods that do not meet correct
                     * signature. The correct signature for an action method
                     * is: String actionName(HttpServletRequest request)
                     */
                    //...check for the correct number of params and the correct param type
                    if (pTypes.length != 1 || !HttpServletRequest.class.toString().equals(pTypes[0].toString())) {
                        continue;
                    } else {
                        //...check for return type
                        if (!String.class.toString().equals(meth.getReturnType().toString())) {
                            continue;
                        }
                    }

                    //If you make it here than that means the method 
                    //meets the requirements to be a full fledged action.
                    //...
                }
Jose Martinez
  • 11,452
  • 7
  • 53
  • 68