Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
EclipseLink/Examples/MOXy/Spring/JAXBDynamicXSD
In order to use EclipseLink Dynamic JAXB with the Spring Framework, you simply need a jaxb.properties
file and an eclipselink.jar
on the classpath. No other special configuration is required. This document will demonstrate how to configure Spring to use EclipseLink JAXB.
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
eclipselink-oxm.xml
into thesetSchemaFile
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
- This is an instance of the
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
Here is an example of EclipseLink 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.
- The latest version of EclipseLink can be found on the EclipseLink download page.
- 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 ascommons-logging.jar
found in/projects/spring-build/lib/ivy
must be on the classpath.
- Model Classes
- The following model classes make use of standard JAXB annotations as well as MOXy extensions:
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 name="phoneNumbers" type="phoneNumber" nillable="true" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <xs:complexType name="phoneNumber"> <xs:sequence> <xs:element name="type" type="xs:string" minOccurs="0"/> <xs:element name="value" type="xs:string" minOccurs="0"/> </xs:sequence> </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); } }
example.gettingstarted.XMLHelperTest.java
This class demonstrates how the XMLHelper bean can be acquired and used to perform marshal/unmarshal operations on a Customer.
package example.gettingstarted; import java.io.FileInputStream; import java.io.FileOutputStream; import javax.xml.bind.JAXBElement; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.eclipse.persistence.dynamic.DynamicEntity; import org.springframework.context.ApplicationContext; 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 { System.out.println("Beginning load and save Customer test."); // 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."); } }
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> <phone-number type="work">613-555-1111</phone-number> <phone-number type="cell">613-555-2222</phone-number> </customer>