简体   繁体   中英

JAXB - Unmarshaller trying to instantiate an abstract class and failing to serialise to the correct class - ignoring @XmlSeeAlso

I've been struggling with an unmarshalling issue with JAXB and POJOs created from the below WSDL (using the jaxws-maven-plugin and wsimport):

<wsdl:definitions targetNamespace="urn://tsys.com/xmlmessaging/CH" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tsys="urn://tsys.com/xmlmessaging/CH" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
 <wsdl:types>
    <xsd:schema targetNamespace="urn://tsys.com/xmlmessaging/CH" xmlns:tsys="urn://tsys.com/xmlmessaging/CH" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn://tsys.com/xmlmessaging/CH" elementFormDefault="qualified" attributeFormDefault="unqualified">
       <xsd:complexType name="TSYSMsgType" abstract="true">
          <xsd:attribute name="reqID" use="optional">
             <xsd:simpleType>
                <xsd:restriction base="xsd:string">
                   <xsd:maxLength value="8"/>
                </xsd:restriction>
             </xsd:simpleType>
          </xsd:attribute>
       </xsd:complexType>
       <xsd:complexType name="TSYSRequestMsgType" abstract="true" mixed="false">
          <xsd:complexContent mixed="false">
             <xsd:extension base="TSYSMsgType"></xsd:extension>
          </xsd:complexContent>
       </xsd:complexType>
       <xsd:complexType name="TSYSResponseMsgType" abstract="true" mixed="false">
          <xsd:complexContent mixed="false">
             <xsd:extension base="TSYSMsgType">
                <xsd:attribute name="status" type="xsd:string" use="required"/>
                <xsd:attribute name="statusMsg" use="required">
                   <xsd:simpleType>
                      <xsd:restriction base="xsd:string">
                         <xsd:enumeration value="passed"/>
                         <xsd:enumeration value="failed"/>
                      </xsd:restriction>
                   </xsd:simpleType>
                </xsd:attribute>
                <xsd:attribute name="version" use="optional" type="xsd:token"/>
             </xsd:extension>
          </xsd:complexContent>
       </xsd:complexType>
       <xsd:complexType name="TSYSInquiryRequestType" abstract="true" mixed="false">
          <xsd:complexContent mixed="false">
             <xsd:extension base="TSYSRequestMsgType">
                <xsd:attribute name="pageToken" use="optional">
                   <xsd:simpleType>
                      <xsd:restriction base="xsd:string">
                         <xsd:minLength value="0"/>
                         <xsd:maxLength value="200"/>
                         <xsd:whiteSpace value="preserve"/>
                      </xsd:restriction>
                   </xsd:simpleType>
                </xsd:attribute>
                <xsd:attribute name="pageItems" use="optional">
                   <xsd:simpleType>
                      <xsd:restriction base="xsd:integer">
                         <xsd:minInclusive value="1"/>
                         <xsd:maxInclusive value="999"/>
                      </xsd:restriction>
                   </xsd:simpleType>
                </xsd:attribute>
             </xsd:extension>
          </xsd:complexContent>
       </xsd:complexType>
       <xsd:attributeGroup name="baseKeyGroup">
          <xsd:attribute name="key" type="xsd:token" use="optional"/>
          <xsd:attribute name="keyType" use="optional">
             <xsd:simpleType>
                <xsd:restriction base="xsd:token">
                   <xsd:enumeration value="cardNbr"/>
                   <xsd:enumeration value="acctID"/>
                </xsd:restriction>
             </xsd:simpleType>
          </xsd:attribute>
       </xsd:attributeGroup>
       <xsd:attributeGroup name="acctKeyGroup">
          <xsd:attribute name="key" type="xsd:token" use="optional"/>
          <xsd:attribute name="keyType" use="optional">
             <xsd:simpleType>
                <xsd:restriction base="xsd:token">
                   <xsd:enumeration value="cardNbr"/>
                   <xsd:enumeration value="acctID"/>
                </xsd:restriction>
             </xsd:simpleType>
          </xsd:attribute>
       </xsd:attributeGroup>
       <xsd:complexType name="TSYSAcctInquiryRequestType" abstract="true" mixed="false">
          <xsd:complexContent mixed="false">
             <xsd:extension base="TSYSInquiryRequestType">
                <xsd:attributeGroup ref="acctKeyGroup"/>
                <xsd:attribute name="cardNbr" type="xsd:token" use="optional"/>
                <xsd:attribute name="acctID" type="xsd:token" use="optional"/>
             </xsd:extension>
          </xsd:complexContent>
       </xsd:complexType>
       <xsd:complexType name="TSYSBaseInquiryRequestType" abstract="true" mixed="false">
          <xsd:complexContent mixed="false">
             <xsd:extension base="TSYSInquiryRequestType">
                <xsd:attributeGroup ref="baseKeyGroup"/>
             </xsd:extension>
          </xsd:complexContent>
       </xsd:complexType> 
       <xsd:complexType name="TSYSMultipleInquiryRequestType" mixed="false">
          <xsd:complexContent mixed="false">
             <xsd:extension base="TSYSRequestMsgType">
                <xsd:sequence>
                   <xsd:element name="inquireRequest" type="TSYSInquiryRequestType" minOccurs="0" maxOccurs="unbounded"/>
                </xsd:sequence>
                <xsd:attributeGroup ref="baseKeyGroup"/>
                <xsd:attribute name="cardNbr" type="xsd:token" use="optional"/>
                <xsd:attribute name="acctID" type="xsd:token" use="optional"/>
             </xsd:extension>
          </xsd:complexContent>
       </xsd:complexType>
      <xsd:complexType name="TSYSInquiryResponseType" abstract="true" mixed="false">
          <xsd:complexContent mixed="false">
             <xsd:extension base="TSYSResponseMsgType">
                <xsd:attribute name="restartToken" use="optional">
                   <xsd:simpleType>
                      <xsd:restriction base="xsd:string">
                         <xsd:minLength value="0"/>
                         <xsd:maxLength value="200"/>
                         <xsd:whiteSpace value="preserve"/>
                      </xsd:restriction>
                   </xsd:simpleType>
                </xsd:attribute>
             </xsd:extension>
          </xsd:complexContent>
       </xsd:complexType>
       <xsd:complexType name="TSYSAcctInquiryResponseType" abstract="true" mixed="false">
          <xsd:complexContent mixed="false">
             <xsd:extension base="TSYSInquiryResponseType">
                <xsd:attributeGroup ref="acctKeyGroup"/>
                <xsd:attribute name="cardNbr" type="xsd:token" use="optional"/>
                <xsd:attribute name="acctID" type="xsd:token" use="optional"/>
             </xsd:extension>
          </xsd:complexContent>
       </xsd:complexType>
       <xsd:complexType name="TSYSBaseInquiryResponseType" abstract="true" mixed="false">
          <xsd:complexContent mixed="false">
             <xsd:extension base="TSYSInquiryResponseType">
                <xsd:attributeGroup ref="baseKeyGroup"/>
             </xsd:extension>
          </xsd:complexContent>
       </xsd:complexType>
      
       <xsd:complexType name="TSYSMultipleInquiryResponseType" mixed="false">
          <xsd:complexContent mixed="false">
             <xsd:extension base="TSYSResponseMsgType">
                <xsd:sequence>
                   <xsd:element name="inquireResult" type="TSYSInquiryResponseType" minOccurs="0" maxOccurs="unbounded"/>
                </xsd:sequence>
                <xsd:attributeGroup ref="baseKeyGroup"/>
                <xsd:attribute name="cardNbr" type="xsd:token" use="optional"/>
                <xsd:attribute name="acctID" type="xsd:token" use="optional"/>
             </xsd:extension>
          </xsd:complexContent>
       </xsd:complexType>
       <xsd:element name="inqAcctStatus">
          <xsd:annotation id="inqAcctStatus">
          </xsd:annotation>
          <xsd:complexType>
             <xsd:sequence>
                <xsd:element ref="tsys:inqAcctStatusRequest"/>
             </xsd:sequence>
          </xsd:complexType>
       </xsd:element>
       <xsd:element name="inqAcctStatusResponse">
          <xsd:complexType>
             <xsd:sequence>
                <xsd:element ref="tsys:inqAcctStatusResult"/>
             </xsd:sequence>
          </xsd:complexType>
       </xsd:element>
       <xsd:complexType name="inqAcctStatusRequestType" mixed="false">
          <xsd:complexContent mixed="false">
             <xsd:extension base="tsys:TSYSAcctInquiryRequestType">
                <xsd:sequence>
                   <xsd:element name="acctNbrRef" minOccurs="0">
                      <xsd:annotation id="inqAcctStatus.inqAcctStatusRequest.acctNbrRef">
                         <xsd:documentation>Last four characters of the account number when account id is used as the key field in the request. This element is used to retrieve statuses from the account level segment.</xsd:documentation>
                      </xsd:annotation>
                      <xsd:simpleType>
                         <xsd:restriction base="xsd:integer">
                            <xsd:totalDigits value="4"/>
                         </xsd:restriction>
                      </xsd:simpleType>
                   </xsd:element>
                </xsd:sequence>
                <xsd:attribute name="statusReqCnt">
                   <xsd:annotation id="inqAcctStatus.inqAcctStatusRequest.statusReqCnt">
                      <xsd:documentation>Number of status codes that you are requesting.&lt;br>If you do not send a value in statusReqCnt, TSYS returns all status codes for the account. The maximum number returned is 200.</xsd:documentation>
                   </xsd:annotation>
                   <xsd:simpleType>
                      <xsd:restriction base="xsd:integer">
                         <xsd:totalDigits value="3"/>
                         <xsd:minInclusive value="1"/>
                         <xsd:maxInclusive value="200"/>
                      </xsd:restriction>
                   </xsd:simpleType>
                </xsd:attribute>
                <xsd:attribute name="version" use="required">
                   <xsd:simpleType>
                      <xsd:restriction base="xsd:token">
                         <xsd:enumeration value="1.2.0"/>
                      </xsd:restriction>
                   </xsd:simpleType>
                </xsd:attribute>
             </xsd:extension>
          </xsd:complexContent>
       </xsd:complexType>
       <xsd:complexType name="inqAcctStatusResponseType" mixed="false">
          <xsd:complexContent mixed="false">
             <xsd:extension base="tsys:TSYSAcctInquiryResponseType">
                <xsd:sequence>
                   <xsd:element name="statusCode" type="IASstatusCodeResponseDataType" minOccurs="0" maxOccurs="1" nillable="true"/>
                </xsd:sequence>
                <xsd:anyAttribute/>
             </xsd:extension>
          </xsd:complexContent>
       </xsd:complexType>
       <xsd:complexType name="IASstatusCodeResponseDataType">
          <xsd:sequence>
             <xsd:element name="status" minOccurs="0" maxOccurs="200" nillable="true">
                <xsd:annotation id="inqAcctStatus.inqAcctStatusResponse.statusCode.status">
                   <xsd:documentation>Container for status information.</xsd:documentation>
                </xsd:annotation>
                <xsd:complexType>
                   <xsd:sequence>
                      <xsd:element name="reason" nillable="true">
                         <xsd:annotation id="inqAcctStatus.inqAcctStatusResponse.statusCode.status.reason">
                            <xsd:documentation>Reason code that further defines the condition of the account.  &lt;br>See Account Status and Reason Codes in the TS2 Codes and Definitions manual.</xsd:documentation>
                         </xsd:annotation>
                         <xsd:simpleType>
                            <xsd:restriction base="xsd:token">
                               <xsd:minLength value="1"/>
                               <xsd:maxLength value="2"/>
                            </xsd:restriction>
                         </xsd:simpleType>
                      </xsd:element>
                      <xsd:element name="desc" minOccurs="0" nillable="true">
                         <xsd:annotation id="inqAcctStatus.inqAcctStatusResponse.statusCode.status.desc">
                            <xsd:documentation>Description of the reason for the account status. &lt;br>For example, if an account status is CL (Account closed), and the reason is IR, the description shows the meaning of IR (Closed Interest Rate).</xsd:documentation>
                         </xsd:annotation>
                         <xsd:simpleType>
                            <xsd:restriction base="xsd:token">
                               <xsd:minLength value="1"/>
                               <xsd:maxLength value="25"/>
                            </xsd:restriction>
                         </xsd:simpleType>
                      </xsd:element>
                      <xsd:element name="x_1.0.0" nillable="true" type="xsd:string"/>
                      <xsd:any minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
                   </xsd:sequence>
                   <xsd:attribute name="code">
                      <xsd:annotation id="inqAcctStatus.inqAcctStatusResponse.statusCode.status.code">
                         <xsd:documentation>Code for the condition of the account. &lt;br>See Account Status and Reason Codes in the TS2 Codes and Definitions manual.</xsd:documentation>
                      </xsd:annotation>
                      <xsd:simpleType>
                         <xsd:restriction base="xsd:token">
                            <xsd:length value="2"/>
                         </xsd:restriction>
                      </xsd:simpleType>
                   </xsd:attribute>
                   <xsd:anyAttribute/>
                </xsd:complexType>
             </xsd:element>
             <xsd:element name="x_1.0.0" nillable="true" type="xsd:string"/>
             <xsd:element name="digitalIssuanceInd" minOccurs="0" nillable="true">
                <xsd:simpleType>
                   <xsd:restriction base="xsd:token">
                      <xsd:enumeration value="DII not indicated"/>
                      <xsd:enumeration value="DII special processing"/>
                      <xsd:enumeration value="DII CRV Activated"/>
                      <xsd:enumeration value="NIL"/>
                   </xsd:restriction>
                </xsd:simpleType>
             </xsd:element>
             <xsd:element name="x_1.2.0" nillable="true" type="xsd:string"/>
             <xsd:any minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
          </xsd:sequence>
          <xsd:anyAttribute/>
       </xsd:complexType>
       
       <xsd:element name="inqAcctStatusRequest" type="inqAcctStatusRequestType" substitutionGroup="inquireRequest"/>
       <xsd:element name="inqAcctStatusResult" type="inqAcctStatusResponseType" substitutionGroup="inquireResponse"/>

       <xsd:element name="inqMulti">
          <xsd:complexType>
             <xsd:sequence>
                <xsd:element name="inqMultiRequest" type="tsys:TSYSMultipleInquiryRequestType" minOccurs="0"/>
             </xsd:sequence>
          </xsd:complexType>
       </xsd:element>
       <xsd:element name="inqMultiResponse">
          <xsd:complexType>
             <xsd:sequence>
                <xsd:element name="inqMultiResult" type="tsys:TSYSMultipleInquiryResponseType" minOccurs="0"/>
             </xsd:sequence>
          </xsd:complexType>
       </xsd:element>
       <xsd:element name="inquireRequest" type="tsys:TSYSInquiryRequestType"/>
       <xsd:element name="inquireResponse" type="tsys:TSYSInquiryResponseType" nillable="true"/>

       <xsd:complexType name="currency">
          <xsd:simpleContent>
             <xsd:extension base="xsd:decimal">
                <xsd:attribute name="code" use="required">
                   <xsd:simpleType>
                      <xsd:restriction base="xsd:token">
                         <xsd:length value="3"/>
                      </xsd:restriction>
                   </xsd:simpleType>
                </xsd:attribute>
             </xsd:extension>
          </xsd:simpleContent>
       </xsd:complexType>
       <xsd:simpleType name="phoneNumber">
          <xsd:restriction base="xsd:string"/>
       </xsd:simpleType>
       <xsd:complexType name="base64Binary">
          <xsd:simpleContent>
             <xsd:extension base="xsd:base64Binary">
                <xsd:attribute name="checksum">
                   <xsd:simpleType>
                      <xsd:restriction base="xsd:token">
                         <xsd:length value="8"/>
                      </xsd:restriction>
                   </xsd:simpleType>
                </xsd:attribute>
             </xsd:extension>
          </xsd:simpleContent>
       </xsd:complexType>
       <xsd:complexType name="charLargeObj">
          <xsd:simpleContent>
             <xsd:extension base="xsd:string">
                <xsd:attribute name="checksum">
                   <xsd:simpleType>
                      <xsd:restriction base="xsd:token">
                         <xsd:length value="8"/>
                      </xsd:restriction>
                   </xsd:simpleType>
                </xsd:attribute>
             </xsd:extension>
          </xsd:simpleContent>
       </xsd:complexType>
        <xsd:simpleType name="TSYScustID">
          <xsd:restriction base="xsd:token">
             <xsd:length value="9"/>
             <xsd:pattern value="\d+"/>
          </xsd:restriction>
       </xsd:simpleType>
    </xsd:schema>
 </wsdl:types>
 <wsdl:message name="soapTSYSprofileInq">
    <wsdl:part element="tsys:TSYSprofileInq" name="TSYSprofile"/>
 </wsdl:message>

 <wsdl:message name="inqMultiSoapIn">
    <wsdl:part element="tsys:inqMulti" name="parameters"/>
 </wsdl:message>
 <wsdl:message name="inqMultiSoapOut">
    <wsdl:part element="tsys:inqMultiResponse" name="parameters"/>
 </wsdl:message>

 <wsdl:portType name="TSYSXMLMessagingSoapInquiry">
    <wsdl:operation name="inqMulti">
       <wsdl:input message="tsys:inqMultiSoapIn"/>
       <wsdl:output message="tsys:inqMultiSoapOut"/>
    </wsdl:operation>
