As of version 1.1 FScript has the ability to access Java objects. This is done by registering an instance of the FSReflectionExtension class. An example of this is in the examples/objects/Objects.java file:
FSReflectionExtension fe=new FSReflectionExtension(); BasicIO fs=new BasicIO(); fs.registerExtension(fe); fs.load(new FileReader("objects.script")); fs.run();
By registering a FSReflectionExtension the following functions become available within FScript:
object system,map system=getClass("java.lang.System") map=create("java.util.HashMap")
The object type is a special type used in FScript to contain objects. There are a few rules governing it's use.
object obj1,obj2 obj1=create("java.util.ArrayList") obj2="This is a string"
obj2="This is another string"Would be valid, but:
obj2=obj1would not.
obj2=null obj2=obj1
The object type can be used outside of the context of FSReflectionExtension . The object type is implemented using the FSObject wrapper class, so any extension/subclass is free to return a FSObject and have it handled internally within FScript as a object in much the same way as Integer,Double and String currently work.
Once an object has been created it can be accessed from FScript in a similar manner to which it can be accessed in Java. Methods can be called, and fields read and set. For example (taken from objects.script in the examples directory):
object map,obj map=create("java.util.HashMap") map.put("a","Apple") map.put("b","Bear") map.put("c","Car") map.put("d","Demolition") #Create out test object obj=create("TestObject") obj.testMethod() out.println(obj.stringField) out.println(obj.intField) out.println(obj.intMethod("5551212")) #Set a field using explicit call obj.setValue("Test value for object") #But we could do this which is equiv to the setValue call #obj.Value="Test value for object" #get value using the implicit getter out.println(obj.Value) #however we could have done this #out.println(obj.getValue())
As can be seen from the above code the FSReflectionExtension class also provides some support for Bean like getters and setters - i.e a line of the type:
myObj.Amount=12If no amount field exists, this call is converted internally to:
myObj.setAmount(12)A similar process takes place with assignment, with:
intValue=myObj.Amountpotentially becoming:
intValue=myObj.getAmount()
It is possible to use a custom exception handler for calls to methods of objects created by the FSReflectionExtension . This exception handler will only be called for exceptions thrown from within the method called, not for exceptions caused by problems with parameters or method names. This can be done using the setExceptionHandler method of FSReflectionExtension .
There are some limitations of FSReflectionExtension however. It is only simple to work with for parameter types etc. that are supported by FScript (Integer, Double and String), although this limitation can be worked around a little by using the object type in FScript for parameters too.
Only one level of indirection (dots) are allowed e.g.
object sys sys=getClass("java.lang.System") sys.out.println("Hello")Will fail at sys.out.println("Hello") . The solution to this is to recode like:
object sys,out sys=getClass("java.lang.System") out=sys.out out.println("Hello")Which is a little cumbersome, but works.
As FSReflectionExtension is an extension, rather than being directly built into FScript it would be possible to write a replacement or enhancement for the extension. FSReflectionExtension makes use of the FSParserExtension interface. This interface is simply an extension of the FSExtension interface which ensures that implementers are passed a reference to the current Parser class. It would be wise to study the source for the FSReflectionExtension before attempting to code an extension/replacement.
Also note that the FSReflection extension makes use of code from the Apache Velocity project, which is under the Apache license. This is stated in the relevant files (murlen.util.fscript.introspection.*).