Calling Java Code from PrologJ

Overview

PrologJ allows Prolog code to access the public methods and fields of Java objects and classes, and to create Java objects, using facilities based on Java reflection.

Builtin Predicates

Two new built-in predicate are added to support calling Java code, and to allow recognizing Prolog terms that are Java objects, not standard Prolog terms.

Extensions to Builtin Predicates

One core predicate is extended to allow access to the fields of Java objects

Parameter Specifiers

Because Java allows several methods/constructors to have the same name but different parameter type signatures, and because Java reflection looks up methods or constructors in a class based on the exact specification of parameter types, it is necessary to explicitly specify the types of the parameters of a call from PrologJ to a Java method or constructor. (The needed information is more than what can be inferred from the Prolog term types).

If the Method argument to the built-in predicate @/2 is a compound term, then its arguments are specifiers for the parameters to be used in calling the Java method or constructor.

A parameter specifier must either be atomic, or it must a compound term of the form null/1, widen/2, array/1 or array/2, or it must be a compound term of arity 1 whose functor is one of the values listed below. It is an error for a parameter specifier to be an uninstantiated variable.

Example: Several of the options for parameter specifiers appear in the examples for @/2 above.

Example: The following (admittedly contorted) example illustrates most of the options for parameter specifiers.

Suppose that there exists a Java class with the following definition:


public class ParameterListDemo
{
    public static void demo(int n,
                            Object o1,
                            Object o2, 
                            int [] intArray,
                            String [] stringArray,
                            Object [] objectArray1,
                            Object [] objectArray2)
    {
        System.out.println("n = " + n);
        System.out.println("o1 = " + o1);
        System.out.println("o2 = " + o2);
        System.out.println("intArray length = " + intArray.length);
        for (int i = 0; i < intArray.length; i ++)
            System.out.println("intArray[" + i + "] = " + intArray[i]);
        System.out.println("stringArray length = " + stringArray.length);
        for (int i = 0; i < stringArray.length; i ++)
            System.out.println("stringArray[" + i + "] = " + stringArray[i]);
        System.out.println("objectArray1 length = " + objectArray1.length);
        for (int i = 0; i < objectArray1.length; i ++)
            System.out.println("objectArray1[" + i + "] = " + objectArray1[i]);
        System.out.println("objectArray2 length = " + objectArray2.length);
        for (int i = 0; i < objectArray2.length; i ++)
            System.out.println("objectArray2[" + i + "] = " + objectArray2[i]);
    }
}

Then the following Java code will result in the output shown below:


class('ParameterListDemo') @ demo(
    42, 
    widen('java.lang.Object', hello), 
    null('java.lang.Object'),
    array(long, [ 1, byte(2), short(3), int(4), long(5), long(6),
          'Byte'(7), 'Short'(8), 'Integer'(9), 'Long'(10) ]),
    array([ hello, world ]), 
    array([ widen('java.lang.Object', hello), world ]),
    array('java.lang.Object', [])).

Output:


n = 42
o1 = hello
o2 = null
longArray length = 10
longArray[0] = 1
longArray[1] = 2
longArray[2] = 3
longArray[3] = 4
longArray[4] = 5
longArray[5] = 6
longArray[6] = 7
longArray[7] = 8
longArray[8] = 9
longArray[9] = 10
stringArray length = 2
stringArray[0] = hello
stringArray[1] = world
objectArray1 length = 2
objectArray1[0] = hello
objectArray1[1] = world
objectArray2 length = 0

Limitations arising from the use of Java Reflection

The facilities described here are implemented by using the mechanisms provided by Java reflection - specifically the getConstructor(), getField(), and getMethod() methods of class Class and the various facilities provided in package java.lang.reflect. The use of these mechanisms creates certain requirements for the implementation of the facilities for accessing Java from PrologJ:

  1. Only public methods, constructors, and fields can be accessed.
  2. Class names must be specified in fully-qualified form - e.g. the class String must be referred to by the atom 'java.lang.String' . (Where primitive class names are allowed, the standard name of the primitive class can be used - e.g. int).
  3. The specifiers for parameters of methods or constructors must specify the exact same class name as occurs in the signature of the method or constructor being used - e.g. in the first example above, it was necessary to widen a String parameter ('What do you think?') to class Object because the showInputDialog method of class JOptionPane declares its second parameter as being of class Object. However, it was not necessary to widen 'Hello World' in the second example, because the constructor of JLabel is declared to take a String parameter.
Copyright © 2005 - Russell C. Bjork. See the file See file COPYING in the root directory for copyright information.

Valid XHTML 1.0!