FESI language extensions - Java Access
Author: Jean-MarcLugrin
Description: Describe the FESI EcmaScript interpreter extensions to create and access Java objects
Keywords: EcmaScript, JavaScript, JScript, Java, extension

| Free EcmaScript Interpreter. A JavaScript interpreter written in Java.

Language extensions - JavaAccess

The JavaAccess extension is always loaded by the interactive interpreter, and allows the user to directly access any Java class reachable via the `CLASSPATH`. It is largely compatible with the Netscape "`Packages`" capability. The example directory contains various usage of JavaAccess. The Netscape JavaScript reference is a good source for further information.

See the Java library section on how to access EcmaScript from a java program.
See the Event Handler section on how to create Java event handlers in EcmaScript.

### Objects defined by the JavaAccess extension

This extensions includes 5 new objects:

`Packages`
  A `JavaPackages` object, representing the root of all Java packages. When a property of a `Packages` object is accessed, a corresponding `JavaPackages` object is created. For example "`Packages.EDU.nowhereUni`" creates a `JavaPackages` for "`EDU.nowhereUni`". A `JavaPackages` is just a name prefix, it does not have to match a real package (the package must be a real one when a class of the package is used).
  It is therefore easy to create package abreviation like:

  `tools = Packages.EDU.puddingtonUni.tools`.

  In addition a `Packages` can be used to create a class loader, to load classes from a directory root or from a jar file. To create such a loader call `Packages` as a function, specifying the directory or jar file name. For example:

  `new Packages("java/graphics/classes").graphics.line`

  refers to a class '`graphics.line`' in a subdirectory of `java/graphics/classes`. `Packages("C:/library/tools.jar")` would similarly create a new root for classes from the specified tools jar file.
  A package cannot be created if the `Packages` object is the expression of a `with` statement - simply create the packages you need before the `with` statement!
`Beans`
  A `JavaBeans` object, representing the root of all Java beans. When a property of a `Beans` object is accessed, a corresponding `JavaBeans` object is created. For example "`Beans.java.awt.Button`" refer to an awt button used as a bean. A new Beans root can be created by calling Beans as a function, specifying jar file or a directory root, for example:

  `JugglerJar = Beans(bdkHome+"juggler.jar")`

  The bean can then be created by specifying it relatively the the bean root, as in '`new JugglerJar.sunw.demo.juggler.Juggler()`'. Even if it loads the bean from a jar file with a manifest, `Beans` does not test if the class was indeed declared as a bean, it will attempt to instantiate any specified class as a bean.
  When declared as a bean, only the properties and method described by the corresponding `BeanInfo` (see Sun documentation on beans) can be accessed. Bean properties can be accessed as EcmaScript properties (`FESI` will use the appropriate getter or setter routines, it will not directly access the fields, even if public).
`java`
  Equivallent to `Packages.java`, to make access to Java language functions easier.
`javaTypeOf`
  A function which returns the name of the class of the java object which would be created, if the value were passed to a Java method. Useful to debug access to overloaded functions. The class `JSWrapper` is used to package EcmaScript objects as a Java object if no better type can be found, and is therefore returned if this function is called for a EcmaScript built-in object. Elementary EcmaScript values are transformed in the smallest type containing them (1234 will be a `java.lang.Short`).
`loadExtension`
  A function to load an EcmaScript extension programmatically, giving the class name as a parameter, for example `loadExtension("FESI.Extensions.FileIO")`. Reloading an already loaded extension has no effect.

The command `@describe` of the interpreter is very useful to examine the characteristic of a java object. Its class, methods and fields are listed, including the properties if the object is used as a bean.

### Accessing properties or fields of a Java or Corba object

The following mechanism is used to access properties or fields of an object created by the `Packages` mechanism or received from a Java function (including CORBA objects received as a Java object from a Java function).

