Showing posts with label json. Show all posts
Showing posts with label json. Show all posts

Monday, May 11, 2009

Passing parameters between browser windows

Imagine having two browser windows - "parent" and "child", "child" being opened from the "parent" using window.open function. At some point you want to pass some parameters to the parent, and then close the child window. Easy:



var myData = null;

var returnValue = function(data) {
myData = data;
}


in parent, and


window.opener.returnValue("Hello, play with me dad");


in the child window. The returned value is assigned to the myData variable and can be used after the window is closed. This simple schema gets a bit complicated when we deal with object variables:


window.opener.returnValue({ name: "Jerry", surname: "Blueberry"});


Now, after the child window is closed, the interpreter behavior depends on the browser used. In Firefox (and probably any other "modern" browser) everything works smoothly. However, in IE 6.0 (not tested in other versions) the object reference is assigned to the myData variable, but the object itself is destroyed. This causes a runtime error with a message "the object invoked has disconnected from its clients" - the returned data has been lost.

The simplest way to deal with this issue is to use some form of serialization of the returned data, and the simplest way to serialize data is to use JSON representation. For example, using the Prototype library:



var myData = null;

var returnValue = function(data) {
myData = data.toJSON().evalJSON();
}


This is the simplest (even if not the fastest) way to make a deep clone of an object. By creating a deep copy of the returned object, we effectively disconnect the object from the originating window. Problem solved.

Monday, April 20, 2009

Introspection, the hard way

My current project is an Ext application with a database backend. The communication between the two is carried out by a rather thin JEE middleware, which serves JSON data to the client. The Java-to-JSON mapping is done by the JsonTools library, which makes this mapping a breeze:


String str = JSONMapper.toJSON(bean).render(true);


Really simple and effective. The library gets the bean properties by introspection, and converts them to their respective JSON representations, so there is no need to write any mapping XMLs or anything- just as you were writing in Ruby :)

However, today I stumbled on a nasty surprise. I created a new class hierarchy, with an abstract class on the top, with non-public concrete classes. The concrete classes are constructed using a Factory pattern, like in the example below:


public abstract class Animal {
public static Animal createAnimal() {
return new Elephant();
}
}

class Elephant extends Animal {
private String weight;
public String getWeight() {...}
public void setWeight(String weight) {...}
}


Everything nice and clean, however:


Animal dumbo = Animal.createAnimal();
System.out.println(JSONMapper.toJSON(dumbo).render(true));
//...


And KA-POW, an IllegalAccessException. What the?

The problematic snippet of code looks something like this:


Class dumboClass = dumbo.getClass();

System.out.println("dumbo is a "+dumboClass.getName()); //Elephant

PropertyDescriptor[] propDscs =
Introspector.getBeanInfo(dumboClass, Introspector.USE_ALL_BEANINFO).
getPropertyDescriptors();

for(PropertyDescriptor pd: propDscs) {
if(pd.getName().equals("class")) continue;

Method preader = pd.getReadMethod();
System.out.println("dumbo."+pd.getDisplayName()+" has a reader "+preader.getName());
//--> dumbo.weight has a reader getWeight -- ok
System.out.println("dumbo."+pd.getName() +"() = "+preader.invoke(dumbo));
// IllegalAccessException
}


If you think a bit about this, it makes perfect sense. Because the dumbo variable is declared as Animal instance, the class using it has no way to know about any of its methods other than the ones defined in the Animal class. Moreover, because the Elephant class is not public, it is not visible outside its package at all, as well as any of its methods.

However, what is surprising is that the Introspector somehow knows about both the Elephant class and its getWeight methods. What is even more surprising, is that you can write:


preader.setAccessible(true);


which makes the code work without any exceptions. The setAccessible method effectively nullifies any access restrictions- which is a mixed blessing, I imagine.