简体   繁体   中英

How can I test if a Method will accept a parameter type?

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?

Try TypeTools . First you'll need to obtain a reference to the declaring class for the bass which you're obtaining inside of your register method:

Class<?> bassClass = field.getDeclaringClass();

Then you can use TypeTools to resolve the type argument T that it supplies for MessageFunction:

Class<?> msgType = TypeResolver.resolveRawArgument(MessageFunction.class, bassClass);

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();
        } 

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.
                    //...
                }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM