开发者

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