JAXB Moxy- Question on how to annotate field that is xsd complex type
I am getting started with JaxB and am using the Moxy implementation. I have an industry standard xsd that I converted to Java Object Model using Jaxb. I have gotten as far as annotating simple fields like string,integer and date.
I have been searching and need to be pointed in the right direction to annotate the following field which is a xsd complex type which has 4 attributes and an optional string element. A subset of the generated code is as follows:
Conditions.java
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"condition"
})
@XmlRootElement(name = "conditions")
public class Conditions {
protected List<Conditions.Condition> condition;
public List<Conditions.Condition> getCondition() {
if (condition == null) {
condition = new ArrayList<Conditions.Condition>();
}
return this.condition;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"problemDate",
"problemType",
"problemCode",
"problemStatus",
})
public static class Condition {
protected IvlTs problemDate;
//This is the field I need to annotate (problemType)
protected Cd problemType;
开发者_开发问答 //The 2 below fields (problemCode, problemStatus) will also have to be annotated but I am just focusing on problemType for now
protected Cd problemCode;
protected Ce problemStatus
public void setProblemDate(IvlTs value) {
this.problemDate = value;
}
public void setProblemType(Cd value) {
this.problemType = value;
}
public void setProblemCode(Cd value) {
this.problemCode = value;
}
public void setProblemStatus(Ce value) {
this.problemStatus = value;
}
//omitted getters
}
Cd.java
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "cd", propOrder = {
"originalText",
})
public class Cd {
protected Object originalText;
@XmlAttribute(name = "code")
@XmlSchemaType(name = "anySimpleType")
protected String code;
@XmlAttribute(name = "displayName")
@XmlSchemaType(name = "anySimpleType")
protected String displayName;
@XmlAttribute(name = "codeSystem")
@XmlSchemaType(name = "anySimpleType")
protected String codeSystem;
@XmlAttribute(name = "codeSystemName")
@XmlSchemaType(name = "anySimpleType")
protected String codeSystemName;
@XmlAttribute(name = "nullFlavor")
protected NullFlavorType nullFlavor;
//ommitted getters and setters
The Cd.java class will be used for a number of other classes, not only in the Conditions.java class.
My question in particular is how would I annotate my fields for problemType in Conditions.java, where problemType has 4 attributes and one optional element.
I will not be able to directly annotate Cd.java as the xml input will differ depending on what class I am implementing (choice of 8 other classes that use Cd.java class). The existing annotations above were auto-generated by Jaxb The xml input for the Conditions.java problemType is as follows:
<PROBLEM_MODULE>
<code>24434</code> //Maps to protected String code in Cd.java;
<codeName>ICD-9</codeName> //Maps to protected String codeSystem in Cd.java;
<display>Asthma</display> //Maps to protected String displayName in Cd.java;
<codeSystem>2.564.34343.222</codeSystem> // Maps to protected String codeSystemName in Cd.java;
</PROBLEM_MODULE>
Please advise where I need to clarify my question. Ultimately I am requesting resources or tutorial to help me through this.
******UPDATE******* Blaise's solution worked perfectly as I tested it on another project that is not as complex. Thus, the method is right, but there is something that I am getting wrong with the metadata file. I updated the Conditions.java file above, as I left out details that may effect the way I need to implement the metadata file.
My oxm.xml file
<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="conditions.exec"
xml-mapping-metadata-complete="true">
<java-types>
<java-type name="Conditions" xml-accessor-type="FIELD">
<xml-root-element name="PROBLEM_MODULE"/>
</java-type>
<java-type name="Cd" xml-accessor-type="FIELD">
<java-attributes>
<xml-type prop-order="code codeSystem displayName codeSystemName"/>
<xml-element java-attribute="codeSystem" name="codeName"/>
<xml-element java-attribute="displayName" name="display"/>
<xml-element java-attribute="codeSystemName" name="codeSystem"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
*Main Class*
public static void main(String[] args) {
try {
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, new File("src/conditions/exec/oxm.xml"));
JAXBContext jc = JAXBContext.newInstance(new Class[] {Conditions.class,Cd.class}, properties);
// create an Unmarshaller
Unmarshaller u = jc.createUnmarshaller();
conditions.exec.Conditions InventoryInput = (conditions.exec.Conditions) u.unmarshal(
new File("src/conditions/exec/problems.xml")); //input file
// create a Marshaller and marshal to a file
Marshaller resultMarshaller = jc.createMarshaller();
resultMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
resultMarshaller.marshal(InventoryInput, System.out);
} catch (JAXBException je) {
je.printStackTrace();
}
You can leverage EclipseLink JAXB (MOXy)'s external binding file to apply a second mapping to your class:
oxm.xml
One thing that I have set in this file is xml-mapping-metadata-complete="true"
, this setting tells MOXy to ignore the annotations completely and just use this file. By default the OXM file is used to supplement the annotations.
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="forum7043389"
xml-mapping-metadata-complete="true">
<java-types>
<java-type name="Root2">
<xml-root-element/>
</java-type>
<java-type name="Cd">
<xml-type prop-order="code codeSystem displayName codeSystemName"/>
<java-attributes>
<xml-element java-attribute="codeSystem" name="codeName"/>
<xml-element java-attribute="displayName" name="display"/>
<xml-element java-attribute="codeSystemName" name="codeSystem"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Demo
The oxm.xml file is passed in as a property to create the JAXBContext
. In the example below jc1
is created on the classes and jc2
is created on the classes and oxm.xml
package forum7043389;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
public class Demo {
public static void main(String[] args) throws Exception {
Cd cd = new Cd();
cd.setCode("24434");
cd.setCodeSystem("ICD-9");
cd.setDisplayName("Asthma");
cd.setCodeSystemName("2.564.34343.222");
JAXBContext jc1 = JAXBContext.newInstance(Root1.class);
Marshaller marshaller1 = jc1.createMarshaller();
marshaller1.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Root1 root1 = new Root1();
root1.setCd(cd);
marshaller1.marshal(root1, System.out);
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum7043389/oxm.xml");
JAXBContext jc2 = JAXBContext.newInstance(new Class[] {Root2.class}, properties);
Marshaller marshaller2 = jc2.createMarshaller();
marshaller2.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Root2 root2 = new Root2();
root2.setCd(cd);
marshaller2.marshal(root2, System.out);
}
}
Output
The following is the output from running the demo:
<?xml version="1.0" encoding="UTF-8"?>
<root1>
<cd code="24434" displayName="Asthma" codeSystem="ICD-9" codeSystemName="2.564.34343.222"/>
</root1>
<?xml version="1.0" encoding="UTF-8"?>
<root2>
<cd>
<code>24434</code>
<codeName>ICD-9</codeName>
<display>Asthma</display>
<codeSystem>2.564.34343.222</codeSystem>
</cd>
</root2>
Cd
package forum7043389;
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "cd", propOrder = {"originalText",})
public class Cd {
protected Object originalText;
@XmlAttribute(name = "code")
@XmlSchemaType(name = "anySimpleType")
protected String code;
@XmlAttribute(name = "displayName")
@XmlSchemaType(name = "anySimpleType")
protected String displayName;
@XmlAttribute(name = "codeSystem")
@XmlSchemaType(name = "anySimpleType")
protected String codeSystem;
@XmlAttribute(name = "codeSystemName")
@XmlSchemaType(name = "anySimpleType")
protected String codeSystemName;
@XmlAttribute(name = "nullFlavor")
protected NullFlavorType nullFlavor;
public Object getOriginalText() {
return originalText;
}
public void setOriginalText(Object originalText) {
this.originalText = originalText;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getCodeSystem() {
return codeSystem;
}
public void setCodeSystem(String codeSystem) {
this.codeSystem = codeSystem;
}
public String getCodeSystemName() {
return codeSystemName;
}
public void setCodeSystemName(String codeSystemName) {
this.codeSystemName = codeSystemName;
}
public NullFlavorType getNullFlavor() {
return nullFlavor;
}
public void setNullFlavor(NullFlavorType nullFlavor) {
this.nullFlavor = nullFlavor;
}
}
Root1
package forum7043389;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Root1 {
private Cd cd;
public Cd getCd() {
return cd;
}
public void setCd(Cd cd) {
this.cd = cd;
}
}
Root2
package forum7043389;
public class Root2 {
private Cd cd;
public Cd getCd() {
return cd;
}
public void setCd(Cd cd) {
this.cd = cd;
}
}
For More Information
- http://wiki.eclipse.org/EclipseLink/UserGuide/MOXy/Runtime/XML_Bindings
- http://blog.bdoughan.com/2010/12/extending-jaxb-representing-annotations.html
- http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
精彩评论