| |||||||||
Book: The Judo Language 0.9 |
|
When calling Java methods and constructors, generally just pass Judo variables as parameters, Judo tries to pick the right method. This should work most of the time, but is not always possible when there are overloaded methods with different numbers of parameters. (Overloaded methods are those in a same class with the same name but different parameters.) Casting values and instanceof test
The following Judo program conducts three sets of tests: calling
Look closely at the output of all test cases and refer to each Java method invoked. As you see, Judo guesses reasonably well even in confusing situations. By casting Judo primitive values to specific Java types, you can invoke a particular method. The casting operators for Java primitive types look like functions, such as All Java objects in Judo have two built-in methods: The
Fully qualified Java class names include a number of package names and the class name itself, separated by dots; they are usually quite long. Judo uses the same Java Pre-imported standard Java packages
In the above example, the first Inner class names
In Java, using inner classes is more of a style than necessity. Only Pass Judo Values To Java MethodsJudo primitive values can be passed directly into Java methods like we have seen earlier. This includes integers, floats, strings and Array.toBooleanArray() // boolean[] Array.toBooleanObjectArray() // Boolean[] Array.toByteArray() // byte[] Array.toByteObjectArray() // Byte[] Array.toCharArray() // char[] Array.toCharObjectArray() // Character[] Array.toShortArray() // short[] Array.toShortObjectArray() // Short[] Array.toIntArray() // int[] Array.toIntObjectArray() // Integer[] Array.toLongArray() // long[] Array.toLongObjectArray() // Long[] Array.toFloatArray() // float[] Array.toFloatObjectArray() // Float[] Array.toDoubleArray() // double[] Array.toDoubleObjectArray() // Double[] Array.toObjectArray() // Object[] Array.toStringArray() // String[] Otherwise, you need to explicitly convert the Judo data structure into a particular Java class instance. Use Java Classes and Class Static MembersJava classes are special objects within JVMs. In Judo, the
Once the class object is in a constant or variable, you can use the One of the main reasons to use Java class objects is to use Java class static members. Java classes' static methods and fields are class-wide members and can be accessed without creating individual instances. In Judo, you need to use the Java class objects to use their static members: println (java::System).currentTimeMillis(); This works, but the syntax is a little cumbersome. In fact, Judo treats Java class names as namespaces, so that Java class static members can be accessed directly like this:
The following example prints out the values of
In the loop, we used the You can create function aliases for static Java methods; these function aliases behave like regular Judo functions. This is a great way to build Judo/Java libraries: you can choose to implement a function as a Java static method and alias it. In fact, many of Judo's own system functions are implemented this way. The syntax is:
Note that function aliases don't care about the parameters of the Java static method. If a function alias is to take variable number of parameters, the Java class must have the name-sake static methods with parameters of all permutations. For instance, the Judo system function function initialContext for java::com.judoscript.bio.SysFunLib.initCtxt; That function may take no parameters, or a factory name and optionally url, user, password and auth as parameters. Hence, the class public class SysFunLib { static InitialContext initCtxt(); static InitialContext initCtxt(String factory); static InitialContext initCtxt(String factory, String url); static InitialContext initCtxt(String factory, String url, String user); static InitialContext initCtxt(String factory, String url, String user, String pwd); static InitialContext initCtxt(String factory, String url, String user, String pwd, String auth); } Another system function,
|
Listing 11.12 java_array.judo |
---|
ia = new java::int[][][] { { { 1, 2, 3 }, { 4, 5, 6 } }, { { 7, 8, 9 }, { 10 } } }; Fa = new java::Float[][][] { { { 1.5, 2.5, 3.5 }, { 4.5, 5.5, 6.5 } }, { { 7.5, 8.5, 9.5 }, { 10.5 } } }; ba = new java::boolean[][][] { { { true, false, true }, { false, true, true } }, { { true, true, true }, { true, true } } }; Ba = new java::Boolean[][][] { { { true, false, true }, { false, true, true } }, { { true, true, true }, { true, true } } }; ca = new java::char[][][] { { { 'A', 'B', 'C' }, { 'D', 'E', 'F' } }, { { 'G', 'H', 'I' }, { 'J', 'K' } } }; Oa = new java::Object[][][] { { { 'a', 'b', 'c' }, { 'd', 'e', 'f' } }, { { 'g', 'h', 'i' }, { 'j', 'k' } } }; print3d ia; print3d Fa; print3d ba; print3d Ba; print3d ca; print3d Oa; function print3d a { println '----- print 3D: ', a; for i from 0 to a.length-1 { for j from 0 to a[i].length-1 { for k from 0 to a[i][j].length-1 { println i, ' ', j, ' ', k, ' => ', a[i][j][k]; } } } } |
When a value is assigned to an array element, Judo tries to convert it to the array element type.
Judo has special treatment of common Java data structures including arrays, some of which we have already seen. This is the topic of the next section.
Java data structures are treated almost identical to their Judo counterparts.
The java.util.Map
interface is treated almost the same as Judo's own Object
. That is, java.util.Map
instance can be initialized with name-value pairs, and the member-access operator, .()
can be used to get and set values instead of Map
's get()
and put()
methods. In addition, if the key value is a string, you can access its value by directly using that string as an "attribute" name, seen in the following example.
ht = new java::Hashtable; // is a Map. ht.Hello = 'Hello, World!'; ht.'Hi, World' = 'Hello, World!'; println ht.Hello; // prints: Hello, World! println ht.'Hi, World'; // prints: Hello, World! println ht.DontExist; // prints nothing.
The most commonly used classes that implement the Map
interfaces are HashMap
, Hashtable
and Properties
. The following example creates a Properties
instance with initial values:
Listing 11.13 props.judo |
---|
props = new java::Properties( a.b.c.d.e.f.g = 'a thru g', h.i.j.k.l.m.n = 'h thru n' ); println props; |
Iterate Java Data Structures and Objects
Earlier, we have seen that the for in
statement can be used to iterate through Java arrays. In fact, for in
can be used to iterate these Java data structures:
java.util.Iterator
instancesjava.util.Enumeration
instancesjava.util.List
instancesjava.util.Collection
instancesjava.util.Map
instances (through their keys)iterator()
method that returns a java.util.Iterator
java.util.Iterator
or java.util.Enumeration
The rules should be obvious, except perhaps the last two. The following Java source file contains three classes; they are all ordinary classes but have those "signature" methods.
Listing 11.14 IterationDemo.java |
---|
import java.util.*; // A class with one iterator() method public class IterationDemo { int i = 0; public Iterator iterator() { i = 0; return new Iterator() { public boolean hasNext() { return i++<3; } public Object next() { return "iterator()-" + i; } public void remove() {} }; } // A class with one method that returns // an Iterator and takes no parameters public static class WithOneIterator { int i = 0; public Iterator foo() { i = 0; return new Iterator() { public boolean hasNext() { return i++<3; } public Object next() { return "foo()-" + i; } public void remove() {} }; } } // A class with one method that returns // an Enumeration and takes no parameters public static class WithOneEnumeration { int i = 0; public Enumeration bar() { i = 0; return new Enumeration() { public boolean hasMoreElements() { return i++<3; } public Object nextElement() { return "bar()-" + i; } }; } } } |
The following Judo program uses the for in
statement to iterate through each of them.
Listing 11.15 for_in_iter.judo |
---|
o = new java::IterationDemo; for x in o { println x; } println; o = new java::IterationDemo$WithOneIterator; for x in o { println x; } println; o = new java::IterationDemo$WithOneEnumeration; for x in o { println x; } |
Access elements in java.util.List
Objects of java.util.List
are treated very much like Judo arrays. For instance, they can be iterated forward and backward, and elements can be accessed via the array element access operator []
, as shown the following example.
Listing 11.16 javalists.judo |
---|
testList new java::java.util.Vector(); testList new java::java.util.ArrayList(); testList new java::java.util.LinkedList(); function testList lst { println nl, '=== ', lst.getClass().getName(), ' ==='; lst.add( Date(2001,1,1) ); lst.add( 1 ); lst.add( 10.01 ); lst.add( 'Hello, World!' ); println 'lst[0] = ', lst[0]; println 'lst[1] = ', lst[1]; println 'lst[2] = ', lst[2]; println 'lst[3] = ', lst[3]; println 'lst[4] = ', lst[4]; lst[9] = 'XYZ'; println 'lst[9] = ', lst[9]; } |
For the first testList()
call, for instance, the output is:
=== java.util.Vector ===
--- size: 4 ---
lst[0] = 1/1/01 12:00 AM
lst[1] = 1
lst[2] = 10.01
lst[3] = Hello, World!
lst[4] =
lst[9] = XYZ
So far we have covered all the basic Java scripting topics in Judo. Other than the special "java" namespace prefix, the operations are natural to both Judo and Java. Next, we are going to look at extending Java classes, including implementing Java interfaces.
The capability for a Java scripting language to extend Java classes and implement Java interfaces is important, because sometimes Java methods expect parameters of interfaces and require the client program to provide implementation classes. A classical use case is event handling. For instance, in a GUI program, you construct the GUI by assembling various components; based on user interaction, GUI components fire events by calling the controller object. This requires that the controller class implement certain interfaces, so the components "know" how to communicate with it. Such a call-back mechanism is not unique to GUI programs. A Java scripting language incapable of extending Java classes and implementing interfaces has serious limitations in terms of full-scale Java scripting.
Judo itself is an object-oriented language, and can extend/implement Java classes and interfaces; such classes are called Java extension classes in Judo. They are defined with the presence of the extends java::
clause. These are the rules governing Java extension classes:
extends
zero or one Java classes and zero or more interfaces, separated by comma. The resultant class is a Java class with that class name without any package names. This user-defined class are created like a normal Judo class via the new
operator without "java" namespace prefix.
super
decorator. You can also invoke own methods, and access this and parent's data fields, public or protected.
super()
, which is one of the parent class's constructors. This call must precede data member initializations and invocations of any other methods.
The most important things to remember are, the class itself is defined very much like a Java class, except the method bodies are written in Judo; everything is public; and constructor is a special issue. Let's look at examples now.
Listing 11.17 extend_class.judo |
---|
class MyHashtable extends java::Hashtable { // Test overriding an existing method int hashCode() { return super.hashCode() ^ 1; } // A new method. String[] getKeys() { arr = []; for x in this { arr.add(x); } return arr.toStringArray(); } // A new method. Object[] getValues() { arr = []; for x in values() { arr.add(x); } return arr.toObjectArray(); } } mht = new MyHashtable; mht.put('adate', Date(2004, 6, 6)); mht.put('anumber', 2); mht.put('astring', 'string'); println ' keys: ', mht.getKeys(); println ' values: ', mht.getValues(); println 'hashCode: ', mht.hashCode(); |
The hashCode()
method overrides the existing method in the parent class, and it invokes the parent's name-sake method. The two new methods, getKeys()
and getValues()
, use Judo arrays to collect keys and values, and eventually return them as Object[]
's.
Java interfaces can be extended (implemented) exactly the same way. The following example defines a Java extension class that implements java.util.Iterator
without implementing any of the methods, because any unimplemented abstract methods in a Java extension class are given empty bodies, so the new class we define is still a concrete (Java) class.
Listing 11.18 extend_itf.judo |
---|
class MyIterator extends java::Iterator { } println o = new MyIterator; for x in o { println x; } |
The following program extends a Java class and a Java interface. You can implement any number of Java interfaces, separated by comma(s); but you can extend no more than one Java class as you would expect.
Listing 11.19 extend_class_itf.judo |
---|
class MySetIterator extends java::HashSet, Iterator { Iterator iter; constructor a, b, c { super(); iter = null; if c != null { add(c); } if b != null { add(b); } if a != null { add(a); } } // Iterator methods boolean hasNext() { if iter == null { iter = iterator(); // of HashSet. } return iter.hasNext(); } Object next() { return (iter==null) ? null : iter.next(); } } o = new MySetIterator('Hi!', 9); o.add('abc'); o.add(Date(2003,7,4)); for x in o { println x; } |
All these examples are to demonstrate Judo's Java extension classes; they may not make much practical sense. This time, we declared a data member, iter
. They can only be initialized in the constructor. The constructor takes up to three parameters; in the testing, we passed two parameters. The program's output is:
Hi! 9 abc 7/4/03 12:00 AM
So, we have covered all the topics of Java scripting in Judo, from the very basics to advanced topics and everything in between. Java scripting is used extensively in building Java GUIs of AWT or Swing, as you will find out a lot in chapter 19. Java GUI Scripting. Next, we present some practical J2EE topics as further examples of Java scripting applications.
Java interface adapters are nothing but anonymous Java objects that implement some Java interfaces. Java interface adapters happen most frequently in event handling, notably in Java GUI programs:
import java.awt.Frame; import java.awt.event.*; Frame f = new Frame(); f.addWindowListener( new WindowListener() { public void windowClosing(WindowEvent e) { System.exit(0); } public void windowClosed(WindowEvent e) {} public void windowOpened(WindowEvent e) {} public void windowIconified(WindowEvent e) {} public void windowDeiconified(WindowEvent e) {} public void windowActivated(WindowEvent e) {} public void windowDeactivated(WindowEvent e) {} } ); f.setVisible(true);
In Judo, this is done via the Java extension class mechanism like this:
Listing 11.20 adapter.judo |
---|
import java.awt.Frame; import java.awt.event.*; f = new java::Frame; f.addWindowListener( new java::WindowListener { void windowClosing(WindowEvent e) { exit 0; } } ); f.setVisible(true); |
As discussed earlier, the unimplemented methods in the interface are given default (empty) implementations.
In Java, an interface adapter can implement just one interface; in Judo, you can implement as many interfaces as you want. In fact, you can even extend a class that has a default constructor. The following example demonstrates:
Listing 11.21 fromPaMa.judo |
---|
a = new java::Papa, Mama, Foo { void playBall() { println 'Make a few dents!'; } void singSong() { println 'Utter some sound.'; } }; a.playBall(); a.singSong(); println "Height: " + a.height(); |
In this example, Papa
and Mama
are two interfaces, and Foo
is a class with a default constructor:
public interface Papa { void playBall(); int height(); } public interface Mama { void singSong(); int height(); } public class Foo { }
Both Papa
and Mama
have a height()
method. What if they have same parameter types but different return types? The result may be unpredictable; it's the user's responsibility to prevent this from happening. The output of the example is:
Make a few dents! Utter some sound. Height: 0
Creating EJB clients in Judo is natural. It is easier to write than in Java because the ubiquitous casting is not needed at all. Coupled with Judo's JDBC capabilities, this constitutes a perfect testing platform for EJBs. With the built-in scheduling support, practical uses of EJBs are just as easy.
Listing 11.22 ejb_client |
---|
1: //ctx = getInitialContext('weblogic.jndi.WLInitialContextFactory', 't3://server'); 2: ctx = getWeblogicContext('t3://server'); // shortcut for Weblogic. 3: home = ctx.lookup(OrderHome); 4: key = new java::OrderPK('00234'); 5: order = home.findByPrimaryKey(key); 6: // do something with order. |
This is a hypothetical case where an order entity bean is retrieved from the server for some operations. Line 1, which is commented out, is the system function getInitialContext()
. Judo has a number of convenience functions to get initial contexts for popular J2EE application servers, including WebLogic, WebSphere, JBoss, Oracle 9iAS and IONA; see line 2. On line 3, OrderHome holds the unique registered home interface name, which is typically the same as its class name. The rest is just using Java classes.
Judo internal classes, i.e., classes in packages com.judoscript.*
, etc., are prohibited from being used. Classes in com.judoscript.util.*
, however, are allowed, because these classes have nothing to do with the Judo language engine.
|