3.34. kink/host_lang/java/JAVA

JAVA mod provides a way to operate on Java objects, values, classes and methods.

Host system integration provided by JAVA mod is seamfull. There is a clear boundary between Kink world and Java world. For example, a Java method cannot be called directly as a Kink fun like JRuby or Groovy. Instead, you have to use .call_method just like “Java_obj.call_method('toString')”.

There are several reasons behind the design.

1) Kink is fundamentally different from Java, both in the object system and the execution semantics. Thus, seamless integration is hard to achieve.

2) Generally, nontrivial software can benefit from a boundary layer between distinct systems.

3) With a clear boundary, Kink can evolve independent of Java version up.

3.34.1. type java_val

A java_val comprises a pair of (objectReference, staticType), where objectReference is the Java object reference, and staticType is the class object of the static type.

The static type is used to find instance methods and instance fields.

J.static_type

J.static_type returns a java_val of the static type.

The result of J.static_type is a java_val (st, java.lang.Class), where st is a class object which represents the static type of the java_val.

Example:

:JAVA.require_from('kink/host_lang/java/')
:Comparable_class <- JAVA.class('java.lang.Comparable')
:Static_type <- JAVA.string('foo').as(Comparable_class).static_type
stdout.print_line(Static_type.repr)
# Output:
#   Java_val(interface java.lang.Comparable as java.lang.Class)

J.dynamic_type

J.dynamic_type returns getClass() of the Java object referenced by J.

Precond: the Java object reference of J must not be null.

The result of J.dynamic_type is a java_val (dt, java.lang.Class), where dt is a class object which is the runtime class of the Java object reference of J.

Example:

:JAVA.require_from('kink/host_lang/java/')
:Comparable_class <- JAVA.class('java.lang.Comparable')
:Dynamic_type <- JAVA.string('foo').as(Comparable_class).dynamic_type
stdout.print_line(Dynamic_type.repr)
# Output:
#   Java_val(class java.lang.String as java.lang.Class)

J.typable_as?(Klass)

J.typable_as? returns whether the reference of J is “typable as” Klass.

The reference is “typable as” Klass if and only if:

1) the reference is null and Klass is a reference type, or

2) the reference is an instance of the Klass, or

3) the reference is an instance of Boolean, Character, Byte, Short, Integer, Long, Float or Double, and Klass is the corresponding primitive type class.

Precond: Klass must be a java_val of which reference is an instance of java.lang.Class.

The result of J.typable_as? is Kink true or false.

Example:

:JAVA.require_from('kink/host_lang/java/')
:Integer_class <- JAVA.class('java.lang.Integer')
:Long_class <- JAVA.class('java.lang.Long')
:Object_class <- JAVA.class('java.lang.Object')

# null can be typed as any reference types
stdout.print_line(JAVA.null.typable_as?(Integer_class).repr)  # => true
stdout.print_line(JAVA.null.typable_as?(JAVA.int_class).repr) # => false

# int(42), the reference of which is Integer.valueOf(42),
# is typeable as int, Integer and Object, but not as long or Long.
:Int <- JAVA.int(42)
stdout.print_line(Int.typable_as?(Integer_class).repr)    # => true
stdout.print_line(Int.typable_as?(JAVA.int_class).repr)   # => true
stdout.print_line(Int.typable_as?(Long_class).repr)       # => false
stdout.print_line(Int.typable_as?(JAVA.long_class).repr)  # => false
stdout.print_line(Int.typable_as?(Object_class).repr)     # => true

J.as(Klass)

J.as makes a new java_val chaning the static type to Klass.

Precond: Klass mut be a java_val (klass, any static type), where klass is an instance of java.lang.Class and J is typeable as klass.

The result of J.as is a java_val (ref, klass), where ref is same as the object reference of J.

Example:

:JAVA.require_from('kink/host_lang/java/')
:Integer_class <- JAVA.class('java.lang.Integer')

