wiki:WikiStart

XerialJ BeanUtil

BeanUtil (org.xerial.util.bean.BeanUtil) provides a simple data binding method between JSON or XML data and Java classes.

A bean class must have the followings:

  • A public default constructor, i.e, a public constructor without any argument.
  • To bind JSON (XML) data to a bean class, there must be public getter/adder/seter/putter methods in the bean class, prefixd with get, add, set or put
    • e.g., getId(), setName(String name), addPerson(Person person), putProperty(String key, String value), etc.
    • BeanUtil supports binding of the follwing data types:
      • primitive types: int/Integer, double/Double, float/Float, boolean/Boolean, String
      • Bean classes
      • Collection of data classes listed here. e.g. List<Integer>, Set<String>, etc.
      • Map types with key and value classes. key and value also must have the data types listed here, e.g., HashMap?<String, Integer>, etc.
  • A setter is used to bind a single data
  • An adder is used to append a data to a collection (ArrayList?, LinkedList?, HashSet?, etc.)
  • A putter is used to append a (key, value) pair to a map type object.

Suffixes of getter/setter/adder/putter must match to the corresponding JSON/XML data names. For example, to correctly load a JSON data,

  { "id":1, "name":"leo" } 

you must prepare the following setters:

  public void setId(int id) { this.id = id; }
  public void setName(String name) { this.name = name; }

The first letter of each setter's suffix is converted to a lower-case letter, e.g. setName -> name, setWikiName -> wikiName, etc.

An example of a Bean class:

class Person 
{ 
  private int id; 
  private String name; 

  // default constructor is requried for any Bean class
  public Person(); 
  public Person(int id, String name) { this.id = id; this.name = name; } 

  // getter & setters
  public int getId() { return id; } 
  public String getName() { return name; } 
  public void setId(int id) { this.id = id; } 
  public void setName(String name) { this.name = name; } 
}

Binding Example:

  Person p1 = new Person(1, "leo"); 
  // BeanUtil.toJSON() will give a json string { "id" : 1, "name" : "leo"} 
  // p1.getId() and p1.getName() are used to retrieve data from p1.
  String json = BeanUtil.toJSON(p1); 
  
  Person p2 = new Person() // empty data 
  // Fills p2 with a given json data 
  // Behind the scenes, p2.setId(1) and p2.setName("leo") are invoked 
  BeanUtil.populate(p2, json);   // p2.id = 1, p2.name = "leo"

Managing collection data

Use addSomething() method, to add collection data.

public class PersonList 
{ 
   ArrayList personList = new ArrayList(); // it must be initialized. 
   public PersonList() {} 
   
   void addPerson(Person p) 
   { personList.add(p); } 

   // this getter is necessary to output JSON data, {"person":{"-c":[{"id":1, "name":"leo"}, {"id":2, "name":"yui"}]}}
   public ArrayList getPerson() { return personList; } 
}

Use putter to add data to Map classes:

public class PersonTable
{
   private TreeMap<Integer, Person> table = new TreeMap<Integer, Person>();

   public TreeMap() {}

   public void putPerson(int id, Person person) { table.put(id, person); }

   public Map getPerson() { return table; }

}

Binding XML Data

BeanUtil can be used to bind XML data to Java classes. Given the following XML data,

<person id="1">
  <name>leo</name>
</person>
   Person p = new Person();
   BeanUtil.populateBeanWithXML(p, xmlData);
   // p.id = 1 and p.name = "leo"

where xmlData is a String of the above XML data.

Generating XML data from a bean class:

   String xml = BeanUtil.toXML("person", new Person(1, "leo"))
   // this yields <person><id>1</id><name>leo</name></person>

Top element tag of the generated XML can be changed as you like:

   String xml = BeanUtil.toXML("member", new Person(1, "leo"))
   /* 
     <member> <id>1</id> <name>leo</name> </menber>
    */

BeanUtil can be used to generate XML data:

   PersonList l = new PersonList();
   l.addPerson(new Person(1, "leo"));
   l.addPerson(new Person(2, "yui"));
   
   System.our.println(BeanUtil.toXML("personList", l));

The output of this code:

<personList>
 <person>
  <id>1</id>
  <name>leo</name>
 </person>
 <person>
  <id>2</id>
  <name>yui</name>
 </person>
</personList>

Loading the above XML data:

  PersonList l2 = new PersonList();
  BeanUtil.populateBeanWithXML(l2, xmlData);

Tips for GWT user

(Writing of the following content is not finished yet, so skip this section)

In the GWT (Google Web Toolkit) of the current version (1.3.3, Mar 2007), the generics feature of Jave (since JDK1.5) cannot be used within the client Java codes. For example, GWT cannot compile the following method:

   void setPersonList(List<Person> personList) 
   { this.personList = personList; }  

So, in GWT, you have to change the argument of the above method as follows:

   void setPersonList(List personList) { ... }  

But, with this setter method, we have no information about the element type contained in the List class. So given a JSON data, e.g.,{ "personList" : [ {"id":1, "name":"leo"}, {"id":2, "name":"taro"}] }, BeanUtil class cannot instantiate Person class. To resolve this problem, BeanUtil supports data binding via adder methods:

   void addPersonList(Person person) { personList.add(person); }

Note that, in order to use this adder correctly, the target of an adder, that is, a collection class (personList), must be initialized before the invocation of the adder, or BeanUtil.populate method causes NullPointerException? or some other undesired effects. Here is an souce code:

public PersonList 
{ 
   ArrayList personList = new ArrayList(); // it must be initialized. 
   public PersonList() {} 
   
   void addPerson(Person p) 
   { personList.add(p); } 

   // this getter is necessary to output JSON data, {"person":{"-c":[{"id":1, "name":"leo"}, {"id":2, "name":"yui"}]}}
   public ArrayList getPerson() { return personList; } 
}

In BeanUtil, a setter method, whose argument has no generic type parameter, e.g., public void setList(List l) never be used to bind JSON data to a class instance. In order to use a Bean class with Map objects, you must define public Map getSomething() and public void putSomething(KeyType? key, ValueType? value) methods, since BeanUtil learns class types K, V from the putSomething(K key, V value) methods. If a method public void setSomething(Map map) exists, BeanUtil simply ignores it. The following is an example of a bean class with Map object. public MapBean? { Map entry = new TreeMap?(); public MapBean?(){} public void putEntry(Key key, Value v) { entry.put(key, value); } public Map getEntry() { return entry; } }