In previous post, I demonstrated, how to easily convert pojo's to xml elements and vice-versa thru JAXB. The key to implementation in that post was the JAXBContext object which served as the factory for the Marshaller and Unmarshalller objects which accordingly takes charge for the marshalling and unmarshalling of POJO's to XML. In this post, I will take a step further by demostrating POJO to SDO marshalling through the help of JAXBHelperContext, the POJO/SDO bridge.
The JAXBHelperContext is a bridge between POJOs and SDO DataObjects. This bridge allows POJO data to be dynamically exposed as SDO DataObjects without the need to implement SDO interfaces and implementaions for each entity. Prior to this JAXBHelperContext, if you need to convert a pojo Job object to its SDO equivalent, aside from the pojo itself, you also need to have JobSDO interface, a JobSDOImpl implementation class, a JobSDO.xsd schema, and bunch of methods to handle the marshalling between your pojo and the SDO class. But with JAXBHelperContext, you only need the JobSDO.xsd schema.
Below is a sample pojo Job.java:
package soadev.hrservice.model;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
@XmlType(name = "JobSDO", namespace = "/soadev.hrservice.model/")
@XmlRootElement(name = "jobSDO")
@XmlAccessorType(XmlAccessType.FIELD)
public class Job{
private String jobId;
private String jobTitle;
private Long maxSalary;
private Long minSalary;
//getters and setters
and the corresponding JobSDO.xsd schema definition
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="/soadev.hrservice.model/"
xmlns="/soadev.hrservice.model/" xmlns:sdoJava="commonj.sdo/java"
sdoJava:package="soadev.hrservice.model">
<xsd:import namespace="commonj.sdo/java"/>
<xsd:complexType name="JobSDO">
<xsd:sequence>
<xsd:element name="jobId" type="xsd:string" minOccurs="0"/>
<xsd:element name="jobTitle" type="xsd:string" minOccurs="0"/>
<xsd:element name="maxSalary" type="xsd:long" minOccurs="0"/>
<xsd:element name="minSalary" type="xsd:long" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="jobSDO" type="JobSDO"/>
</xsd:schema>
The @XmlType(name = "JobSDO", namespace = "/soadev.hrservice.model/") should map accordingly to the schema definition as color coded above. The corresponding field names in the pojo should should also map to the elements in the schema. In case a field is not the same with the schema element name then you could put an @XmlElement(name="elementName") annotation on top of the field declaration to map it to the approriate element.
Action speaks louder than words...
The runner class below demonstrate how to instantiate SDO instances from POJO and schema definition and how to wrap and unwrap POJO's to SDO and vice-versa. I was amazed to note that any changes made to pojo instance is also being reflected on the SDO wrapper- well, the SDO is just wrapping the pojo anyway. :D
package soadev.sdojaxbsample.clients;
import commonj.sdo.DataObject;
import commonj.sdo.Type;
import commonj.sdo.helper.XMLDocument;
import java.sql.Timestamp;
import java.util.Date;
import javax.xml.bind.JAXBContext;
import org.eclipse.persistence.sdo.helper.jaxb.JAXBHelperContext;
import soadev.hrservice.model.Department;
import soadev.hrservice.model.Employee;
import soadev.hrservice.model.Job;
public class PojoToSdoClient {
public static void main(String[] args) {
PojoToSdoClient client = new PojoToSdoClient();
try {
client.testInstantiateSimpleSdo();
client.testInstantiateComplexSdo();
client.testTheAmazingWrappingPojoToSdo();
client.testTheAmazingUnwrappingSdoToPojo();
} catch (Exception e) {
e.printStackTrace();
}
}
public void testInstantiateSimpleSdo()throws Exception{
System.out.println("----Start testInstantiateSimpleSdo----");
JAXBContext jaxbContext = JAXBContext.newInstance(Job.class);
JAXBHelperContext jaxbHelperContext = new JAXBHelperContext(jaxbContext);
ClassLoader loader = Thread.currentThread().getContextClassLoader();
jaxbHelperContext.getXSDHelper().define(loader.getResourceAsStream("soadev/hrservice/model/JobSDO.xsd"), "soadev/hrservice/model");
Type jobType = jaxbHelperContext.getType(Job.class);
System.out.println("Instantiating dataobject...");
DataObject jobSDO = jaxbHelperContext.getDataFactory().create(jobType);
System.out.println("JobSDO instantiated: " + jobSDO);
jobSDO.set("jobId", "SOADEV");
jobSDO.set("jobTitle", "SOA Developer");
jobSDO.set("maxSalary", 20000L);
jobSDO.set("minSalary", 18000L);
System.out.println("jobTitle: " +jobSDO.getString("jobTitle"));
//print out
XMLDocument xmlDocument =jaxbHelperContext.getXMLHelper().createDocument(jobSDO, jobSDO.getType().getURI(), "jobSDO");
jaxbHelperContext.getXMLHelper().save(xmlDocument, System.out, null);
System.out.println("----End testInstantiateSimpleSdo----");
}
public void testInstantiateComplexSdo()throws Exception{
System.out.println("----Start testInstantiateComplexSdo----");
JAXBContext jaxbContext = JAXBContext.newInstance(Employee.class);
JAXBHelperContext jaxbHelperContext = new JAXBHelperContext(jaxbContext);
ClassLoader loader = Thread.currentThread().getContextClassLoader();
jaxbHelperContext.getXSDHelper().define(loader.getResourceAsStream("soadev/hrservice/model/JobSDO.xsd"), "soadev/hrservice/model");
jaxbHelperContext.getXSDHelper().define(loader.getResourceAsStream("soadev/hrservice/model/DepartmentSDO.xsd"), "soadev/hrservice/model");
jaxbHelperContext.getXSDHelper().define(loader.getResourceAsStream("soadev/hrservice/model/EmployeeSDO.xsd"), "soadev/hrservice/model");
Type employeeType = jaxbHelperContext.getType(Employee.class);
System.out.println("Instantiating EmployeeSDO...");
DataObject employeeSDO = jaxbHelperContext.getDataFactory().create(employeeType);
System.out.println("EmployeeSDO instantiated: " + employeeSDO);
employeeSDO.set("firstName", "Rommel");
employeeSDO.set("lastName", "Pino");
Type jobType = jaxbHelperContext.getType(Job.class);
System.out.println("Instantiating JobSDO...");
DataObject jobSDO = jaxbHelperContext.getDataFactory().create(jobType);
System.out.println("JobSDO instantiated: " + jobSDO);
jobSDO.set("jobId", "SOADEV");
System.out.println("Setting the job property of the EmployeeSDO object");
employeeSDO.set("job", jobSDO);
Type departmentType = jaxbHelperContext.getType(Department.class);
System.out.println("Instantiating DepartmentSDO...");
DataObject departmentSDO = jaxbHelperContext.getDataFactory().create(departmentType);
System.out.println("DepartmentSDO instantiated: " + departmentSDO);
departmentSDO.set("departmentName", "Java Development Team");
System.out.println("Setting the department property of the EmployeeSDO object");
employeeSDO.set("department", departmentSDO);
System.out.println("Retrieving the jobId property from the EmployeeSDO object");
System.out.println("jobId is: " + employeeSDO.get("job/jobId"));
System.out.println("Retrieving the departmentName property from the EmployeeSDO object");
System.out.println("departmentName is: " + employeeSDO.get("department/departmentName"));
//print out
XMLDocument xmlDocument =jaxbHelperContext.getXMLHelper().createDocument(employeeSDO, employeeSDO.getType().getURI(), "employeeSDO");
jaxbHelperContext.getXMLHelper().save(xmlDocument, System.out, null);
System.out.println("----End testInstantiateComplexSdo----");
}
public void testTheAmazingWrappingPojoToSdo()throws Exception{
System.out.println("----Start testTheAmazingWrappingPojoToSdo----");
Employee employee = new Employee();
employee.setLastName("Pino");
employee.setFirstName("Rommel");
employee.setHireDate(new Timestamp(new Date().getTime()));
Job job = new Job();
job.setJobId("SOADEV");
job.setJobTitle("SOA Developer");
job.setMaxSalary(20000L);
job.setMinSalary(18000L);
employee.setJob(job);
Department department = new Department();
department.setDepartmentId(100L);
department.setDepartmentName("Java Development Team");
employee.setDepartment(department);
JAXBContext jaxbContext = JAXBContext.newInstance(Employee.class);
JAXBHelperContext jaxbHelperContext = new JAXBHelperContext(jaxbContext);
ClassLoader loader = Thread.currentThread().getContextClassLoader();
jaxbHelperContext.getXSDHelper().define(loader.getResourceAsStream("soadev/hrservice/model/JobSDO.xsd"), "soadev/hrservice/model");
jaxbHelperContext.getXSDHelper().define(loader.getResourceAsStream("soadev/hrservice/model/DepartmentSDO.xsd"), "soadev/hrservice/model");
jaxbHelperContext.getXSDHelper().define(loader.getResourceAsStream("soadev/hrservice/model/EmployeeSDO.xsd"), "soadev/hrservice/model");
DataObject employeeSDO = jaxbHelperContext.wrap(employee);
//print out
XMLDocument xmlDocument =jaxbHelperContext.getXMLHelper().createDocument(employeeSDO, employeeSDO.getType().getURI(), "employeeSDO");
jaxbHelperContext.getXMLHelper().save(xmlDocument, System.out, null);
System.out.println("----End testTheAmazingWrappingPojoToSdo----");
}
public void testTheAmazingUnwrappingSdoToPojo()throws Exception{
System.out.println("----Start testTheAmazingUnwrappingSdoToPojo----");
JAXBContext jaxbContext = JAXBContext.newInstance(Job.class);
JAXBHelperContext jaxbHelperContext = new JAXBHelperContext(jaxbContext);
ClassLoader loader = Thread.currentThread().getContextClassLoader();
jaxbHelperContext.getXSDHelper().define(loader.getResourceAsStream("soadev/hrservice/model/JobSDO.xsd"), "soadev/hrservice/model");
Type jobType = jaxbHelperContext.getType(Job.class);
DataObject jobSDO = jaxbHelperContext.getDataFactory().create(jobType);
jobSDO.set("jobTitle", "SOA Developer");
System.out.println("Unwrapping jobSDO to job Pojo...");
Job job = (Job) jaxbHelperContext.unwrap(jobSDO);
System.out.println(job);
System.out.println(job.getJobTitle());
job.setJobId("SOADEV");
System.out.println("Changes to Pojo is also reflected in the SDO wrapper...");
System.out.println(jobSDO.getString("jobId"));
System.out.println("----End testTheAmazingUnwrappingSdoToPojo----");
}
}
Run output...
C:\Oracle\11g\jdk160_24\bin\javaw.exe -client -classpath ...
----Start testInstantiateSimpleSdo----
Instantiating dataobject...
JobSDO instantiated: soadev.hrservice.model.JobSDOImpl@2c35e
jobTitle: SOA Developer
<?xml version="1.0" encoding="UTF-8"?>
<ns0:jobSDO xmlns:ns0="/soadev.hrservice.model/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<jobId>SOADEV</jobId>
<jobTitle>SOA Developer</jobTitle>
<maxSalary>20000</maxSalary>
<minSalary>18000</minSalary>
</ns0:jobSDO>
----End testInstantiateSimpleSdo----
----Start testInstantiateComplexSdo----
[EL Warning]: 2011-08-01 16:32:28.683--An java.lang.IllegalArgumentException occurred processing referenced schema with uri /soadev.hrservice.model/ with schemaLocation DepartmentSDO.xsd.
[EL Warning]: 2011-08-01 16:32:28.699--An java.lang.IllegalArgumentException occurred processing referenced schema with uri /soadev.hrservice.model/ with schemaLocation JobSDO.xsd.
Instantiating EmployeeSDO...
EmployeeSDO instantiated: soadev.hrservice.model.EmployeeSDOImpl@18a8ce2
Instantiating JobSDO...
JobSDO instantiated: soadev.hrservice.model.JobSDOImpl@c943d1
Setting the job property of the EmployeeSDO object
Instantiating DepartmentSDO...
DepartmentSDO instantiated: soadev.hrservice.model.DepartmentSDOImpl@b40ec4
Setting the department property of the EmployeeSDO object
Retrieving the jobId property from the EmployeeSDO object
jobId is: SOADEV
Retrieving the departmentName property from the EmployeeSDO object
departmentName is: Java Development Team
<?xml version="1.0" encoding="UTF-8"?>
<ns0:employeeSDO xmlns:ns0="/soadev.hrservice.model/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<department>
<departmentName>Java Development Team</departmentName>
</department>
<firstName>Rommel</firstName>
<job>
<jobId>SOADEV</jobId>
</job>
<lastName>Pino</lastName>
</ns0:employeeSDO>
----End testInstantiateComplexSdo----
----Start testTheAmazingWrappingPojoToSdo----
[EL Warning]: 2011-08-01 16:32:28.762--An java.lang.IllegalArgumentException occurred processing referenced schema with uri /soadev.hrservice.model/ with schemaLocation DepartmentSDO.xsd.
[EL Warning]: 2011-08-01 16:32:28.762--An java.lang.IllegalArgumentException occurred processing referenced schema with uri /soadev.hrservice.model/ with schemaLocation JobSDO.xsd.
<?xml version="1.0" encoding="UTF-8"?>
<ns0:employeeSDO xmlns:ns0="/soadev.hrservice.model/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<department>
<departmentId>100</departmentId>
<departmentName>Java Development Team</departmentName>
</department>
<firstName>Rommel</firstName>
<hireDate>2011-08-01T13:32:28.699Z</hireDate>
<job>
<jobId>SOADEV</jobId>
<jobTitle>SOA Developer</jobTitle>
<maxSalary>20000</maxSalary>
<minSalary>18000</minSalary>
</job>
<lastName>Pino</lastName>
</ns0:employeeSDO>
----End testTheAmazingWrappingPojoToSdo----
----Start testTheAmazingUnwrappingSdoToPojo----
Unwrapping jobSDO to job Pojo...
soadev.hrservice.model.Job@24c4a3
SOA Developer
Changes to Pojo is also reflected in the SDO wrapper...
SOADEV
----End testTheAmazingUnwrappingSdoToPojo----
Process exited with exit code 0.
Sample Application
You can access the sample application from
here.
Common Gotchas
If you encounter "ClassCastException com.sun.xml.bind.v2.runtime.JAXBContextImpl cannot be cast to org.eclipse.persistence.jaxb.JAXBContext" when you run your own sample, you need to specify EclipseLink MOXy as your JAXB provider by adding a file called jaxb.properties in the same package as your model classes. Please see the sample file in the application.
Relevant Links