:Int <- JAVA.int(42)
stdout.print_line(Int.repr)                   # => Java_val(42 as int)
stdout.print_line(Int.as(Integer_class).repr) # => Java_val(42 as java.lang.Integer)

Note that you cannot perform widening or narrowing operations using this method. If you convert 42 to 42L for example, use constructor funs such as JAVA.long explicitly.

:JAVA.require_from('kink/host_lang/java/')

:Int <- JAVA.int(42)
stdout.print_line(Int.repr)  # => Java_val(42 as int)

:Long <- JAVA.long(Int.to_kink_num)
stdout.print_line(Long.repr) # => Java_val(42 as long)

J.eq_eq?(Another)

J.eq_eq? returns whether the referenes of J and Another are identical in the meaning of Java == operator.

Example:

:JAVA.require_from('kink/host_lang/java/')

# null is eq_eq? null, irrespective of their static types
:Null_string <- JAVA.null.as(JAVA.class('java.lang.String'))
:Null_integer <- JAVA.null.as(JAVA.class('java.lang.Integer'))
stdout.print_line(Null_string.eq_eq?(Null_integer).repr)  # => true

:Object_class <- JAVA.class('java.lang.Object')
:Str <- JAVA.string('foobar')
:Str_as_obj <- Str.as(Object_class)

# object is eq_eq? itself, irrespective their static types
stdout.print_line(Str.eq_eq?(Str_as_obj).repr)        # => true

# object is not eq_eq? another object
stdout.print_line(Str.eq_eq?(Object_class.new).repr)  # => false

J.null?

J.null? returns whehter the reference of J is null.

The result is Kink true or false.

J.to_kink_str

J.to_kink_str makes a Kink str from a Java string.

The reference of J must be an instance of java.lang.String.

J.to_kink_bool

J.to_kink_bool makes a Java bool from a Java boolean.

Precond: the reference of J must be an instance of java.lang.Boolean.

J.to_kink_num

J.to_kink_num makes a Kink num from a Java number.

Precond:

The object reference of J must be an instance of Character, Byte, Short, Integer, Long, Float, Double, BigInteger or BigDecimal. If the reference is an instance of Float or Double, it must be finite.

Conversion details:

If J is a Character, Byte, Short, Integer, Long or BigInteger, the scale of the result num is 0, and the mantissa of the result num is equal to the number itself.

If J is a Float or Double, the scale of the result num is the minimum non-negative scale on which the number can be exactly expressed, and the mantissa of the result num is J * (10 ^ scale).

If J is a BigDecimal, the scale of the result num is equal to the result of BigDecimal.scale(), and the mantissa is equal to the result of BigDecimal.unscaledValue().

Example:

:JAVA.require_from('kink/host_lang/java/')

:Ans <- JAVA.byte(42).to_kink_num
stdout.print_line(Ans.repr)           # => 42
stdout.print_line(Ans.scale.repr)     # => 0
stdout.print_line(Ans.mantissa.repr)  # => 42

:Pi <- JAVA.float(3.14).to_kink_num
stdout.print_line(Pi.repr)          # => 3.1400001049041748046875
stdout.print_line(Pi.scale.repr)    # => 22
stdout.print_line(Pi.mantissa.repr) # => 31400001049041748046875

If the reference of J is a NaN or infinite numbers, J.to_kink_num raises an exception.

J.to_kink_bin

J.to_kink_bin makes a Kink bin from a Java byte array.

Precond: the object reference of J must be an instance of byte[].

Contents of the byte array is copied to the bin val, thus modification to the byte array does not affect the result bin val.

Example:

:JAVA.require_from('kink/host_lang/java/')

:Bytes <- JAVA.byte_class.new_array_of(JAVA.byte(1) JAVA.byte(2) JAVA.byte(3))
:Bin <- Bytes.to_kink_bin
stdout.print_line(Bin.repr) # => BIN.of(0x01 0x02 0x03)

