JAXB маршал полиморфный POJO в XML - PullRequest
0 голосов
/ 04 октября 2018

Я пытаюсь использовать 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 не похож на (a) для 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>

Можно ли удалить тег <innerPayLoad> и просто вставить с помощью функции маршала CustomAdaptorзначение?

Оцените помощь и советы по решению этой проблемы.

1 Ответ

0 голосов
/ 04 октября 2018

Вам не нужно писать собственный адаптер для различных типов профилей в вашем 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>element

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

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

и еще один подкласс UserInformationProfile для представления элемента <user-information-profile>.

Используя вышеупомянутый подход, вы можете разархивировать ваши примеры XML и снова получить тот же вывод при маршалинге,

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...