Cómo obtener un objeto de método para la implementación de una interfaz genérica en Java

In my case I want to find out if apply method's parameter for given implementation of Guayaba Function interface is annotated @Nullable. Method to be implemented:

boolean isNullableArgument(Class<? extends Function<?,?>> function);

I don't know how to get implemented apply método de function clase.


E.g. there could be Function implementations like this:

new Function<String,Integer>() {
    public Integer apply(String input) { … }
    public Integer apply(Integer input) { … }
}

preguntado el 12 de septiembre de 13 a las 00:09

I don't think the possible function implementation you describe would actually be legal. Have you tried it? -

@LouisWasserman I've found a solution. -

3 Respuestas

Here's a quick and dirty solution. Don't copy and paste it directly - it's only meant as an example to get you started.

static boolean applyHasAnnotation(
        @SuppressWarnings("rawtypes") final Class<? extends Function> functionType,
        final Class<? extends Annotation> annotationType
) throws SecurityException, NoSuchMethodException {
    //for each directly implemented interface,
    for (final Type interfaceType : functionType.getGenericInterfaces()) {
        //if the interface is parameterized,
        if (interfaceType instanceof ParameterizedType) {
            final ParameterizedType genericInterfaceType = (ParameterizedType)interfaceType;
            //if the interface is Function
            if (genericInterfaceType.getRawType() == Function.class) {
                //get the type argument for T
                final Type inputType = genericInterfaceType.getActualTypeArguments()[0];
                //get its raw type
                final Class<?> rawInputType =
                        (inputType instanceof ParameterizedType)
                        ? (Class<?>)((ParameterizedType)inputType).getRawType()
                        : (Class<?>)inputType;
                //use it to find the apply implementation
                final Method applyMethod = functionType.getDeclaredMethod("apply", rawInputType);
                //for each annotation on its first (and only) parameter,
                for (final Annotation inputAnnotation : applyMethod.getParameterAnnotations()[0]) {
                    //if its type is the specified annotation type, return true
                    if (inputAnnotation.annotationType() == annotationType) {
                        return true;
                    }
                }
                return false;
            }
        }
    }
    //a more complicated inheritance hierarchy has defeated us
    throw new IllegalArgumentException("Function info not found.");
}

In actuality, you'll want to code the various concerns separately:

  • finding the generic interface on the implementing type
  • buscando el F type argument to the generic interface
  • buscando el apply implementación
  • checking its parameter for a given annotation

As pointed out in the code, this solution easily breaks for more complicated type hierarchies, for example:

abstract class LongFunction<T> implements Function<Long, T> { }

A new LongFunction<String> { } seria un Function<Long, String> but the above method would not location the generic Function interface on its runtime type.

Respondido el 12 de Septiembre de 13 a las 03:09

La solucion es:

import com.google.common.base.Function;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Map;
import javax.annotation.Nullable;
import org.apache.commons.lang3.reflect.TypeUtils;

public class FunkUtils { private FunkUtils() {}

    public static boolean isNullableArgument(Class<? extends Function> functionClass) throws Exception {
        Map<TypeVariable<?>,Type> typeArgs = TypeUtils.getTypeArguments(functionClass, Function.class);
        TypeVariable<?> argTypeParam = Function.class.getTypeParameters()[0];
        Type argType = typeArgs.get(argTypeParam);
        Class argClass = TypeUtils.getRawType(argType, null);
        Method applyMethod = functionClass.getDeclaredMethod("apply", argClass);
        Annotation[] argAnnos = applyMethod.getParameterAnnotations()[0];
        for (int i = 0; i < argAnnos.length; i++) {
            if (argAnnos[i] instanceof Nullable) return true;
        }
        return false;
    }
}

There is a bug in TypeUtils.getTypeArguments in commons-lang3 version 3.1, but it is fixed in 3.2, that is under development now.

Respondido el 13 de Septiembre de 13 a las 16:09

If I got you question right, you want to do some validation of the annotation in the apply method. You would need to use reflection este caso (especialmente este método). It would be something like (I will just make a draft omitting the exceptions):

this.getClass().getMethod("apply", parameter.getClass()).getParameterAnnotations()

Respondido el 12 de Septiembre de 13 a las 01:09

I don't think the OP knows what parameter.getClass() is at runtime. Look at the method that they want to implement: boolean isNullableArgument(Class<? extends Function<?,?>> function);. - Muel

The main problem is how to get parameter from your “draft”. - Timofey Gorshkov

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.