Bytes.array_set(0 JAVA.byte(100))
stdout.print_line(Bin.repr) # => BIN.of(0x01 0x02 0x03)

J.unwrap

J.unwrap returns the Kink val referred by J as an instance of org.kink_lang.kink.Val.

Precond: the object reference of J must be an instance of org.kink_lang.kink.Val, and the runtime of the val must be same as the current runtime.

Example:

:JAVA.require_from('kink/host_lang/java/')

:Str <- 'foo'
:Wrapped_str <- JAVA.wrap(Str)
stdout.print_line(Wrapped_str.repr) # => Java_val(StrVal(foo) as org.kink_lang.kink.Val)

:Unwrapped_str <- Wrapped_str.unwrap
stdout.print_line(Unwrapped_str.repr) # => "foo"
:Same? <- Unwrapped_str.val_id == Str.val_id
stdout.print_line(Same?.repr)         # => true

J.array_class

J.array_class returns a java_val of the array class of the component class refferred by J.

Precond:

The object reference of J must be an instance of java.lang.Class. The class must not be void class. If the class is an array class, its dimension must be equal to or less than 254.

Postcond:

The result of J.array_class is a java_val (arrayClass, java.lang.Class), where arrayClass the array class object.

Example:

:JAVA.require_from('kink/host_lang/java/')
:Array_class <- JAVA.int_class.array_class
stdout.print_line(Array_class.repr)  # => Java_val(class [I as java.lang.Class)

J.new_array(Size)

J.new_array returns a java_val of an array created with the Size and the component class J.

The elements are initialized as false if the component class is boolean, 0 if the component class is char, byte, short, int, long, float or double, null otherwise.

Precond:

The object reference of J must be an instance of java.lang.Class. The class must not be void class. If the class is an array class, its dimension must be equal to or less than 254.

Size must be a non-negative int num.

Postcond:

The result of J.new_array is a java_val (arrayObj, arrayClass), where arrayObj is the created array, and arrayClass is the array class.

Example:

:JAVA.require_from('kink/host_lang/java/')
:Array <- JAVA.int_class.new_array(2)
stdout.print_line(Array.repr)               # => Java_val([I@1ebd319f as [I)
stdout.print_line(Array.array_get(0).repr)  # => Java_val(0 as int)
stdout.print_line(Array.array_get(1).repr)  # => Java_val(0 as int)
stdout.print_line(Array.array_length.repr)  # => 2

J.new_array_of(E0 E1 ,,,)

J.new_array_of returns a java_val of an array created with elements E0, E1 ,,, and the component class J.

Precond:

The object reference of J must be an instance of java.lang.Class. The class must not be void class. If the class is an array class, its dimension must be equal to or less than 254.

E0, E1, ,,, must be a java_val the references of which are typable as the component class.

Postcond:

The result of J.new_array_of is a java_val (arrayObj, arrayClass), where arrayObj is the created array, and arrayClass is the array class.

Example:

:JAVA.require_from('kink/host_lang/java/')
:Array <- JAVA.int_class.new_array_of(JAVA.int(10) JAVA.int(20))
stdout.print_line(Array.repr)               # => Java_val([I@1ebd319f as [I)
stdout.print_line(Array.array_get(0).repr)  # => Java_val(10 as int)
stdout.print_line(Array.array_get(1).repr)  # => Java_val(20 as int)
stdout.print_line(Array.array_length.repr)  # => 2

J.array_length

J.array_length returns the length of the Java array J as a Kink num.

The object reference of J must be an array.

J.array_get(Ind)

J.array_get returns an element of the array J at the index Ind.

Precond:

The object reference of J must be an array.

Ind must be a Kink int num, and must be in the range of [0, length-of-J).

Postcond:

The result is a java_val (elemObj, componentType), where componentType is the component type of the array.

If the componentType is a reference type, elemObj is the element of the array itself.

If the componentType is a primitive type, elemObj is an instance of the corresponding wrapper class.

