Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "EclipseLink/Examples/MOXy/Spring/JAXBDynamicXSD"

< EclipseLink‎ | Examples‎ | MOXy‎ | Spring
(example.gettingstarted.XMLHelperTest.java)
(Example)
 
(7 intermediate revisions by the same user not shown)
Line 69: Line 69:
 
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
 
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
 
 
   <xs:element name="address" type="address"/>
 
   <xs:element name="address" type="address"/>
 
 
   <xs:element name="customer" type="customer"/>
 
   <xs:element name="customer" type="customer"/>
 
 
   <xs:element name="phoneNumber" type="phoneNumber"/>
 
   <xs:element name="phoneNumber" type="phoneNumber"/>
  
Line 87: Line 84:
 
       <xs:element ref="address" minOccurs="0"/>
 
       <xs:element ref="address" minOccurs="0"/>
 
       <xs:element name="name" type="xs:string" minOccurs="0"/>
 
       <xs:element name="name" type="xs:string" minOccurs="0"/>
       <xs:element name="phoneNumbers" type="phoneNumber" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
+
       <xs:element ref="phoneNumber" minOccurs="0" maxOccurs="unbounded"/>
 
     </xs:sequence>
 
     </xs:sequence>
 
   </xs:complexType>
 
   </xs:complexType>
Line 93: Line 90:
 
   <xs:complexType name="phoneNumber">
 
   <xs:complexType name="phoneNumber">
 
     <xs:sequence>
 
     <xs:sequence>
      <xs:element name="type" type="xs:string" minOccurs="0"/>
 
 
       <xs:element name="value" type="xs:string" minOccurs="0"/>
 
       <xs:element name="value" type="xs:string" minOccurs="0"/>
 
     </xs:sequence>
 
     </xs:sequence>
 +
    <xs:attribute name="type" type="xs:string"/>
 
   </xs:complexType>
 
   </xs:complexType>
 
</xs:schema>
 
</xs:schema>
Line 156: Line 153:
 
</source>
 
</source>
  
==== example.gettingstarted.XMLHelperTest.java ====
+
This code demonstrates how the XMLHelper bean can be acquired and used to perform marshal/unmarshal operations on a Customer.
This class demonstrates how the XMLHelper bean can be acquired and used to perform marshal/unmarshal operations on a Customer.
+
 
<source lang="java">
 
<source lang="java">
package example.gettingstarted;
+
// initialize IoC Container
 +
ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
 +
// retrieve the XMLHelper instance from the Container
 +
XMLHelper xmlHelper = (XMLHelper) appContext.getBean("xmlHelper");
  
import java.io.FileInputStream;
+
// load Customer
import java.io.FileOutputStream;
+
JAXBElement<DynamicEntity> jaxbElement = (JAXBElement<DynamicEntity>) xmlHelper.load(new StreamSource(new FileInputStream("customer.xml")));
 
+
DynamicEntity customer = jaxbElement.getValue();
import javax.xml.bind.JAXBElement;
+
// update customer
import javax.xml.transform.stream.StreamResult;
+
DynamicEntity address = customer.get("address");
import javax.xml.transform.stream.StreamSource;
+
address.set("street", "234 Some Other Rd.");
 
+
customer.set("address", address);
import org.eclipse.persistence.dynamic.DynamicEntity;
+
// save customer
import org.springframework.context.ApplicationContext;
+
xmlHelper.save(customer, new StreamResult(new FileOutputStream("customer.xml")));
import org.springframework.context.support.ClassPathXmlApplicationContext;
+
 
