Walnut/Ordinary Programming/Interfacing to Java
Interfacing to Java
Importing classes from the Java API
We can import a class from the underlying Java virtual machine with the import statement, and speak to the Java object much as we would speak to an E object: replace vector as example
# E sample #create a single vector with a direct call to Java def myVector := <unsafe:java.util.makeVector>() myVector.addElement("abc") #create a makeVector function which can be called repeatedly to make more vectors def makeVector := <unsafe:java.util.makeVector> def vector2 := makeVector() # create a shorthand for the java.util package, that gives quick access to all the # classes in java.util def <util> := <unsafe:java.util.*> def vector3 := <util:makeVector>()
In the example, we showed 3 ways of getting a Java object, which are roughly comparable to the different styles of using "import" in Java. If you just want one vector, you can get it by directly calling the vector constructor. If you plan to make many vectors, you can import the class into a variable. And if you plan to use many classes in a particular package, you can create your own representative for the package that you can use instead of "<unsafe>".
Note that the angle-brackets here are simply syntactic sugar: <util> is short for util__uriGetter and <util:makeVector> is short for util__uriGetter.get("makeVector").
Note also that E prefixes every Java class name with "make". The idea here is to make existing Java classes match the naming conventions of E constructors.
We have now seen 3 uriGetters, file:, unsafe:, and the programmer-defined util:. Four other uriGetters are also predefined, swing: (for accessing javax.swing) and awt: (for accessing java.awt), resource: (for read-only access to resource files such as images, sounds, and static texts), and import:, described next.
The import: uriGetter is similar to unsafe:, except it only imports those parts of the Java API that have been audited for capability security and found to convey no authority (see the Appendix for a definition of "authority").put in link, think of better example. Remove vector from the book Since the Vector class conveys no authority, you could also get a vector with import:
def vector4 := <unsafe:java.util.makeVector>()
As discussed later with Library Packages and Secure Mobile Code, emakers cannot use unsafe: unless the unsafe__uriGetter is explicitly handed to them. So import: is often useful in these security-aware situations. A complete list of safe versus unsafe classes, and the small percentage of Java API methods which are suppressed for security reasons, are listed in the Appendix.link
resource: mention it is safe, can be used in emakers
getting static public constants from Java: must put parens after the name as if it was a method returning a value, not a variable.
As noted earlier, E does not have an expression to directly represent public static final variables. To use such static finals from a Java class, put parentheses at the end of the variable name, making it syntactically look like a function call, prefix it with "get", uppercase the first letter, and E will get the value for you:
# E sample <unsafe:java.util.makeCalendar>.getYEAR()
Speaking to Java objects with superclass/subclass overloaded methods
Speaking to Java objects is usually as easy as shown above, where we simply sent myVector an addElement(object) message as if it were an E object. A problem arises with some Java objects if they have overloaded methods for which the only distinguishing mark is the static typing of the parameters in which one of the methods specifies a type that is a superclass of the type in the other method--a rare but not unheard-of situation. coercion causes same problemIn that case, we need to revert to a more descriptive messaging convention.
We introduced the E.call() function earlier for communicating with E objects. It can also be used to call Java objects and to specify the signature of an overloaded method with the types of the parameters. In this example, we see that the print function for the System.out object is overloaded for both String and Object, with String being a subclass of Object, so the full signature is required:
? def out := <unsafe:java.lang.makeSystem>.getOut() # value: <a PrintStream> ? out.print("abc") # example problem: <IllegalArgumentException: ...> ? E.call(out, "print(String)", ["abc"])
(Where should the following explanation go?) To use an example from awt: or swing:, we need our vat to be running with the AWT event loop. Normally this happens by running in a vat spawned to run a "*.e-awt" file. currentVat.morphInto("awt") asks the current vat to start executing instead in the awt event loop. It returns a promise which resolves to null or broken once this operation succeeds or fails. ? interp.waitAtTop(p) pauses our interpreter (E's read-eval-print loop) until p is resolved.
Now that that's done, we can proceed to the next example.
? def myLabel := E.call(<swing:makeJLabel>, "run(String)",["label text"])
If you encounter one of these special cases that requires multiple parameters, the signatures must be laid out with exact spelling and exact spacing, notably with exactly one space between the comma and the next signature:
E.call(javaObject, "method(String, int)", ["abc", 23])
Arrays and primitive types
It is possible to make Java arrays of Java primitive types, as in this example:
# E sample def makeFlexList := <elib:tables.makeFlexList> def byteArray := makeFlexList.fromType(<type:byte>, 300) byteArray.setSize(300) byteArray := 3
Here we have created a 300-element editable array of bytes. The individual elements can be accessed with square bracket notation.
XXX Now that this example has been corrected, does it still serve its purpose? Also, it's not technically correct to say this makes a Java array. It makes an E FlexList, which, on E-on-Java, currently happens to be implemented by wrapping a Java array. However, if your program depends on this fact, it is probably broken.
Java Adapters and Interfaces
As described earlier, you can use the match[verb,args] construct to aid in writing adapters and other objects that must meet a Java interface specification. E will automatically manipulate the resulting E objects and the java virtual machine so that Java understands that the E object meets the interface specification. It is not possible to make subclasses of Java classes in E. However, because the developers of the Java API have wisely moved aggressively to make sure that interfaces, rather than subclasses, are core to Java object interoperability, there is virtually no Java interfacing goal that cannot be achieved with this machinery.
The Java API versus capability security
A final note: almost all of the objects and methods in the Java API are available in E for version 1.0 through the unsafe_uriGetter; unfortunately very few have been audited sufficiently to be included with the import__uriGetter. In the future, more of the API will be accessible through the import__uriGetter; however, some parts of the Java API will be altered and/or suppressed even in unsafe__uriGetter to achieve a more secure yet easier to use computing framework. This is discussed further in the chapter on Mobile Code. You can see the list of suppressed methods and unsafe classes in the Javadoc.