</wsdl:portType>
 <wsdl:binding name="TSYSXMLMessagingSoapInquiry" type="tsys:TSYSXMLMessagingSoapInquiry">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="inqMulti">
       <soap:operation soapAction="urn://tsys.com/xmlmessaging/CH/inqMulti" style="document"/>
       <wsdl:input>
          <soap:header message="tsys:soapTSYSprofileInq" part="TSYSprofile" use="literal"/>
          <soap:body use="literal"/>
       </wsdl:input>
       <wsdl:output>
          <soap:header message="tsys:soapTSYSprofileInq" part="TSYSprofile" use="literal"/>
          <soap:body use="literal"/>
       </wsdl:output>
    </wsdl:operation>
 </wsdl:binding>
 <wsdl:service name="TSYSXMLMessagingInquiry">
    <wsdl:port binding="tsys:TSYSXMLMessagingSoapInquiry" name="TSYSXMLMessagingSoapInquiry05">
       <soap:address location="HTTP://YOUR.URL.HERE"/>
    </wsdl:port>
    <wsdl:port binding="tsys:TSYSXMLMessagingSoapInquiry" name="TSYSXMLMessagingSoapInquiry06">
       <soap:address location="HTTP://YOUR.URL.HERE"/>
    </wsdl:port>
 </wsdl:service>