J.array_set(Ind Elem)

J.array_set stores the Elem to the array J at the index Ind.

Precond:

The object reference of J must be an array.

Ind must be a Kink int num, and must be in the range of [0, length-of-J).

Elem must be a java_val, the object reference of which is typable as the component type of the array.

J.throw

J.throw jumps with the Java exception J.

Precond: the object reference of J must be an instance of java.lang.Throwable.

If J.throw is invoked within the $thunk of JAVA.try, the rest of evaluation of $thunk is aborted, cleanup thunks registered by Fun.ensure are invoked as described in kink/CONTROL.escape, and $on_thrown of JAVA.try is called with the Java exception.

If J.throw is invoked outside of $thunk of JAVA.try, the Java exception is converted to a Kink exception pair, then it is reraised (see kink/CORE.reraise).

Example: throw Java exceptions within and without JAVA.try

:JAVA.require_from('kink/host_lang/java/')
:throw_runtime_exception <- {(:Msg)
  :Rte_class = JAVA.class('java.lang.RuntimeException')
  Rte_class.new(JAVA.string(Msg)).throw
}

JAVA.try(
  { throw_runtime_exception('within JAVA.try') }
  { raise('must not reach here') }
  {(:Ex)
    stdout.print_line('thrown: {}'.format(Ex.repr))
  }
)
# Output:
#   thrown: Java_val(java.lang.RuntimeException: within JAVA.try as java.lang.Throwable)

:TRACE.require_from('kink/')
{ throw_runtime_exception('outside of JAVA.try') }.try(
  { raise('must not reach here') }
  {(:Msg :Traces)
    TRACE.format_traces(Msg Traces).each{ stderr.print_line(\0) }
  }
)
# Output:
#   exception traces: from oldest to newest
#   [launch]
#   ,,,
#   [java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)]
#   exception message: exception: java.lang.RuntimeException: outside of JAVA.try

Example: cleanups thunks are invoked

:JAVA.require_from('kink/host_lang/java/')
:CONTROL.require_from('kink/')
JAVA.try(
  { CONTROL.with_on_exit{(:on_exit)
      on_exit{ stdout.print_line('bye') }
      on_exit{ stdout.print_line('ciao') }
      :Rte_class = JAVA.class('java.lang.RuntimeException')
      Rte_class.new(JAVA.string('jump')).throw
    }
  }
  { raise('must not reach here') }
  {(:Ex)
    stdout.print_line(Ex.repr)
  }
)
# Output:
#   ciao
#   bye
#   Java_val(java.lang.RuntimeException: jump as java.lang.Throwable)

J.get_field(Field_name)

J.get_field gets the content of the public instance field.

The field is looked up from the static type of J, using Class.getField(String).

Precond:

The static type must have the public instance field specified by the Field_name.

Postcond:

The result is a java_val (contentObj, fieldType).

fieldType is the declared type of the field.

If the field type is a reference type, contentObj is the content of the field.

If the field type is a primitive type, contentObj is an instance of the corresponding wrapper class.

Example:

:JAVA.require_from('kink/host_lang/java/')
:Vm <- JAVA.wrap(new_val).get_field('vm')
stdout.print_line(Vm.repr)
# Output:
#   Java_val(org.kink_lang.kink.Vm@1ebd319f as org.kink_lang.kink.Vm)

J.set_field(Field_name Content)

J.set_field sets the content to the public instance field.

The field is looked up from the static type of J, using Class.getField(String).

Precond:

The static type of J must have the public instance field specified by the Field_name.

The field must not be final. TODO: this check is not yet implemented.

Content must be a java_val, the object reference of which is typable as the declared type of the field.

J.get_static(Field_name)

J.get_static gets the content of the public static field.

The field is looked up from the class object which is the object reference of the java_val J.

Precond:

The object reference of J must be an instance of java.lang.Class.

The class must have a public static field specified by the Field_name.

Postcond:

