简体   繁体   English

JAXB 将多态 POJO 编组为 XML

[英]JAXB marshal polymorphic POJO to XML

I am trying to use JAXB to marshal class file(with annotations).我正在尝试使用 JAXB 来封送类文件(带注释)。 Under <profile-set> it can have different tags for eg<profile-set>它可以有不同的标签,例如

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

Sample output XML files are as below示例输出 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) 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> 

Below is the code (only profile-set)下面是代码(仅配置文件集)

 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;
        }

    }

And 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;
    }
}       

But the final XML produced is not similar to (a) for organization-information-profile但最终生成的 XML 与 (a) for organization-information-profile

 <?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>

Is it possible to remove <innerPayLoad> tag and just insert with CustomAdaptor marshal function return value?是否可以删除<innerPayLoad>标记并仅插入 CustomAdaptor marshal 函数返回值?

Appreciate help and hints to solve this issue.感谢帮助和提示来解决这个问题。

You don't need to write a custom adapter for the various profile types within your ProfileSet .您不需要为ProfileSet的各种配置文件类型编写自定义适配器。

Instead, to handle such mixed XML Content the canonical approach goes like this.相反,为了处理这种混合的 XML 内容,规范的方法是这样的。

In your ProfileSet class you should define a polymorphic Java property profile which can take the contents of a <organization.information-profile> , <connection-profile> or <user-information-profile> element.在您的ProfileSet类中,您应该定义一个多态 Java 属性profile ,它可以采用<organization.information-profile><connection-profile><user-information-profile>元素的内容。 (I preferred the name profile here instead of innerPayload ). (我更喜欢这里的名称profile而不是innerPayload )。 The mapping between these XML element names and Java classes is done by using the @XmlElements annotation.这些 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;
    }
 }

You need an abstract super-class Profile containing only the properties common to all kinds of profiles:您需要一个抽象的超类Profile ,它只包含所有类型的Profile共有的属性:

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

    @XmlElement
    private String name;

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

You have one subclass OrganizationInformationProfile for representing the <organization-information-profile> element您有一个子类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

}

and another subclass ConnectionProfile for representing the <connection-profile> element和另一个用于表示<connection-profile>元素的子类ConnectionProfile

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

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

and yet another subclass UserInformationProfile for representing the <user-information-profile> element.以及另一个用于表示<user-information-profile>元素的子类UserInformationProfile

By using the above approach you can unmarshal your XML examples and get the same output again when marshalling.通过使用上述方法,您可以解组 XML 示例并在编组时再次获得相同的输出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM