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)"