6.68. kink/javahost/JAVA_PROXY¶
6.68.1. JAVA_PROXY.new(Interface $handler ...[$config={}])¶
newは、メソッドの動作をKinkの関数$handlerに委譲するJavaオブジェクトを作る。
コンフィグメソッド:
• C.also_implement(Also_implement): default = []
• C.override_tostring
• C.override_equals
• C.override_hashcode
• C.override_default
• C.on_success($success): default = VAL.identity
• C.on_error($error): default = 例外を投げる関数
作られたJavaオブジェクトは、java.lang.reflect.Proxyのインスタンスになる。これは、インタフェースInterfaceを実装し、またAlso_implementが含むインタフェースを実装する。
プロキシの生成が成功したとき、newは、java値(proxy, Interface)を引数として$successを末尾呼び出しする。ここでproxyは、生成されたインスタンスである。
プロキシの生成が、Proxy.newProxyInstanceの仕様で説明されるように、IllegalArgumentExceptionで失敗したとき、newは、java値(iae, IllegalArgumentException)を引数として$errorを末尾呼び出し する。ここでiaeは、投げられたIllegalArgumentExceptionである。
呼び出し
プロキシのメソッドの呼び出しは、後述する例外を除いて、$handlerに委譲される。
メソッドが呼び出されると、新しい抽象スタックマシンが作られる。その抽象スタックマシンの中で、java.lang.reflect.Methodオブジェクトと、Javaメソッドの引数列からなるvecを引数として、$handlerが呼び出される。
$handlerの最初の引数はjava値(method, java.lang.reflect.Method)である。ここでmethodは、呼び出されたメソッドのjava.lang.reflect.Methodオブジェクトである。
$handlerの第二引数は、java値(arg, argType)のvecである。ここで、argTypeは対応するパラメータ型である。argTypeが参照型のとき、argは渡された引数そのものである。argTypeがプリミティブ型のとき、argはその引数をラップするラッパインスタンスである。
toStringの呼び出し
C.override_tostringが呼ばれなかったとき、プロキシのObject.toString()メソッドは、"java-kink-proxy(java.lang.Runnable)"のような文字列を戻す。
C.override_tostringが呼ばれたとき、toString()の呼び出しは、$handlerに委譲される。
equalsの呼び出し
C.override_equalsが呼ばれなかったとき、プロキシのObject.equals(Object)は、Javaの参照の同一性を、Javaの == 演算子でテストする。
C.override_equalsが呼ばれたとき、equals(Object)の呼び出しは、$handlerに委譲される。
hashCodeの呼び出し
C.override_hashcodeが呼ばれなかったとき、プロキシのObject.hashCode()は、System.identityHashCode()の結果を戻す。
C.override_hashcodeが呼ばれたとき、hashCode()の呼び出しは、$handlerに委譲される。
インタフェースのdefaultメソッドの呼び出し
C.override_defaultが呼ばれなかったとき、proxyが持つインタフェースのdefaultメソッドの呼び出しは、defaultメソッドの実装に委譲される。
C.override_defaultが呼ばれたとき、呼び出しは$handlerに委譲される。
呼び出しから戻る
メソッドの戻り型が参照型のとき、呼び出しがその参照型の値refを戻すには、$handlerはjava値(ref, *)を戻さなければならない。
メソッドの戻り型がchar, boolean, byte, short, int, long, float, doubleのいずれかのとき、呼び出しが値primitiveを戻すには、$handlerはjava値(wrapper, *)を戻さなければならない。ここでwrapperは、primitiveをラップするラッパインスタンスでなければならない。
メソッドの戻り型がvoidのとき、呼び出しが戻るには、$handlerはjava_throw以外の値を戻さなければならない。
呼び出しからJavaのThrowableを投げる
呼び出しがJavaのThrowableを投げるには、$handlerはjava_throwを戻さなければならない。
事前条件
Interfaceはjava値(cl, *)でなければならない。ここでclは、java.lang.Classのインスタンスでなければならない。
Also_implementはjava値(cl, *)のvecでなければならない。ここでclは、java.lang.Classのインスタンスでなければならない。
$successはjava値を取る関数でなければならない。
$errorはIllegalArgumentExceptionのjava値を取る関数でなければならない。
例: プロキシインスタンスを作る
:JAVA.require_from('kink/javahost/')
:JAVA_PROXY.require_from('kink/javahost/')
:IntUnaryOperator_class <- JAVA.class('java.util.function.IntUnaryOperator')
:Increment <- JAVA_PROXY.new(IntUnaryOperator_class){(:Method :Args)
Method.call_method('getName').to_kink_str == 'applyAsInt' || raise('unexpected method')
JAVA.int(Args.front.to_kink_num + 1)
}
:Double <- JAVA_PROXY.new(IntUnaryOperator_class){(:Method :Args)
Method.call_method('getName').to_kink_str == 'applyAsInt' || raise('unexpected method')
JAVA.int(Args.front.to_kink_num * 2)
}
:Increment_then_double <- Increment.call_method('andThen' Double) # call default implementation
:R <- Increment_then_double.call_method('applyAsInt' JAVA.int(3))
stdout.print_line(R.repr) # => (java "8" as int)
例: toStringをオーバーライドする
:JAVA.require_from('kink/javahost/')
:JAVA_PROXY.require_from('kink/javahost/')
:IntUnaryOperator_class <- JAVA.class('java.util.function.IntUnaryOperator')
:Object_class <- JAVA.class('java.lang.Object')
:Increment <- JAVA_PROXY.new(IntUnaryOperator_class
{(:Method :Args)
:Method_name = Method.call_method('getName').to_kink_str
branch(
{ Method_name == 'toString' } {
JAVA.string('IntUnaryOperator(increment the int)')
}
{ Method_name == 'applyAsInt' } {
JAVA.int(Args.front.to_kink_num + 1)
}
{ true } {
Method_name == 'applyAsInt' || raise('unexpected method')
JAVA.int(Args.front.to_kink_num + 1)
}
)
}
{(:C) C.override_tostring }
)
stdout.print_line(Increment.call_method('applyAsInt' JAVA.int(3)).repr)
# => (java "4" as int)
stdout.print_line(Increment.as(Object_class).call_method('toString').to_kink_str.repr)
# => "IntUnaryOperator(increment the int)"