문제

I have a class which contains an ArrayList(SuperClass) property. Now I wish to unmarshall the following XML file which contains different element names in that collection because these are subclasses of the Superclass. Is there a way of doing this with Moxy?

<?xml version="1.0" encoding="UTF-8"?>
<SmMessageSet xmlns:nav="urn:ccsds:recommendation:navigation:schema:ndmxml:R1.5"
    xmlns="urn:ccsds:recommendation:service_management:schema:sccs:R1.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:ccsds:recommendation:service_management:schema:sccs:R1.0 file:/C:/CCSDS-910.11-B-1_XML_schemas/CCSDS-910.11-B-1_XML_schemas/SmSchema-v1.0.0.xsd">
    <sccsSmVersionRef>sccsSmVersionRef0</sccsSmVersionRef>
    <smSource>smSource0</smSource>
    <smDestination>smDestination0</smDestination>
    <serviceAgreementRef>serviceAgreementRef0</serviceAgreementRef>
    <smMessages>
        <querySpaceCommunicationServiceProfileFailedReturn>
            <messageSequenceNumber>50</messageSequenceNumber>
            <messageTimestamp>2006-05-04T18:13:51.0</messageTimestamp>
            <invocationMessageSequenceNumber>50</invocationMessageSequenceNumber>
            <spaceCommunicationServiceProfileRef>spaceCommunicationServiceProfileRef0
            </spaceCommunicationServiceProfileRef>
            <qscspError>
                <erroredItem>erroredItem0</erroredItem>
                <diagnostic>operation timeout</diagnostic>
            </qscspError>
            <qscspError>
                <erroredItem>erroredItem1</erroredItem>
                <diagnostic>operation timeout</diagnostic>
            </qscspError>
        </querySpaceCommunicationServiceProfileFailedReturn>
        <createUserAccountInvocation1>
            <messageSequenceNumber>50</messageSequenceNumber>
            <messageTimestamp>2006-05-04T18:13:51.0</messageTimestamp>
            <username>createdUser</username>
            <password>createdPassword</password>
            <firstname>Test</firstname>
            <lastname>User</lastname>
            <email>test.user@host.de</email>
            <role>SCHEDULING_OFFICER</role>
            <superuser>0</superuser>
        </createUserAccountInvocation1>
    </smMessages>
</SmMessageSet>

The querySpaceCommunicationServiceProfileFailedReturn and createUserAccountInvocation are in my java object model subclasses of SmMessage base class, which is held by the SmMessageSet class in an, as above described, ArrayList of SmMessage classes.

I would also like to not change the current XML structure (i.e. create a wrapper element around the SmMessages in the XML file).

Any help would be appreciated :)

도움이 되었습니까?

해결책

You could do the following leveraging @XmlElementWrapper and @XmlElementRef:

Java Model

SmMessageSet

You can use the @XmlElementWrapper annotation to add a grouping element around the collection (see: http://blog.bdoughan.com/2010/09/jaxb-collection-properties.html). You can also use the @XmlElementRef annotation to model the element name as the inheritance indicator (substitution groups in XML Schema, see: http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-substitution.html).

package forum20745762;

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlRootElement(name="SmMessageSet")
@XmlAccessorType(XmlAccessType.FIELD)
public class SmMessageSet {

    @XmlElementWrapper
    @XmlElementRef
    private List<SmMessage> smMessages;

}

SmMessage

JAXB/MOXy won't automatically pull in all subclasses of a class, so you can use the @XmlSeeAlso annotation to have them pulled in.

package forum20745762;

import javax.xml.bind.annotation.XmlSeeAlso;

@XmlSeeAlso({CreateUserAccountInvocation.class, QuerySpaceCommunicationServiceProfileFailedReturn1.class})
public class SmMessage {

}

CreateUserAccountInvocation

One each of the subclasses you need to annotate with @XmlRootElement. This is the element name that the @XmlElementRef annotation will match on.

package forum20745762;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class CreateUserAccountInvocation extends SmMessage {

}

QuerySpaceCommunicationServiceProfileFailedReturn1

package forum20745762;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class QuerySpaceCommunicationServiceProfileFailedReturn1 extends SmMessage {

}

package-info

We will use the package level @XmlSchema annotation to map the namespaces (see: http://blog.bdoughan.com/2010/08/jaxb-namespaces.html).

@XmlSchema(
    namespace="urn:ccsds:recommendation:service_management:schema:sccs:R1.0",
    elementFormDefault=XmlNsForm.QUALIFIED
)
package forum20745762;

import javax.xml.bind.annotation.*;

Demo Code

Demo

The following demo code will read the XML from your question, and then write it back out.

package forum20745762;

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(SmMessageSet.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum20745762/input.xml");
        SmMessageSet smMessageSet = (SmMessageSet) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(smMessageSet, System.out);
    }

}

Output

The output below corresponds to just the subset of your XML document that I had mapped to:

<?xml version="1.0" encoding="UTF-8"?>
<SmMessageSet xmlns="urn:ccsds:recommendation:service_management:schema:sccs:R1.0">
   <smMessages>
      <querySpaceCommunicationServiceProfileFailedReturn1/>
      <createUserAccountInvocation/>
   </smMessages>
</SmMessageSet>
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top