+
public class XMLHelperTest {
+
    private static final String APP_CTX = "applicationContext.xml";
+
    private static final String CUSTOMER_XML = "classes/customer.xml";
+
    private static final String CUSTOMER_XML_OUT = "classes/customer-out.xml";
+
    private static final String XMLHELPER_BEAN = "xmlHelper";
+
    private XMLHelper xmlHelper;
+
   
+
    public static void main(String[] args) throws Exception {
+
        XMLHelperTest test = new XMLHelperTest();
+
        test.setup();
+
        test.testLoadAndSaveCustomer();
+
    }
+
 
+
    public void setup() {
+
        // initialize IoC Container
+
        ApplicationContext appContext = new ClassPathXmlApplicationContext(APP_CTX);
+
        // retrieve the XMLHelper instance from the Container
+
        xmlHelper = (XMLHelper) appContext.getBean(XMLHELPER_BEAN);
+
    }
+
   
+
    public void testLoadAndSaveCustomer() throws Exception {
+
        // load Customer
+
        try {
+
            JAXBElement<DynamicEntity> jaxbElement = (JAXBElement<DynamicEntity>) xmlHelper.load(new StreamSource(new FileInputStream(CUSTOMER_XML)));
+
            if (jaxbElement != null) {
+
                DynamicEntity customer = jaxbElement.getValue();
+
                if (customer.get("name") != null && customer.get("address") != null && customer.get("phoneNumbers") != null) {
+
                    String name = customer.get("name");
+
                    if (name.equals("Jane Doe")) {
+
                        customer.set("name", "Jane Doh");
+
                        xmlHelper.save(customer, new StreamResult(new FileOutputStream(CUSTOMER_XML_OUT)));
+
                        jaxbElement = (JAXBElement<DynamicEntity>) xmlHelper.load(new StreamSource(new FileInputStream(CUSTOMER_XML_OUT)));
+
                        if (jaxbElement != null) {
+
                            customer = jaxbElement.getValue();
+
                            name = customer.get("name");
+
                            if (name.equals("Jane Doh")) {
+
                                System.out.println("Test passed.");
+
                                return;
+
                            }
+
                        }
+
                    }
+
                }
+
            }
+
        } catch (ClassCastException cce) {
+
            //cce.printStackTrace();
+
        }
+
        System.out.println("Test failed.");
+
    }
+
}
+
 
</source>
 
</source>
  
Line 233: Line 181:
 
       <street>123 Any Street</street>
 
       <street>123 Any Street</street>
 
     </address>
 
     </address>
     <phone-number type="work">613-555-1111</phone-number>
+
     <phoneNumber type="work">
     <phone-number type="cell">613-555-2222</phone-number>
+
        <value>613-555-1111</value>
 +
     </phoneNumber>
 +
    <phoneNumber type="cell">
 +
        <value>613-555-2222</value>
 +
    </phoneNumber>
 
</customer>
 
</customer>
 
</source>
 
</source>

Latest revision as of 13:21, 26 November 2010

In order to use EclipseLink Dynamic JAXB with the Spring Framework, you simply need a jaxb.properties file, an eclipselink.jar, and a jaxb-xjc.jar on the classpath. No other special configuration is required. This document will demonstrate how to configure Spring to use EclipseLink Dynamic JAXB, bootstrapped from an XML schema.

Configuration: applicationContext.xml

In Spring, beans are configured using the applicationContext.xml file. The following XML file will be used to configure our beans:

<beans 
    xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
 
    <bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
        <property name="lazyInit" value="true"/>
        <property name="contextPath" value="example.gettingstarted"/>
    </bean>
 
    <bean id="xmlHelper" class="example.gettingstarted.XMLHelper">
        <property name="schemaFile"><value>classpath:customer.xsd</value></property>
        <property name="marshaller" ref="jaxbMarshaller"/>
     </bean>
 
</beans>

Two beans are being defined here:

  • xmlHelper
    • This is the class that will do all of the work, i.e. marshal and unmarshal
    • We use the "schemaFile" property to indicate that we want Spring to inject the XML schema customer.xsd into the setSchemaFile method on our xmlHelper bean. This schema will be used to create our dynamic entities.
    • We use the "marshaller" property to indicate that we want Spring to inject an instance of org.springframework.oxm.jaxb.Jaxb2Marshaller
  • jaxbMarshaller
    • This is an instance of the org.springframework.oxm.jaxb.Jaxb2Marshaller class that will be injected into our xmlHelper bean
    • We use the "contextPath" property to pass the context path to the underlying JAXBContext
    • We use the "lazyInit" property set to "true" to allow us to pass in the properties object containing the XML schema before the underlying JAXBContext is created

Following is the jaxb.properties file that tells Spring to use EclipseLink JAXB:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory

Bootstrapping the Application

The standard Spring bean lookup method can be used to gain access to the xmlHelper bean:

// initialize IoC Container
ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// retrieve the XMLHelper instance from the Container
XMLHelper xmlHelper = (XMLHelper) appContext.getBean("xmlHelper");

