JAXB编组多态POJO到XML

时间:2018-10-04 05:08:52

标签: java jaxb

我正在尝试使用JAXB封送类文件(带有批注)。在<profile-set>下,它可以具有不同的标签,例如

<organization-information-profile>
<connection-profile>
<user-information-profile>

示例输出XML文件如下

a)

    <?xml version="1.0"?>
    <request version="2.0" principal="111" credentials="xxxxx">
      <target name="TestAPI" operation="create">
        <parameter>
          <organization>
            <qualified-name>some-qualified-name</qualified-name>
            <profile-set>
              <name>TestOrg</name>
              <organization-information-profile>
                <name>Organization Information</name>
                <qualified-name>/Organization Information</qualified-name>
                <last-name>Test</last-name>
                <address>some-address</address>
                <city>my-city</city>
                <province></province>
                <postal-code>1111</postal-code>
                <country>Timbaktu</country>
                <phone-number-day>1111</phone-number-day>
                <email-address>some@email.com</email-address>
                <attribute name="PhoneNumber1">
                  <value context="organization">23333</value>
                </attribute>
                <attribute name="ShortName">
                  <value context="organization">my company</value>
                </attribute>
                <attribute name="TaxId">
                  <value context="organization">myorg</value>
                </attribute>
              </organization-information-profile>
            </profile-set>
          </organization>
        </parameter>
      </target>
</request>

b)

        <?xml version="1.0"?>
        <request version="2.0" principal="11111" credentials="xxxxx">
          <target name="TestAPI" operation="update">
            <parameter>
              <organization>
                <qualified-name>some-qualified-name</qualified-name>
                <profile-set>
                  <name>TestOrg</name>
                  <connection-profile>
                    <qualified-name>some-qualified-name</qualified-name> 
                    <service>
                      <name>some service</name> 
                    </service>
                    <attribute name="att-1">
                      <value context="organization" segment="some-segment" subscript="524288">fill-the-value</value> 
                    </attribute>
                    <attribute name="att-2">
                      <value context="organization" segment="some-segment" subscript="524288">qedqwe</value> 
                    </attribute>            
                  </connection-profile>
                </profile-set>
              </organization>
            </parameter>
          </target>
        </request> 

下面是代码(仅配置文件集)

 public static class ProfileSet
    {
        @XmlElement(name = "name")
        public String name;

        // innerPayLoad is template to store different profile objects
        @XmlJavaTypeAdapter(CustomAdaptor.class)
        @XmlElement
        public InnerPayLoad innerPayLoad;

        public ProfileSet(String name, InnerPayLoad innerPayLoad)
        {
            this.name = name;
            this.innerPayLoad = innerPayLoad;
        }

    }

和CustomAdaptor

public class CustomAdaptor extends XmlAdapter<String,InnerPayLoad<?>>
{


    @Override
    public InnerPayLoad<?> unmarshal(String v) throws Exception
    {
        return null;
    }

    @Override
    public String marshal(InnerPayLoad<?> v) throws Exception
    {
         String value = TestCode.convertToXmlNoHeader(v.whichProfile,v.whichProfile.getClass());

         // after converting value becomes 

        //  <organization-information-profile>
        //      <name>Organization Information</name>
        //  </organization-information-profile> 

        return value;
    }
}       

但是最终生成的XML与organization-information-profile

的(a)不同
 <?xml version='1.0' encoding='UTF-8'?>
<request version="2.0" principle="11111" credentials="xxxxx">
  <target name="TestAPI" operation="create">
    <parameter>
      <organization>
        <qualified-name>newOrg</qualified-name>
        <profile-set>
          <innerPayLoad>&lt;organization-information-profile>
    &lt;name>Organization Information&lt;/name>
&lt;/organization-information-profile></innerPayLoad>
          <name>testOrg</name>
        </profile-set>
      </organization>
    </parameter>
  </target>
</request>

是否可以删除<innerPayLoad>标签并仅使用CustomAdaptor元帅函数返回值插入?

感谢帮助和提示来解决此问题。

1 个答案:

答案 0 :(得分:1)

您无需为ProfileSet中的各种配置文件类型编写自定义适配器。

相反,要处理这种混合的XML内容,规范方法是这样的。

在您的ProfileSet类中,您应该定义一个多态Java属性profile 可以接受<organization.information-profile>的内容, <connection-profile><user-information-profile>元素。 (我更喜欢在这里使用名称profile而不是innerPayload)。 这些XML元素名称和Java类之间的映射已完成 通过使用@XmlElements注释。

@XmlAccessorType(XmlAccessType.FIELD)
public class ProfileSet {

    @XmlElement(name = "name")
    private String name;

    // template to store different profile objects    
    @XmlElements({
        @XmlElement(name = "organization-information-profile", type = OrganizationInfomationProfile.class),
        @XmlElement(name = "connection-profile", type = ConnectionProfile.class),
        @XmlElement(name = "user-information-profile", type = UserInformationProfile.class)
    })
    private Profile profile;

    // default constructor used by JAXB unmarshaller
    public ProfileSet() {
    }

    public ProfileSet(String name, Profile profile) {
        this.name = name;
        this.profile = profile;
    }
 }

您需要一个抽象的超类Profile,其中仅包含各种配置文件共有的属性:

@XmlAccessorType(XmlAccessType.FIELD)
public abstract class Profile {

    @XmlElement
    private String name;

    @XmlElement(name = "attribute")
    private List<Attribute> attributes;
}

您有一个子类OrganizationInformationProfile代表 <organization-information-profile>元素

@XmlAccessorType(XmlAccessType.FIELD)
public class OrganizationInfomationProfile extends Profile {

    @XmlElement(name = "qualified-name")
    private String qualifiedName;

    @XmlElement(name = "last-name")
    private String lastName;

    @XmlElement(name = "address")
    private String address;

    // ... other properties

}

和另一个代表ConnectionProfile元素的子类<connection-profile>

@XmlAccessorType(XmlAccessType.FIELD)
public class ConnectionProfile extends Profile {

    @XmlElement(name = "service")
    private Service service;
}

和另一个子类UserInformationProfile,用于表示<user-information-profile>元素。

通过使用以上方法,您可以解组XML示例 并在编组时再次获得相同的输出。