6.72. kink/javahost/METHOD_HANDLE¶
Provides utility functions to manipulate java.lang.MethodHandle.
6.72.1. METHOD_HANDLE.invoke(Mh Args ...[$config={}])¶
`invoke` invokes the method handle `Mh` by MethodHandle.invokeWithArguments. `Args` is passed as the arguments.
Unlike Java.call_method, .call_static, and .new, `type` attributes of the elements of `Args` don't need to specify the parameter types. For example, they all can be java.lang.Object. It is because the type information is stored in the method handle itself.
A `java_call_config` value is passed to $config. See kink/javahost/JAVA for `java_call_config` type.
Result
1) If the return type of the method handle is a reference type `rt`, and the invocation returns `resultObj`, `invoke` tail-calls the success continuation with a `java` value (resultObj, rt).
2) If the return type `pt` of the method handle is char, boolean, byte, short, int, long, float or double, and the invocation returns a value, `invoke` tail-calls the success continuation with a `java` value (box, pt), where `box` is a wrapper instance of the returned value.
3) If the return type of the method handle is void, and the invocation returns, `invoke` tail-calls the success continuation with no arg.
4) If the invocation terminates throwing a Java exception `exceptionObj`, and the exception is an instance of one or more exception types specified by invocations of C.catch, `invoke` tail-calls the error continuation corresponding to the most specific exception type `et` with a `java` value (exceptionObj, et).
5) If the invocation terminates throwing a Java exception, and no exception type passed to C.catch matches the thrown exception, `invoke` raises a Kink exception.
Preconditions
`Mh` must be an `java` value of (mh, *), where `mh` is an instance of MethodHandle.
`Args` must be a `vec` of `java` values. `objectReference` attributes of the elements must be typable-as the corresponding parameter types of `mh`.
$config must be a function which takes a `java_call_config`.
6.72.2. METHOD_HANDLE.instance_method(Owner_class Method_name Param_classes Ret_class ...[$config={}])¶
`instance_method` looks up a method handle of a public instance method.
Config methods:
• C.on_success($success): default = VAL.identity
• C.on_no_such_method($no_such_method): default = a function which raises an exception
• C.on_illegal_access($illegal_access): default = a function which raises an exception
`instance_method` looks up a method using MethodHandles.publicLookup().findVirtual, where `Owner_class` is the class which owns the method, `Method_name` is the name of the method, `Param_classes` is the parameter types, and `Ret_class` is the type of the returned value.
Result
If the specified public method is found, `instance_method` tail-calls $success with a `java` value (mh, MethodHandle), where `mh` is the method handle of the method. The parameter types of the method handle will be `[Owner_class] + Param_classes`, and the return type will be `Ret_class`.
If an exception `nsme` of NoSuchMethodException is thrown, `instance_method` tail-calls $no_such_method with a `java` value (nsme, NoSuchMethodException).
If an exception `iae` of IllegalAccessException is thrown, `instance_method` tail-calls $illegal_access with a `java` value (iae, IllegalAccessException).
Preconditions
`Owner_class` must be a `java` value (oc, *), where `oc` is an instance of java.lang.Class.
`Method_name` must be a `str`.
`Param_classes` must be a `vec` of `java` values (pc, *), where `pc` is an instance of java.lang.Class
`Ret_class` must be a `java` val (rc, *), where `rc` is an instance of java.lang.Class.
6.72.3. METHOD_HANDLE.static_method(Owner_class Method_name Param_classes Ret_class ...[$config={}])¶
`static_method` looks up a method handle of a public static method.
Config methods:
• C.on_success($success): default = VAL.identity
• C.on_no_such_method($no_such_method): default = a function which raises an exception
• C.on_illegal_access($illegal_access): default = a function which raises an exception
`static_method` looks up a method using MethodHandles.publicLookup().findStatic, where `Owner_class` is the class which owns the method, `Method_name` is the name of the method, `Param_classes` is the parameter types, and `Ret_class` is the type of the returned value.
Result
If the specified method is found, `static_method` tail-calls $success with a `java` value (mh, MethodHandle), where `mh` is the method handle of the method. The parameter types of the method handle will be `Param_classes`, and the return type will be `Ret_class`.
If an exception `nsme` of NoSuchMethodException is thrown, `instance_method` tail-calls $no_such_method with a `java` value (nsme, NoSuchMethodException).
If an exception `iae` of IllegalAccessException is thrown, `instance_method` tail-calls $illegal_access with a `java` value (iae, IllegalAccessException).
Preconditions
`Owner_class` must be a `java` value (oc, *), where `oc` is an instance of java.lang.Class.
`Method_name` must be a `str`.
`Param_classes` must be a `vec` of `java` values (pc, *), where `pc` is an instance of java.lang.Class
`Ret_class` must be a `java` val (rc, *), where `rc` is an instance of java.lang.Class.
6.72.4. METHOD_HANDLE.constructor(Owner_class Param_classes ...[$config={}])¶
`constructor` looks up a method handle of a public constructor.
Config methods:
• C.on_success($success): default = VAL.identity
• C.on_no_such_method($no_such_method): default = a function which raises an exception
• C.on_illegal_access($illegal_access): default = a function which raises an exception
`constructor` looks up a constructor using MethodHandles.publicLookup().findConstructor, by `Owner_class` as the owner of the consturctor, and `Param_classes` as the parameter types.
Result
If the specified constructor is found, `constructor` tail-calls $success with a `java` value (mh, MethodHandle), where `mh` is the method handle of the constructor. The parameter types of the method handle will be `Param_classes`, and the return type will be `Owner_class`.
If an exception `nsme` of NoSuchMethodException is thrown, `constructor` tail-calls $no_such_method with a `java` value (nsme, NoSuchMethodException).
If an exception `iae` of IllegalAccessException is thrown, `constructor` tail-calls $illegal_access with a `java` value (iae, IllegalAccessException).
Preconditions
`Owner_class` must be a `java` value (oc, *), where `oc` is an instance of java.lang.Class.
`Param_classes` must be a `vec` of `java` values (pc, *), where `pc` is an instance of java.lang.Class
$success, $no_such_method, and $illegal_access must be functions which take a `java` value.
6.72.5. METHOD_HANDLE.proxy(Param_classes Ret_class $handler)¶
`proxy` returns a method handle which delegates the procedure to a Kink function $handler.
The result is a `java` value (mh, MethodHandle), where `mh` is a method handle which delegates the procedure to $handler. The parameter types of the method handle will be `Param_classes`, and the return type will be `Ret_class`.
Invocation of the method handle
When the method handle is invoked, a new abstract stack machine is created, and $handler is called in the abstract stack machine.
The arguments of the invocation are passed as the arguments of $handler. The arguments are passed as `java` values (arg, argType). Here, `argType` is the corresponding parameter type of the method handle. If `argType` is a reference type, `arg` is the passed argument itself. If `argType` is a primitive type, `arg` is a wrapper instance which wraps the argument.
To return from the invocation
If the return type of the method handle is a reference type, to order that the invocation return a value `ref` of the reference type, $handler must return a `java` value (ref, *).
If the return type of the method handle is char, boolean, byte, short, int, long, float, or double, to order that the invocation return a value `primitive`, $handler must return a `java` value (wrapper, *), where `wrapper` is a wrapper instance object which wraps `primitive`.
If the return type of the method handle is void, to order that the invocation return, $handler must return any value other than `java_throw`.
To throw a Java Throwable from the invocation
To order that the invocation throw a Java Throwable, $handler must return a `java_throw`.
Preconditions
`Param_classes` must be a `vec` of `java` values (pc, *), where `pc` is an instance of java.lang.Class
`Ret_class` must be a `java` val (rc, *), where `rc` is an instance of java.lang.Class.
Example: return an int
:JAVA.require_from('kink/javahost/')
:METHOD_HANDLE.require_from('kink/javahost/')
:Mh <- METHOD_HANDLE.proxy([JAVA.int_class JAVA.int_class] JAVA.int_class){(:X :Y)
:Sum = X.to_kink_num + Y.to_kink_num
JAVA.int(Sum)
}
:R <- METHOD_HANDLE.invoke(Mh [JAVA.int(10) JAVA.int(20)])
stdout.print_line(R.repr) # => (java "30" as int)
Example: throw an exception
:JAVA.require_from('kink/javahost/')
:JAVA_THROW.require_from('kink/javahost/')
:METHOD_HANDLE.require_from('kink/javahost/')
:RuntimeException_class <- JAVA.class('java.lang.RuntimeException')
:Mh <- METHOD_HANDLE.proxy([] JAVA.void_class){
JAVA_THROW.new(RuntimeException_class.new(JAVA.string('bang!')))
}
METHOD_HANDLE.invoke(Mh []){(:C)
C.catch(RuntimeException_class){(:Rte)
stdout.print_line('thrown: {}'.format(Rte.repr))
}
}
# => thrown: (java "java.lang.RuntimeException: bang!" as java.lang.RuntimeException)