The result is a java_val (contentObj, fieldType).

fieldType is the declared type of the field.

If the field type is a reference type, contentObj is the content of the field.

If the field type is a primitive type, contentObj is an instance of the corresponding wrapper class.

Example:

:JAVA.require_from('kink/host_lang/java/')
:Byte_class <- JAVA.class('java.lang.Byte')
:Byte_max <- Byte_class.get_static('MAX_VALUE')
stdout.print_line(Byte_max.repr)  # => Java_val(127 as java.lang.Byte)

J.set_static(Field_name Content)

J.set_static sets Content to the public static field.

The field is looked up from the class object which is the object reference of the java_val J.

Precond:

The reference of J must be an instance of java.lang.Class.

The class must have a public static field specified by the Field_name.

The field must not be final. TODO: this check is not yet implemented.

Content must be a java_val, the object reference of which is typable as the declared type of the field.

J.call_method(Method_name A0 A1 ,,,)

J.call_method calls a public instance method.

The method is looked up from the static type of J, using Class.getMethod(Method_name, A0.static_type, A1.static_type, ,,,).

Precond:

A0, A1 ,,, must be java_vals.

The static type of J must have the specified public instance method.

Postcond:

1) If the return type is a reference type, and the method terminates without throwing exception, J.call_method returns a java_val (resultObj, returnType), where resultObj is the return value of the method, and returnType is the declared return type of the method.

2) If the return type is char, boolean, byte, short, int, long, float or double, and the method terminates without throwing exception, J.call_method returns a java_val (resultObj, returnType), where resultObj is a wrapper instance of the return value, and returnType is the declared return type of the method.

3) If the return type is void, and the method terminates without throwing exception, J.call_method returns nada.

4) If the method terminates throwing a Java exception, the exception is treated as if J.throw method is called.

Example:

:JAVA.require_from('kink/host_lang/java/')
:ArrayList_class <- JAVA.class('java.util.ArrayList')
:Object_class <- JAVA.class('java.lang.Object')
:Lst <- ArrayList_class.new

# .as(Object_class) is required,
# because the method is looked up using static types of the args
Lst.call_method('add' JAVA.string('foo').as(Object_class))
Lst.call_method('add' JAVA.int(42).as(Object_class))

stdout.print_line(Lst.repr) # => Java_val([foo, 42] as java.util.ArrayList)

# call ArrayList.remove(int)
:Removed <- Lst.call_method('remove' JAVA.int(0))
stdout.print_line(Removed.repr) # => Java_val(foo as java.lang.Object)

# call ArrayList.remove(java.lang.Object)
:Success <- Lst.call_method('remove' JAVA.int(42).as(Object_class))
stdout.print_line(Success.repr) # => Java_val(true as boolean)

J.call_static(Method_name A0 A1 ,,,)

J.call_static calls a public static method.

The method is looked up from the class object which is the reference of the java_val J, using Class.getMethod(Method_name, A0.static_type, A1.static_type, ,,,).

Precond:

A0, A1 ,,, must be java_vals.

The class object which is the object reference of J must have the specified public static method.

Postcond:

Same as J.call_method.

J.new(A0 A1 ,,,)

J.new makes a new Java instance calling a public constructor.

The constructor is looked up from the class object which is the reference of the java_val J, using Class.getConstructor(A0.static_type, A1.static_type, ,,,).

Precond:

A0, A1 ,,, must be java_vals.

The class object which is the reference of J must have the specified public constructor.

Postcond:

1) If the new instance is created, J.new returns a java_val (resultObj, returnType), where resultObj is the new instance, and returnType is the class object which is the reference of J.

2) If the constructor terminates throwing a Java exception, the exception is treated as if J.throw method is called.

3.34.2. JAVA.java?(Val)

JAVA.java? returns whether Val is a java_val.

3.34.3. JAVA.string(Str)

JAVA.string makes a Java string.

Str must be a Kink str.