1. First a public Java field with the same name si looked up. If it is found, then it is directly accessed (any setter or getter function is ignored).
2. Fields with a name starting with "on" are handled specially: if they do not exist in an object, they are interpreted as a request to setup an event handler (see the event handling page for details).
3. If the field is not found or not public, then bean introspection is used to find the property. If is is found by introspection then the getter or setter routines is used.
4. As a last ressort a routine with the name of the property is looked up as a setter (void with 1 argument of the same type) or getter (no argument, returning a value). This last method is compatible with CORBA objects accessed from Java.

The properties of objects declared as Bean (using the Beans creation mechanism) are only looked up using bean introspection.

It is naturally always possible to call a setter or getter routine directly.

### Creating Java objects

Once the JavaAccess package is loaded, it is possible to create new Java objects, for example:

`cal = new java.util.GregorianCalendar();`

The Java objects can be called almost as native EcmaScript objects. Strings, dates and numeric values are converted automatically between EcmaScript and Java. Non convertible objects are wrapped, that is a Java object (as a Calendar) is represented by a wrapper object in EcmaScript. This wrapper objects takes care of calling the native functions or accessing the properties. If the wrapper is given back to a Java routine, then the wrapped (Java native) object is used as its value. In case of overloaded functions, the wrapper will attempt to find a suitable instance, possibly widening numbers or converting single character Strings to a Character if needed.

Array returned from a java routine as wrapped as an array and can be manipulated as an array. If the wrapped array is passed back to a Java routine, the array will be unwrapped. An EcmaScript `Array` can be used where a java `array` is required, if all elements of the array can be converted to the target array component type. In that case a copy of the array is used as a parameter. This may be time consuming for very large array. If an array must be shared between Java and EcmaScript, it must be created in Java.

If a java class or object name conflicts with an EcmaScript keyword, you must use the dynamic indexing notation, as for example in:

`java.lang.System["in"]`

Because the notation '`java.lang.System.in`' would create a syntax error, '`in`' being a keyword in EcmaScript.

### Using enumerators

It is possible to directly use Java enumerators in a "for in" construction. For example:

`// Get the properties`
`properties = java.lang.System.getProperties();`

`// List them, using a java enumerators`
`for (key in properties.keys()) {`
`value = properties.get(key);`
`writeln ("Property '" , key, " = '", value, "'");`
`}`

### Constructors used as a function

If a Java class name is used as a function, the corresponding constructor is called if it exists - for example:

`cal=java.util.GregorianCalendar()`

There is one difference for elementary values. In principle values which can be converted to an EcmaScript type are automatically converted. For example `str=java.lang.String("Hello")` will create an EcmaScript string, not a wrapped Java `String`. However if `new` is used with these basic types, a wrapper to a Java `String` will be returned instead. That wrapper is likely to be converted to an EcmaScript string at the first usage, but this may be convenient to force the type of a variable to solve a delicate overloading conflicts. For example: `javaObj.append(new java.lang.Long(23))` will direct EcmaScript to look at a variant of the `append` functionwith a `Long` parameter (rather than say a `Double`).

It is possible to define event processing routines with `FESI`, see the FESI event handling page for details.

### Limitations

Indexed beans properties are not currently supported, unless the full array can be accessed and set at once.

Information on beans and event handling is kept with the wrapper of the object. If a bean or a java object is created or received by FESI, passed to a Java routine from `FESI` and, then returned to `FESI` (for example as the return value), it will receive a new wrapper. This may create some confusion, especially regarding the equality of such objects. The recommendation is to always use the original reference of a bean or Java object in `FESI`.

The selection of the routine is based on some heuristic to solve overloading. You may have to use `@debugJavaAccess` in the interpreter if the routine called is not the expected one. Because of the difference in model between the Java and EcmaScript typing, it is not always possible to make a unique conversion. In pratice these case are rare and if needed a wrapper routine or an extension may be created.

The following limitation is non obvious (see bug (4090460) in Sun Java implementation): Invoking a public method on a java object that is inherited from a non-public class is callable directly but not via reflection (and therefore not from FESI) when the caller is from a different package. That problem persists under JDKs 1.1.7B through 1.3beta on Win98, NT4.0, and SunOS 5.5.1. As a workaround you can make the super class public or write a wrapper object.

Return to the main page

Last update: 21 October 1999