How to get "double.class" by a "Double" Object

Viewed 252

description:

  • I need use getMethod, it requires the parameterTypes.
  • The origin method requires double (a primitive type, not Double), and I can't change origin method.
  • I can't just input double.class in parameterTypes, because the s maybe diffierent types, such as Integer(not int).
  • The method parameter in Foo.java are always and only primitive types.

code:

test.java
    public static void main( String args[] )
    {
        Object obj = new Foo();
        Object s = 1.2;
        String type = "Double";
        try {
            Method method = obj.getClass().getMethod("return" + type, s.getClass());// got NoSuchMethodException here, because it requires `double` not Double
            System.out.println(method.invoke(obj,s));
        } catch (NoSuchMethodException | IllegalAccessException |InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
Foo.java //(I can't change/add code/delete in this part)
public class Foo {
    public double returnDouble(double type){
        return type;
    }
    public int returnInt(int type){
        return type;
    }
}

what I have tried:

  • Use Map
    public static void main( String args[] )
    {
        Object obj = new Foo();
//        Object s = 1;
//        String type = "Int";
        Object s = 1.2;
        String type = "Double";
        Map<String, Class> methodClassMap = new HashMap<String, Class>() {{
            put("Double",double.class);
            put("Integer",int.class);
        }};
        try {
            Method method = obj.getClass().getMethod("return" + type, methodClassMap.get(s.getClass().getSimpleName()));
            System.out.println(method.invoke(obj,s));
        } catch (NoSuchMethodException | IllegalAccessException |InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
  • It worked, but I have to list all possible type of value the s.

question:

  • Any better solution than using Map? Maybe use generic?
1 Answers

When you know beforehand that the target method always uses a primitive types, you can use the unwrap() method of MethodType of the java.lang.invoke package.

Object obj = new Foo();
Object s = 1.2;
String type = "Double";
try {
    MethodType mt = MethodType.methodType(s.getClass(), s.getClass()).unwrap();
    Method method = obj.getClass().getMethod("return" + type, mt.parameterArray());
    System.out.println(method.invoke(obj, s));
} catch(ReflectiveOperationException e) {
    e.printStackTrace();
}

Alternatively, when you’re already using the method type of the java.lang.invoke package, you can also use a method handle to perform the invocation.

Object obj = new Foo();
Object s = 1.2;
String type = "Double";
try {
    MethodType mt = MethodType.methodType(s.getClass(), s.getClass()).unwrap();
    MethodHandle mh = MethodHandles.lookup().bind(obj, "return" + type, mt);
    System.out.println(mh.invoke(s));
} catch(Throwable e) {
    e.printStackTrace();
}

But note that unlike Reflection, the return type has to be correctly specified for the lookup. I’m assuming the same return type as the parameter type, like in your example.

Related