Example: Bootstrap from an XML schema

Here is an example of EclipseLink Dynamic JAXB used with the Spring Framework.

Requirements

  • EclipseLink
    • The latest version of EclipseLink can be found on the EclipseLink download page. eclipselink.jar must be on the classpath.
  • Spring Framework
    • The latest version of the Spring Framework can be found on the Spring download page.
    • The JAR files in the dist folder of your Spring install as well as commons-logging.jar found in /projects/spring-build/lib/ivy must be on the classpath.
  • JAXB XJC
    • The latest version of XJC is bundled with the JAXB RI. jaxb-xjc.jar must be on the classpath.

Source/Config Files

This section contains the various source and configuration files for the example.

customer.xsd

Following is the XML schema that is used to create the dynamic entities:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="address" type="address"/>
  <xs:element name="customer" type="customer"/>
  <xs:element name="phoneNumber" type="phoneNumber"/>
 
  <xs:complexType name="address">
    <xs:sequence>
      <xs:element name="city" type="xs:string" minOccurs="0"/>
      <xs:element name="street" type="xs:string" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
 
  <xs:complexType name="customer">
    <xs:sequence>
      <xs:element ref="address" minOccurs="0"/>
      <xs:element name="name" type="xs:string" minOccurs="0"/>
      <xs:element ref="phoneNumber" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>
 
  <xs:complexType name="phoneNumber">
    <xs:sequence>
      <xs:element name="value" type="xs:string" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="type" type="xs:string"/>
  </xs:complexType>
</xs:schema>

example.gettingstarted.XMLHelper.java

This is the class responsible for marshal/unmarshal operations:

package example.gettingstarted;
 
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
 
import javax.xml.bind.JAXBException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
 
import org.springframework.core.io.Resource;
import org.springframework.oxm.XmlMappingException;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
 
public class XMLHelper {
    public static final String XML_SCHEMA_KEY = "xml-schema";
    private Map<String, Source> properties;
    private Jaxb2Marshaller marshaller;
 
    /**
     * Unmarshal a given source
     */
    public Object load(Source source) throws XmlMappingException, IOException {
        return marshaller.unmarshal(source);
    }
 
    /**
     * Marshal a given Object to a Result
     */
    public void save(Object obj, Result result) throws XmlMappingException, IOException {
        marshaller.marshal(obj, result);
    }
 
    /**
     * This method is used by Spring to inject the XSD file that is to be used 
     * to generate the domain classes dynamically. 
     */
    public void setSchemaFile(Resource schemaFile) throws IOException, JAXBException {
        properties = new HashMap<String, Source>();
        properties.put(XML_SCHEMA_KEY, new StreamSource(schemaFile.getInputStream()));
    }
 
    /**
     * This method is used by Spring to inject an instance of Jaxb2Marshaller
     */
    public void setMarshaller(Jaxb2Marshaller marshaller) {
        this.marshaller = marshaller;
        this.marshaller.setJaxbContextProperties(properties);
    }
}

This code demonstrates how the XMLHelper bean can be acquired and used to perform marshal/unmarshal operations on a Customer.

// initialize IoC Container
ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// retrieve the XMLHelper instance from the Container
XMLHelper xmlHelper = (XMLHelper) appContext.getBean("xmlHelper");
 
// load Customer
JAXBElement<DynamicEntity> jaxbElement = (JAXBElement<DynamicEntity>) xmlHelper.load(new StreamSource(new FileInputStream("customer.xml")));
DynamicEntity customer = jaxbElement.getValue();
// update customer
DynamicEntity address = customer.get("address");
address.set("street", "234 Some Other Rd.");
customer.set("address", address);
// save customer
xmlHelper.save(customer, new StreamResult(new FileOutputStream("customer.xml")));

customer.xml

This is a sample instance document.

<?xml version="1.0" encoding="UTF-8"?>
<customer>
   <name>Jane Doe</name>
   <address>
      <city>My Town</city>
      <street>123 Any Street</street>
    </address>
    <phoneNumber type="work">
        <value>613-555-1111</value>
    </phoneNumber>
    <phoneNumber type="cell">
        <value>613-555-2222</value>
    </phoneNumber>
</customer>

Back to the top