Monday, July 16, 2012

JAXB XmlAdapter – Customized Marshaling and Unmarshaling

JAXB (Java Architecture for XML Binding), is an easy to use and efficient framework for working with XML documents in Java. A developer can easily convert an XML into Java objects (Unmarshaling) and vice versa (Marshaling) using JAXB. Although simple Java types (String, int) can be directly maps to XML types, sometimes a customized representation is required. For e.g. consider an XML snippet below

<config>
   <properties>
      <property name="name 1" value="value 1"/>
      <property name="name 2" value="value 2"/>
   </properties>
</config>

By default JAXB will bind it to the following Java object structure

@XmlRootElement
public class Config {
       @XmlElement (name="properties" type=Properties.class)     
        public Properties properties;
       …….
}

@XmlType
public class Properties {
        @XmlElement
       public List property;
       …………
}

@XmlType
public class Property {
      @XmlAttribute
       public String name;
       @XmlAttribute
       public String value;
       ……….
}

But imagine a scenario where you want the domain object to look like this

public class Config {
      public HashMap properties; //Map of property name and value
}

This is a typical case where you want to read an XML configuration file and maintain the properties in a Map.

To achieve this, you need a mechanism to intercept the default marshaling and unmarshaling of JAXB. And this can be done using XMLAdapter.

JAXB provides interceptors, in the form of XMLAdapters, to customize the marshaling and unmarshaling during binding. The below screen explains the concept.

Let’s consider the above example and see how can we achieve the expected output using adapters.

First of all, note that XMLAdapter is a customization on the top of default binding and hence the default classes, mentioned above, i.e. Config, Properties and Property need to be there. Now write a custom adapter. Customer adapters are provided with 2 parameters, one which JAXB will bind and one which you need as output of binding. Within adapter, you need to implement the logic of converting one to another. Here is how our custom adapter would look like.

public class CustomAdapter extends XmlAdapter> {
       @Override
       public Properties marshal(HashMap map) throws Exception {
              Iterator> itr = map.entrySet().iterator();
              ArrayList list = new ArrayList(map.entrySet().size());
              while (itr.hasNext()) {
                     Entry entry = itr.next();
                     Property property = new Property();
                     property.setName(entry.getKey());
                     property.setValue(entry.getValue());
                     list.add(property);
              }
              Poperties properties = new Properties();
              properties.setProperties(list);
              return properties;
       }
       @Override
       public HashMap unmarshal(Properties properties) throws Exception {      
              List list = properties.getProperties();      
              HashMap map = new HashMap(list.size());
              for (Property property : list) {               
                  map.put(property.getName(), property.getValue());
              }
              return map;
       }
}

Along with this, now we need to change the root element class a bit, since we want the Hashmap as the value holder now.
@XmlRootElement
public class Config {      
       @XmlJavaTypeAdapter (CustomAdapter.class)
       @XmlElement (name="properties", type=Properties.class)
       private HashMap properties;
       ………………
}

Now write a method to test the unmarshaling.

public void testUnmarshal() {
       try {
              JAXBContext context = JAXBContext.newInstance(Config.class);
              Config config = (Config) context.createUnmarshaller().unmarshal(new File("config.xml"));
              Iterator> itr = config.getProperties().entrySet().iterator();
              while (itr.hasNext()) {
                     Entry entry = itr.next();
                     System.out.println(entry.getKey() + "  " + entry.getValue());
              }                   
       } catch (JAXBException e) {
              e.printStackTrace();
       }
}

The output of the above test method would be
name 1   value 1
name 2   value 2


Conclusion: JAXB provides XMLAdapters as a way to the developer to intercept the marshaling and unmarshaling process and write code to custom mappings.

Sunday, July 15, 2012

Hibernate Inverse Attribute – Re-Explained

It was few years ago, when I started working on the newer version of Hibernate, the first and the most confusing term I encountered is ‘inverse’ attribute. Although soon I realized that it is not that complex and perplex, however its name and the way people explained it, added lot of confusion around it.

This blog is yet another endeavor to explain this attribute, and possibly in the most simple way using easily understandable examples.

Before we start, note that inverse attribute is used in bidirectional mapping including one-to-many and many-to-many (soon you will realize that it make sense).

Now, whenever you get an inverse attribute with true value in collection mapping (for e.g. set) of an entity mapping, read it like this: “I am not the one who is responsible for maintaining this relationship, but the inverse is true i.e. the other entity in the relationship is responsible for this”.

Let’s explore this with examples.

We’ll consider an example which includes both one-to-many and many-to-many relationship. Assume 3 entities, Employee, Department and Certification. The relationship between Department and Employee is one-to-many from Department side (i.e. One department can have many employees, but an employee belongs to one department only). While the relationship between Employee and Certification is many-to-many (i.e. an employee can have many certifications while a certification can belong to multiple employees). Here is how this would look like



