简体   繁体   中英

MethodHandle cast return type

I try to link methods together through methodhandles, some of them are from generic types. If a function returns a generic type I have to specify Object.class for the MethodType but I see no easy way to convert it back into the generic type parameter type. In most cases it's no problem because invoke seem to convert them automatically but I must create mhs which could be run with invokeExact. Is there no easy way to cast with methodhandles?

My testcode:

public static void main(String[] args) throws Throwable {
    class Prefixer {
        public static String prefix(String s) {
            return "Number: " + s;
        }
    }
    IntFunction<String> converter = Integer::toString;

    var lookup = MethodHandles.lookup();
    var prefixMH = lookup.findStatic(Prefixer.class, "prefix", MethodType.methodType(String.class, String.class));

    var converterMH = lookup.findVirtual(IntFunction.class, "apply", MethodType.methodType(Object.class, int.class));
    converterMH = converterMH.bindTo(converter);

    /* Doesn't work because converter is a (int)Object and no (int)String
    var mh = MethodHandles.filterArguments(prefixMH, 0, converterMH);
     */

    /* Does work for invoke but not for invokeExact
    var prefixCasted = MethodHandles.explicitCastArguments(prefixMH, MethodType.methodType(String.class, Object.class));
    var mh = MethodHandles.filterArguments(prefixCasted, 0, converterMH);
    */
    /* Does work for invoke but not for invokeExact */
    var mh = MethodHandles.filterArguments(prefixMH, 0, converterMH.asType(MethodType.methodType(String.class, int.class)));

    System.out.println(mh.invoke(12));
    System.out.println(mh.invokeExact(42));
}

Your current code looks okay to me, you just need to use a cast at the call site as well:

System.out.println((String) mh.invokeExact(42));

Otherwise the type at the call site will be (int)Object which doesn't match the type of the MethodHandle (int)String and you get a WMTE.

The invoke version of the call you have:

System.out.println(mh.invoke(12));

Will implicitly convert the type of mh into (int)Object (the type of the call site) using an asType call, and then invoke the resulting method handle.

If you want to do that explicitly and use invokeExact you could do:

mh = mh.asType(MethodType.methodType(Object.class, int.class));
System.out.println(mh.invokeExact(42));

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