Java Interop
JFuncMachine provides several expressions for interacting with Java objects. JFuncMachine does not provide any kind of data structures, so it is anticipated that language implementations will use Java classes to implement the structures they need, making the Java Interop expressions extremely important.
A language implementation has to do a little more work here than usual, because JFuncMachine doesn’t try to inspect any Java objects referenced in Java interop, meaning it can compile classes to reference classes that aren’t in the classpath at compile time. You have to supply fully-qualified class names as strings rather than just supplying the class, and you may need to supply parameter types in order to help JFuncMachine locate the correct method. For instance, if a method argument has a type that is a subclass of the type the method expects, JFuncMachine doesn’t know that and without the parameter type being specified, it would look for a method that takes the subclass type.
CallJavaConstructor
In order to create an instance of a Java object, you must
call its constructor. Although down in the Java Virtual
Machine the creation of an object and the execution of
its constructor method are actually two different operations,
JFuncMachine consolidates these into CallJavaConstructor,
making it work like the Java new operator.
In its simplest form, you can call a constructor by just providing the fully-qualified class name and the expressions for the constructor parameters. Since the type of each argument expression might not be the exact type needed to call the constructor, you can also provide an array of parameter types to specify what types the constructor actually requires.
Here is an example that calls the default constructor for an object (the no-argument constructor):
MethodDef method = new MethodDef("testjava", Access.PUBLIC, new Field[]{},
new ObjectType(ToyClass.class.getName()),
new CallJavaConstructor(ToyClass.class.getName(), new Expression[0]));CallJavaMethod
To invoke a non-static method on a Java object, you must supply the fully-qualified class name, the name of the method, its return type, an expression containing the object whose method is being invoked, and the arguments to the method. As with the constructor, you may also want to supply the parameter types for the method, as the values in the argument expressions may have slightly different types.
Here is an example of a Java method call:
new CallJavaMethod(ToyClass.class.getName(), "addMember",
SimpleTypes.INT, new GetValue("obj", new ObjectType(ToyClass.class.getName())),
new Expression[] { new IntConstant(22) }));CallInterfaceMethod
Java distinguishes between calling an object method and calling a method defined in an interface. The only difference between this and the normal method invocation is that instead of supplying a class name, you supply a fully-qualified interface name.
Here is an example that calls through an interface:
new CallJavaInterface(ToyInterface.class.getName(), "addMember",
SimpleTypes.INT, new GetValue("obj", new ObjectType(ToyInterface.class.getName())),
new Expression[] { new IntConstant(22) }));CallJavaStaticMethod
Calling a static method is similar to calling a regular method, you just don’t supply a target object. Here is an example static method call:
new CallJavaStaticMethod(ToyClass.class.getName(), "addStatic",
SimpleTypes.STRING,
new Expression[] { new GetValue("str", SimpleTypes.STRING) }));CallJavaSpecialMethod
There are a few kinds of methods, such as private ones, that
require a different calling mechanism in the JVM. For these, you
use CallJavaSpecialMethod, with the same parameters as you
would for a normal method:
new CallJavaSpecialMethod("org.jfuncmachine.test.TestJava",
"privateMethod", SimpleTypes.STRING,
new GetValue("this",
new ObjectType("org.jfuncmachine.test.TestJava")),
new Expression[] { new GetValue("x", SimpleTypes.STRING) }));CallJavaSuperConstructor
Although the invocation of a Java super constructor is
one of the circumstances that requires the special method
invocation, JFuncMachine provodes a separate expression
to call the superconstructor. In this particular case, you
don’t have to supply the class name, just the target object
and the argument expressions. You can also provide the argument
types if necessary. Note that in the example below the
type being specified is in the GetValue call, and not
for the CallJavaSuperConstructor expression itself.
new CallJavaSuperConstructor(new GetValue("this",
new ObjectType("org.jfuncmachine.test.TestJava")),
new Expression[] { new IntConstant(20)}));GetJavaField
To fetch the value of a Java field, you must supply the class name that contains the field, the name of the field, its type, and a target expression that yields the object containing the field.
new GetJavaField(ToyClass.class.getName(), "memberInt", SimpleTypes.INT,
new GetValue("obj", new ObjectType(ToyClass.class.getName()))));GetJavaStaticField
To fetch a static Java field value, you supply the class name, the field name, and its type, but since it is static you don’t need to supply a target value.
new GetJavaStaticField(ToyClass.class.getName(),
"staticString", SimpleTypes.STRING));SetJavaField
To set a Java field value, you must supply all the same things as with getting a field - class name, field name, type, and target object, and then you must also supply an expression that generates the value to store in the field.
new SetJavaField(ToyClass.class.getName(), "memberInt", SimpleTypes.INT,
new GetValue("obj", new ObjectType(ToyClass.class.getName())),
new GetValue("i", SimpleTypes.INT)));SetJavaStaticField
Since a static field doesn’t require a target, the SetJavaStaticField
expression is just like SetJavaField except that you don’t supply
a target object.
new SetJavaStaticField(ToyClass.class.getName(),
"staticString", SimpleTypes.STRING,
new GetValue("str", SimpleTypes.STRING)));