The relationship between Employee and Certification is maintained using a relationship table (Emp_Cert) as shown below.
 

 
The domain and mapping of the 3 entities would look like this:

public class Employee {

     private int id;
     private String name;
     private Department dept;
     private Set certs;
    //Setters Getters…
}

<class name="Employee">
     <id name="id">
        <generator class="sequence"/>
     </id>
     <property name="name"/>
     <many-to-one name="dept" class="Department" column="dept_id"></many-to-one>
     <set name="certs" inverse="false" table="emp_cert">
        <key column="emp_id"/>
        <many-to-many column="cert_id" class="Certification"/>
     </set>
</class>


public class Department {

      private int id;
      private String name;
      private Set emps;
      //Setters Getters…..
}

<class name="Department">
     <id name="id">
       <generator class="sequence"/>
     </id>
     <property name="name"/>
     <set name="emps" inverse="false">
        <key column="dept_id"/>
        <one-to-many class="Employee"/>
     </set>
</class>

public class Certification {

      private int id;
      private String name;
      private Set emps;
      //Setters Getters…..
}

<class name="Certification">
     <id name="id">
        <generator class="sequence"/>
     </id>
     <property name="name"/>
     <set name="emps" inverse="false" table="emp_cert">
        <key column="cert_id"/>
        <many-to-many column="emp_id" class="Employee"/>
     </set>
</class>

Note that inverse attribute is used only in collection mapping for e.g. set.

Let’s first discuss the one-to-many relationship.

In the Department mapping above, since the inverse attribute has false (default) value for employee set, it indicates that you can also add Employees through Department class.

Consider the code below:

//Set ID from DB.
int empID = 1;
int deptID = 1;

SessionFactory factory = HibernateUtil.getSessionFactory();
Session session = factory.openSession();
Transaction tx = session.beginTransaction();
Employee emp = (Employee) session.get(Employee.class, empID);
Department dept = (Department) session.get(Department.class, deptID);
dept.getEmps().add(emp);//This will be saved in DB as inverse is false.
tx.commit();
session.flush();

The execution of above code will result in an Update SQL statement to update the dept_id value of given Employee.

Now consider the case of inverse=”true”. The mapping would look like this:

<class name="Department">
     <id name="id">
        <generator class="sequence"/>
     </id>
     <property name="name"/>
     <set name="emps" inverse="true">
        <key column="dept_id"/>
        <one-to-many class="Employee"/>
     </set>
</class>

This tells hibernate that Department entity is not responsible for maintaining the relationship.

Thus if the same above code is executed again, Hibernate won’t execute any update SQL and employees’ dept_id won’t be updated.


Thus in one-to-many, we use inverse always in the side which is ‘one’ in the relationship and which indicates that this is not the side which will maintain relationship.

Now consider the case of many-to-many relationship. In this example, relationship between Employee and Certification is many-to-many. An employee can do any number of certificates while a certification can be done by more than one employee.

In many-to-many relationship, both sides or one of them can be responsible for maintaining the relationship. Thus inverse attribute can be set true at any side, which you think is not responsible for maintaining relationship. Consider the code snippet below

//Set ID from DB.
int empID = 1;
int certId = 1;

SessionFactory factory = HibernateUtil.getSessionFactory();
Session session = factory.openSession();
Transaction tx = session.beginTransaction();
Employee emp = (Employee) session.get(Employee.class, empID);
Certification cert= (Certification) session.get(Certification.class, certId);

//If inverse is false in both employee and certification mappings, you can execute any of the below 2 statements. Both will result in same (insertion in emp_cert table)
//But if inverse is true in certification mapping, statement 2 won't work.
//If inverse is true in employee certification, statement 1 won't work.
//emp.getCerts().add(cert); //statemet 1
//cert.getEmps().add(emp); //statement 2

tx.commit();
session.flush();

If inverse is false at both end, any of the below 2 statement can result in insertion of an entry in emp_cert table.

emp.getCerts().add(cert); //statemet 1
cert.getEmps().add(emp); //statement 2

But assume that inverse is true in Certification mapping, then statement 2 won’t result in SQL insert statement for emp_cert table and hence no row will be inserted in this table.

<class name="Certification">
     <id name="id">
        <generator class="sequence"/>
     </id> <property name="name"/>
     <set name="emps" inverse="true" table="emp_cert">
     <key column="cert_id"/>
       <many-to-many column="emp_id" class="Employee"/>   
     </set>
</class>

Similarly, if inverse attribute is true in Employee mapping, then statement 1 above will not insert any row in emp_cert table.

Conclusion: I hope after reading this article and understanding this example, you will realize that inverse attribute in hibernate is an easy to understand and very helpful parameter in optimizing the bidirectional relationship.