JavaScript, JSON and JavaFX Script

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.


Types

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"
             }]
       };


No comma between property values

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"
             }]
       };


Local variables within literal

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.


Arrays are flat

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.


Object literals for Java objects

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.

Comments:

Post a Comment:
Comments are closed for this entry.
About

sundararajan

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today
Bookmarks
Links

No bookmarks in folder

Blogroll

No bookmarks in folder

News

No bookmarks in folder