The result is a java_val (string, java.lang.String), where the string is a java.lang.String instance which is copied from Str.

3.34.4. JAVA.bytes(Bin)

JAVA.bytes makes a Java byte array from the Kink Bin val.

Bin must be a Kink bin val.

The result is a java_val (byteArray, byte[]), where byteArray is an array of bytes whose elements are copied from Bin.

3.34.5. JAVA.boolean(Bool)

JAVA.boolean returns a Java boolean corresponding to the Kink Bool.

Bool must be Kink true or false.

If Bool is true, JAVA.boolean returns a java_val (Boolean.TRUE, boolean).

If Bool is false, JAVA.boolean returns a java_val (Boolean.FALSE, boolean).

3.34.6. JAVA.char(Num)

JAVA.char returns a Java char corresponding to the Kink Num.

Num must be a Kink int num.

The result is a java_val (ch, char), where ch is an instance of java.lang.Character which is copied from the least significant 16 bits.

3.34.7. JAVA.byte(Num)

JAVA.byte returns a Java byte corresponding to the Kink Num.

Num must be a Kink int num.

The result is a java_val (bt, byte), where bt is an instance of java.lang.Byte which is copied from the least significant 8 bits.

3.34.8. JAVA.short(Num)

JAVA.short returns a Java short corresponding to the Kink Num.

Num must be a Kink int num.

The result is a java_val (sh, short), where bt is an instance of java.lang.Short which is copied from the least significant 16 bits.

3.34.9. JAVA.int(Num)

JAVA.int returns a Java int corresponding to the Kink Num.

Num must be a Kink int num.

The result is a java_val (n, int), where n is an instance of java.lang.Integer which is copied from the least significant 32 bits.

3.34.10. JAVA.long(Num)

JAVA.long returns a Java long corresponding to the Kink Num.

Num must be a Kink int num.

The result is a java_val (ln, long), where ln is an instance of java.lang.Long which is copied from the least significant 64 bits.

3.34.11. JAVA.float(Num)

JAVA.float returns a Java float numerically close to the Kink Num.

Num must be a Kink num.

The result is a java_val (fl, float), where fl is an instance of java.lang.Float, and fl is the result of conversion by BigDecimal.floatValue().

3.34.12. JAVA.double(Num)

JAVA.double returns a Java double numerically close to the Kink Num.

Num must be a Kink num.

The result is a java_val (dbl, double), where dbl is an instance of java.lang.Double, and dbl is the result of conversion by BigDecimal.doubleValue().

3.34.13. JAVA.big_integer(Num)

JAVA.big_integer returns a Java BigInteger corresponding to the Kink Num.

Num must be a Kink num.

The result is a java_val (bi, java.math.BigInteger), where bi is an instance of java.math.BigInteger, and the number represented by bi is equal to Num.

3.34.14. JAVA.big_decimal(Num)

JAVA.big_decimal returns a Java BigDecimal corresponding to the Kink Num.

Num must be a kink num.

The result is a java_val (bd, java.math.BigDecimal), where bd is an instance of java.math.BigDecimal, the scale of bd is equal to the scale of Num, and the unscaledValue of bd is equal to the mantissa of Num.

3.34.15. JAVA.wrap(Val)

JAVA.wrap make a java_val which represents the Kink Val.

JAVA.wrap return a java_val (kv, org.kink_lang.kink.Val), where kv is an instance of org.kink_lang.kink.Val which represents the Val.

The Val can be extracted from the result java_val using J.unwrap method.

Example:

:JAVA.require_from('kink/host_lang/java/')
:Str <- 'foo'
:Wrapper <- JAVA.wrap(Str)
stdout.print_line(Wrapper.repr)  # => Java_val(StrVal(foo) as org.kink_lang.kink.Val)
stdout.print_line(Wrapper.unwrap.repr)  # => "foo"

3.34.16. JAVA.boolean_class

JAVA.boolean_class returns a java_val which represents boolean.class.

