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 settersand 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. :Dpackage 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.
Hi Rommel,
ReplyDeleteThank you for posting this.
You can also use our sdo-jaxb-compiler.sh(cmd) script to generate both the JAXB and SDO models from an XML schema.
Also, since the addition of the JAXBHelperContext to EclipseLink you no longer need to generate the impl classes for your SDO model, this option is already pre-configured when using the sdo-jaxb-compler.sh(cmd) script.
-Blaise
Blaise Doughan
Team Lead, EclipseLink JAXB/SDO (MOXy)