</wsdl:definitions>

The Java classes generated by wsimport:

TSYSInquiryResponseType

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "TSYSInquiryResponseType")
@XmlSeeAlso({
    TSYSAcctInquiryResponseType.class,
    TSYSBaseInquiryResponseType.class,
    TSYSCustomerInquiryResponseType.class
})
public  class TSYSInquiryResponseType
    extends TSYSResponseMsgType
{
    @XmlAttribute(name = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
    private String xsiType;

    @XmlAttribute(name = "restartToken")
    protected String restartToken;

    /**
     * Gets the value of the restartToken property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getRestartToken() {
        return restartToken;
    }

    /**
     * Sets the value of the restartToken property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setRestartToken(String value) {
        this.restartToken = value;
    }

    public String getXsiType() {
        return xsiType;
    }

    public void setXsiType(String xsiType) {
        this.xsiType = xsiType;
    }
}

InqAcctStatusResponseType

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "TSYSAcctInquiryResponseType")
@XmlSeeAlso({
    InqAcctStatusResponseType.class
})
public abstract class TSYSAcctInquiryResponseType
    extends TSYSInquiryResponseType
{

    @XmlAttribute(name = "cardNbr")
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
    @XmlSchemaType(name = "token")
    protected String cardNbr;
    @XmlAttribute(name = "acctID")
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
    @XmlSchemaType(name = "token")
    protected String acctID;

    /**
     * Gets the value of the cardNbr property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getCardNbr() {
        return cardNbr;
    }

    /**
     * Sets the value of the cardNbr property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setCardNbr(String value) {
        this.cardNbr = value;
    }

    /**
     * Gets the value of the acctID property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getAcctID() {
        return acctID;
    }

    /**
     * Sets the value of the acctID property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setAcctID(String value) {
        this.acctID = value;
    }
}

InqAcctStatusResponseType

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "inqAcctStatusResponseType", propOrder = {
    "statusCode"
})
public class InqAcctStatusResponseType
    extends TSYSAcctInquiryResponseType
{

    @XmlElementRef(name = "statusCode", namespace = "urn://tsys.com/xmlmessaging/CH", type = JAXBElement.class, required = false)
    protected JAXBElement<IASstatusCodeResponseDataType> statusCode;
    @XmlAnyAttribute
    private Map<QName, String> otherAttributes = new HashMap<QName, String>();

    /**
     * Gets the value of the statusCode property.
     * 
     * @return
     *     possible object is
     *     {@link JAXBElement }{@code <}{@link IASstatusCodeResponseDataType }{@code >}
     *     
     */
    public JAXBElement<IASstatusCodeResponseDataType> getStatusCode() {
        return statusCode;
    }

    /**
     * Sets the value of the statusCode property.
     * 
     * @param value
     *     allowed object is
     *     {@link JAXBElement }{@code <}{@link IASstatusCodeResponseDataType }{@code >}
     *     
     */
    public void setStatusCode(JAXBElement<IASstatusCodeResponseDataType> value) {
        this.statusCode = value;
    }

    /**
     * Gets a map that contains attributes that aren't bound to any typed property on this class.
     * 
     * <p>
     * the map is keyed by the name of the attribute and 
     * the value is the string value of the attribute.
     * 
     * the map returned by this method is live, and you can add new attribute
     * by updating the map directly. Because of this design, there's no setter.
     * 
     * 
     * @return
     *     always non-null
     */
    public Map<QName, String> getOtherAttributes() {
        return otherAttributes;
    }

}

So you can see that the abstract TSYSInquiryResponseType contains an @XmlSeeAlso linking it to another abstract TSYSAcctInquiryResponseType class, which in turn @XmlSeeAlso links to the concrete InqAcctStatusResponseType class - which in turn has the @XmlType tag.

It's my understanding that the combination of this inheritance and context loading should enable the unmarshaller to process the below SOAP message and create the correct inqAcctStatusResponseType class; however, I'm getting an InstantiationException - as the unmarshaller is trying to instantiate the abstract TSYSInquiryResponseType .

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn://tsys.com/xmlmessaging/CH">
   <soap:Header>
      <TSYSprofileInq xsi:type="TSYSprofileType">
         <clientID>8571</clientID>
         <userID>MOBAPP</userID>
         <vendorID>00000000</vendorID>
         <securityID>8571</securityID>
         <logID>MOBAPP</logID>
         <TSYSInfo>CIC1VS0P-MQP0</TSYSInfo>
      </TSYSprofileInq>
   </soap:Header>
   <soap:Body>
      <inqMultiResponse>
         <inqMultiResult status="000" statusMsg="passed" acctID="00000096432" key="5276690020709766" keyType="cardNbr">
            <inquireResult xsi:type="inqAcctStatusResponseType" status="000" statusMsg="passed" key="5276690020709766" keyType="cardNbr" version="1.2.0">
               <statusCode>
                  <status code="IN">
                     <reason>C</reason>
                     <desc>INACTIVE SINCE OPEN</desc>
                     <x_1.0.0/>
                  </status>
                  <status code="DC">
                     <reason>Q1</reason>
                     <desc>FIXED REPAYMENT PROGRAM</desc>
                     <x_1.0.0/>
                  </status>
                  <status code="FU">
                     <reason>PU</reason>
                     <desc>FIRST USE WAS PURCHASE</desc>
                     <x_1.0.0/>
                  </status>
                  <status code="TA">
                     <reason>P</reason>
                     <desc>PERSONAL TYPE ACCOUNT</desc>
                     <x_1.0.0/>
                  </status>
                  <status code="YT">
                     <reason>Y</reason>
                     <desc>ACCOUNT CYCLED TODAY</desc>
                     <x_1.0.0/>
                  </status>
                  <x_1.0.0/>
                  <digitalIssuanceInd>DII not indicated</digitalIssuanceInd>
                  <x_1.2.0/>
               </statusCode>
            </inquireResult>
         </inqMultiResult>
      </inqMultiResponse>
   </soap:Body>
</soap:Envelope>

2022-06-10 09:58:07.816 ERROR 3604 --- [o-auto-1-exec-2] cvpswTsysWebClient : Exception caught whilst retrieving Inquiry for AccountId: 00000097686, Exception: org.springframework.oxm.UnmarshallingFailureException: JAXB unmarshalling exception; nested exception is javax.xml.bind.UnmarshalException: Unable to create an instance of com.virginmoney.tsys.ws.client.generated.TSYSInquiryResponseType with linked exception: [java.lang.InstantiationException]

I had a search and found similar issues being described: JAXB: Unmarshaller tries to instantiate abstract class (ignoring xsi:type)

InstantiationException during JAXB Unmarshalling (abstract base class, with @XmlSeeAlso concrete sub class)

None of the suggestions seem to have made a difference. I'm using Java11 and spring-boot-starter-parent v2.6.0

Does anyone have any ideas please? I feel like I'm going a bit code blind.

Thanks in advance.

UPDATE - SOLUTION Manipulating the SOAP response to inject namespaces resulted in the unmarshaller working as expected

StreamResult result = new StreamResult(bytArrayOutputStream);
    getWebServiceTemplate().sendSourceAndReceiveToResult(marshall(inqMulti), webServiceMessage -> {
        try {
            SoapHeader soapHeader = ((SoapMessage) webServiceMessage).getSoapHeader();

            // create the header element
            ObjectFactory factory = new ObjectFactory();
            TSYSprofileType inqAcctStatusSoapHeader =
                    factory.createTSYSprofileType();
            inqAcctStatusSoapHeader.setClientID(profileHeaderClientId);
            inqAcctStatusSoapHeader.setUserID(profileHeaderUserId);
            inqAcctStatusSoapHeader.setVendorID(profileHeaderVendorId);

            JAXBElement<TSYSprofileType> headers =
                    factory.createTSYSprofileInq(inqAcctStatusSoapHeader);

            // create a marshaller
            JAXBContext context = JAXBContext.newInstance(TSYSprofileType.class);
            Marshaller marshaller = context.createMarshaller();

            // marshal the headers into the specified result
            marshaller.marshal(headers, soapHeader.getResult());
        } catch (JAXBException e) {
            logger.error("Exception caught whilst activation for AccountId: {}, Exception: {}", accountId, e);
        }
    }, result);

    String inqMultiResponseString = new String(bytArrayOutputStream.toByteArray());
    inqMultiResponseString = inqMultiResponseString.replaceAll("<inqMultiResponse xmlns=\"urn://tsys.com/xmlmessaging/CH\">", "<inqMultiResponse xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:tsys=\"urn://tsys.com/xmlmessaging/CH\">");
    inqMultiResponseString = inqMultiResponseString.replaceAll("</", "</tsys:");
    inqMultiResponseString = inqMultiResponseString.replaceAll("<(?!/)", "<tsys:");
    inqMultiResponseString = inqMultiResponseString.replaceFirst("<tsys:", "<"); //fixing the <xml version> tag
    inqMultiResponseString = inqMultiResponseString.replaceAll("xsi:type=\"", "xsi:type=\"tsys:");

I managed to resolve my issue - it turns out the SOAP response I was receiving was lacking the expected namespace declarations. Adding these in (via some string manipulation) allowed the unmarshaller to work as expected

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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