The result is a java_val (boolean.class, java.lang.Class).

3.34.17. JAVA.char_class

JAVA.char_class returns a java_val which represents char.class.

The result is a java_val (char.class, java.lang.Class).

3.34.18. JAVA.byte_class

JAVA.byte_class returns a java_val which represents byte.class.

The result is a java_val (byte.class, java.lang.Class).

3.34.19. JAVA.short_class

JAVA.short_class returns a java_val which represents short.class.

The result is a java_val (short.class, java.lang.Class).

3.34.20. JAVA.int_class

JAVA.int_class returns a java_val which represents int.class.

The result is a java_val (int.class, java.lang.Class).

3.34.21. JAVA.long_class

JAVA.long_class returns a java_val which represents long.class.

The result is a java_val (long.class, java.lang.Class).

3.34.22. JAVA.float_class

JAVA.float_class returns a java_val which represents float.class.

The result is a java_val (float.class, java.lang.Class).

3.34.23. JAVA.double_class

JAVA.double_class returns a java_val which represents double.class.

The result is a java_val (double.class, java.lang.Class).

3.34.24. JAVA.void_class

JAVA.void_class returns a java_val which represents void.class.

The result is a java_val (void.class, java.lang.Class).

3.34.25. JAVA.null

JAVA.null returns a java_val which represents null reference.

The result is a java_val (null, java.lang.Object).

3.34.26. JAVA.true

JAVA.true returns a java_val which represents Java true.

The result is a java_val (true, boolean).

3.34.27. JAVA.false

JAVA.false returns a java_val which represents Java false.

The result is a java_val (false, boolean).

3.34.28. JAVA.find_class(Class_name)

JAVA.find_class tries to find a class, then returns [] or [Klass].

Class_name must be a Kink str, which represents a binary name of the class.

JAVA.find_class loads the specified class from the class loader which the Kink runtime belongs to.

If the class is found, JAVA.find_class returns a single element vec [Klass], where Klass is a java_val (the loaded class object, java.lang.Class).

If the class is not found, JAVA.find_class returns an empty vec [].

3.34.29. JAVA.class(Class_name)

JAVA.class tries to find a class, then returns the class.

Class_name must be a Kink str, which represents a binary name of the class.

JAVA.class loads the specified class from the class loader which the Kink runtime belongs to.

If the class is found, JAVA.class returns the Klass, where Klass is a java_val (the loaded class object, java.lang.Class).

If the class is not found, JAVA.class raises an exception.

Invoking JAVA.class(Class_name) is a shorthand way to invoke JAVA.find_class(Class_name).each($id { raise(__error_message__) }).

3.34.30. JAVA.try($thunk $on_returned $on_thrown)

JAVA try invokes a $thunk which may cause a Java exception, and if the $thunk throws an exception, traps and passes it to $on_thrown.

JAVA.try invokes $thunk with no args.

If $thunk terminates without throwing an exception, JAVA.try tail-calls $on_returned with the result of the $thunk. The result of the $thunk can be any Kink val, not restricted to a java_val.

If $thunk terminates with throwing an exception, which can be any instance of java.lang.Throwable, JAVA.try tail-calls $on_thrown with a java_val (th, java.lang.Throwable).

Example:

:JAVA.require_from('kink/host_lang/java/')
:Integer_class <- JAVA.class('java.lang.Integer')
:attempt_parse_int <- {(:Str)
  JAVA.try(
    { Integer_class.call_static('parseInt' JAVA.string(Str)) }
    {(:Int)
      'parsed as {}'.format(Int.repr)
    }
    {(:Ex)
      'could not parse: {}'.format(Ex.call_method('toString').to_kink_str)
    }
  )
}
stdout.print_line(attempt_parse_int('42'))
# Output:
#   parsed as Java_val(42 as int)

stdout.print_line(attempt_parse_int('boo'))
# Output:
#   could not parse: java.lang.NumberFormatException: For input string: "boo"