JavaFX Script, as you may know already, is a declarative and statically typed scripting language. It has first-class functions, declarative syntax, list-comprehensions, and incremental dependency-based evaluation.
JavaFX Script syntax includes object literals - a declarative syntax to construct objects. If you know JavaScript, you may know about JavaScript Object Literals and it's subset called JSON - which is a lightweight data-interchange format (considered to be an alternative for XML in certain use-cases). There are some parallels between JavaScript object literal syntax and that of the JavaFX Script. Of course there are differences. The following is an attempt to summarize the differences.
JavaFX Script is statically typed. But, user may omit types in many places. JavaFX can infer types from the context. While defining object literals, the type of the object is specified. For example:
class Person {
attribute name: String;
attribute children: Person*;
}
var chris = Person {
name: "Chris"
children:
[Person {
name: "Dee"
},
Person {
name: "Candice"
}]
};
But except for the "top most" object, we can omit types elsewhere and JavaFX will infer types. For example, the above may also be written as shown below:
class Person {
attribute name: String;
attribute children: Person*;
}
var chris = Person {
name: "Chris"
children:
[ Person {
name: "Dee"
},
Person {
name: "Candice"
}]
};
JavaScript is dynamically typed. So, we don't and can't specify the type of the object. [And yes, I do know about JavaScript 2.0 - which is optionally typed. But, I am talking about the current implementations]. We write the above object in JavaScript as
var chris = {
name: "Chris",
children:
[ {
name: "Dee"
},
{
name: "Candice"
}]
};
JavaFX object literal examples do not include comma between property specifications. For example,
class Person {
attribute name: String;
attribute children: Person*;
}
var chris = Person {
name: "Chris"
children:
[Person {
name: "Dee"
},
Person {
name: "Candice"
}]
};
Please note that there is comma between elements of the array but
there is no comma between properties (between name and
children in above). But, JavaScript object literals
(and JSON) have comma between properties as well. But,
JavaFX implementation seems to accept comma. So, the following
var chris = Person {
name: "Chris", // <-- comma here is fine!
children:
[Person {
name: "Dee"
},
Person {
name: "Candice"
}]
};
JavaFX allows local variables in object literal. We can write something like:
class Person {
attribute name: String;
attribute likes: String;
}
var v = Person {
// n is local to this literal
var n = "sundar"
name: n,
likes: "Java"
};
In JavaScript, we can not use local variables within literal definition. If we want such variables, we may do something like this:
var obj = (function() {
// n is local in function
var n = "sundar";
return {
name: n,
likes: "Java"
}
})();
i.e., we define an anonymous function surrounding the object literal and call it to get the object.
In JavaFX, arrays are flat.
var v = ["Jan", ["Feb", "Mar"]];
// the above is same as ..
// var v = ["Jan", "Feb", "Mar"];
In JavaScript (and in JSON), arrays can be nested.
JavaFX allows Java objects to be created with object literal syntax. For example:
import javax.swing.JFrame;
import javax.swing.JButton;
var f = new JFrame { title: "hello world" };
var b = new JButton { label: "ok" };
f.add(b, "Center");
f.pack();
f.setVisible(true);
Mozilla Rhino implementation of JavaScript (which is included in Sun's JDK 6) allows accesing Java classes. But, JSON-like initialization is not supported for Java objects. Java bean conventions are supported. So, it is possible to use field access syntax for getXXX()/setXXX() method calls. We may write the above as
importClass(javax.swing.JFrame);
importClass(javax.swing.JButton);
var f = new JFrame();
// Java bean convention
f.title = "hello world";
var b = new JButton();
b.label = "ok" ;
f.add(b, "Center");
f.pack();
// bean convention again
f.visible = true;
Is it possible at all to have JSON-like syntax to create Java objects? Yes, it is! We can use JSAdapter. We can define the following two JavaScript functions using JSAdapter.
function junwrap(o) {
var origObj = "__wrapped__";
if (o instanceof Array) {
var res = new Array(o.length);
for (var e in o) {
res[e] = junwrap(o[e]);
}
return res;
}
if ((typeof(o) == 'function' ||
typeof(o) == 'object') &&
origObj in o) {
return o[origObj];
} else {
return o;
}
}
function jimport(ctr, name) {
var origObj = "__wrapped__";
var obj = new ctr();
this[name] = function(initObj) {
var res = new JSAdapter() {
__has__ : function(name) {
return (name in obj) || (name == origObj);
},
__get__ : function(name) {
if (name == origObj) {
return obj;
} else {
var v = obj[name];
if (typeof(v) == 'function') {
return function() {
var args = new Array(arguments.length);
for (var i = 0; i < arguments.length; i++) {
args[i] = junwrap(arguments[i]);
}
return v.apply(obj, args);
}
} else {
return v;
}
}
},
__put__: function (name, value) {
if (name != 'origObj') {
value = junwrap(value);
obj[name] = value;
}
}
}
for (var f in initObj) {
res[f] = initObj[f];
}
return res;
}
}
With the above functions, we can write
jimport(javax.swing.JFrame, "Frame");
jimport(javax.swing.JButton, "Button");
var f = new Frame() { title: "hello world"; };
var b = new Button() { label: "ok" };
f.add(b, "Center");
f.pack();
f.visible = true;
Note that this JSON-like Java object initialization may be used in the server side JavaScript as well. For example, we may create a java.util.Date object as
jimport(java.util.Date, "JDate");
var d = new JDate() {
date : 1,
month: 0, // 0 is January!
year : 17 // offset from year 1900
};
Two server side use-cases with the Phobos framework include:
Typically, we may create these POJO class instances and persist/marshall for subsequent use. These POJO classes follow Java bean conventions. So, it is easy to use JSON-like object creation with these classes.
There are many
Software Configuration Management (SCM) systems also called Revision Control Systems and trillion other names
....
Being a Sun employee, I've been using Teamware ever since I joined Sun. During the development of JDK 6, I became involved in integrating JSR-223 reference implementation (RI) code into JDK 6 (javax.script package and Rhino based JavaScript engine). During this effort, I had to learn CVS - because the RI code was kept in CVS repository.
In a recently started project, we have started using Subversion. I read The Subversion book. When I say I "read", I mean I read it just enough for working with a repository. I don't attempt to read to become an expert - I've not done that with Teamware either!
But, OpenSolaris uses Mercurial. Also, OpenJDK will use Mercurial. So, I woke up finally and started learning Mercurial
I found the following resources very useful:
I hope I won't have to learn yet another SCM before 2015
JRuby 1.0 has been released. The jsr-223 script engine for JRuby had an issue because of a recent change in JRuby parse API during 1.0.0RC3. Thanks to the java.net user "bongobongo" for reporting this issue along with the patch. I've included this fix and regenerated binaries and changed the engine to use JRuby 1.0 version -- as usual, you can find the sources and binaries at @ scripting.dev.java.net
It has been a while. I've not updated on scripting.dev.java.net project and related activities. Here it is ...
You probably know this already, but just in case you missed: JavaFX Script has jsr-223 script engine for it (included in javafxrt.jar). See also: