paramName という名前の抽象グローバル要素を含む WSDL を次に示します。
<wsdl:definitions name="AdapterSessionManagerService" targetNamespace="http://companyname.org/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:tns="http://companyname.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:types>
<xs:schema elementFormDefault="unqualified" targetNamespace="http://companyname.org/" version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<import namespace="http://companyname.org/adapter1/" schemaLocation="http://localhost:8081/adapters/AdapterSessionManager?xsd=adapter1/ElementName.xsd"/>
<import namespace="http://companyname.org/adapter2/" schemaLocation="http://localhost:8081/adapters/AdapterSessionManager?xsd=adapter2/ElementName.xsd"/>
<xs:element name="initAdapterSession" type="tns:initAdapterSession"/>
<xs:element name="initAdapterSessionResponse" type="tns:initAdapterSessionResponse"/>
<xs:complexType name="initAdapterSession">
<xs:sequence>
<xs:element name="adapterId" type="xs:long"/>
<xs:element name="callbackURL" type="xs:anyURI"/>
<xs:element name="adapterInputData" type="tns:AdapterInputDataType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="initAdapterSessionResponse">
<xs:sequence>
<xs:element minOccurs="0" name="return" type="xs:long"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="AdapterInputDataType">
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="atomicParam" type="tns:AtomicParamType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="AtomicParamType">
<xs:sequence>
<xs:element maxOccurs="1" minOccurs="1" ref="tns:paramName"/>
<xs:element maxOccurs="1" minOccurs="1" name="paramValue" type="tns:AtomicParamValueType"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="AtomicParamValueType">
<xs:union memberTypes="xs:string xs:long xs:decimal xs:dateTime xs:boolean"/>
</xs:simpleType>
<xs:element abstract="true" name="paramName" type="xs:string"/>
</xs:schema>
</wsdl:types>
<wsdl:message name="initAdapterSessionResponse">
<wsdl:part element="tns:initAdapterSessionResponse" name="parameters"/>
</wsdl:message>
<wsdl:message name="initAdapterSession">
<wsdl:part element="tns:initAdapterSession" name="parameters"/>
</wsdl:message>
<wsdl:portType name="AdapterSessionManager">
<wsdl:operation name="initAdapterSession">
<wsdl:input message="tns:initAdapterSession" name="initAdapterSession"/>
<wsdl:output message="tns:initAdapterSessionResponse" name="initAdapterSessionResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="AdapterSessionManagerServiceSoapBinding" type="tns:AdapterSessionManager">
<soap12:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="initAdapterSession">
<soap12:operation soapAction="" style="document"/>
<wsdl:input name="initAdapterSession">
<soap12:body use="literal"/>
</wsdl:input>
<wsdl:output name="initAdapterSessionResponse">
<soap12:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="AdapterSessionManagerService">
<wsdl:port binding="tns:AdapterSessionManagerServiceSoapBinding" name="AdapterSessionManagerPort">
<soap12:address location="http://localhost:8081/adapters/AdapterSessionManager"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
この要素は、別の名前空間で定義された同じ名前の要素を持つ SOAP メッセージで代用されることを意図しています。以下は、そのような定義の例です。
<schema targetNamespace="http://companyname.org/adapter1/" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:inptypns="http://companyname.org/" xmlns:tns="http://companyname.org/adapter1/">
<import namespace="http://companyname.org/"/>
<element name="paramName" substitutionGroup="inptypns:paramName" type="tns:AtomicParamNameType"/>
<simpleType name="AtomicParamNameType">
<restriction base="string">
<enumeration value="foo"/>
<enumeration value="bar"/>
</restriction>
</simpleType>
</schema>
以下は、wsimport によって生成されたコードを含む、この Web サービスを実装する Java コードです。
@WebService(wsdlLocation = "WEB-INF/wsdl/AdapterSessionManager.wsdl")
@BindingType(SOAPBinding.SOAP12HTTP_BINDING)
public class AdapterSessionManager {
@WebMethod
public Long initAdapterSession(
@WebParam(name = "adapterId")
@XmlElement(required = true)
Long adapterId,
@WebParam(name = "callbackURL")
@XmlElement(required = true)
URL callbackURL,
@WebParam
@XmlElement(required = true)
AdapterInputDataType adapterInputData
) {...}
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "AdapterInputDataType", propOrder = {
"atomicParam"
})
public class AdapterInputDataType {
protected List<AtomicParamType> atomicParam;
public List<AtomicParamType> getAtomicParam() {
if (atomicParam == null) {
atomicParam = new ArrayList<AtomicParamType>();
}
return this.atomicParam;
}
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "AtomicParamType", propOrder = {
"paramName",
"paramValue"
})
public class AtomicParamType {
@XmlElementRef(name = "paramName", namespace = "http://companyname.org/", type = JAXBElement.class)
protected JAXBElement<?> paramName;
@XmlElement(required = true)
protected String paramValue;
public JAXBElement<?> getParamName() {
return paramName;
}
public void setParamName(JAXBElement<?> value) {
this.paramName = value;
}
public String getParamValue() {
return paramValue;
}
public void setParamValue(String value) {
this.paramValue = value;
}
}
@XmlRegistry
public class ObjectFactory {
private final static QName _ParamName_QNAME = new QName("http://companyname.org/", "paramName");
public ObjectFactory() {
}
public AtomicParamType createAtomicParamType() {
return new AtomicParamType();
}
public AdapterInputDataType createAdapterInputDataType() {
return new AdapterInputDataType();
}
@XmlElementDecl(namespace = "http://companyname.org/", name = "paramName")
public JAXBElement<String> createParamName(String value) {
return new JAXBElement<String>(_ParamName_QNAME, String.class, null, value);
}
}
@XmlType(name = "AtomicParamNameType", namespace = "http://companyname.org/adapter1/")
@XmlEnum
public enum AtomicParamNameType {
@XmlEnumValue("foo")
FOO("foo"),
@XmlEnumValue("bar")
BAR("bar");
private final String value;
AtomicParamNameType(String v) {
value = v;
}
public String value() {
return value;
}
public static AtomicParamNameType fromValue(String v) {
for (AtomicParamNameType c: AtomicParamNameType.values()) {
if (c.value.equals(v)) {
return c;
}
}
throw new IllegalArgumentException(v);
}
}
@XmlRegistry
public class ObjectFactory {
private final static QName _ParamName_QNAME = new QName("http://companyname.org/adapter1/", "paramName");
public ObjectFactory() {
}
@XmlElementDecl(namespace = "http://companyname.org/adapter1/", name = "paramName", substitutionHeadNamespace = "http://companyname.org/", substitutionHeadName = "paramName")
public JAXBElement<AtomicParamNameType> createParamName(AtomicParamNameType value) {
return new JAXBElement<AtomicParamNameType>(_ParamName_QNAME, AtomicParamNameType.class, null, value);
}
}
次の SOAP リクエストでサービスをテストしています。
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://companyname.org/" xmlns:ans="http://companyname.org/adapter1/">
<soapenv:Header/>
<soapenv:Body>
<ws:initAdapterSession>
<adapterId>123</adapterId>
<callbackURL>http://callback</callbackURL>
<adapterInputData>
<atomicParam>
<ans:paramName>foo</ans:paramName>
<paramValue>hello</paramValue>
</atomicParam>
</adapterInputData>
</ws:initAdapterSession>
</soapenv:Body>
</soapenv:Envelope>
アプリケーション サーバーがリクエストを受信すると、次の UnmarshallException が発生します。
javax.xml.bind.UnmarshalException: 予期しない要素 (uri:" http://companyname.org/adapter1/ "、local:"paramName")。期待される要素は <{ http://companyname.org/ }paramName>,<{}paramValue> です
JAXB は、http://companyname.org/adapter1/
名前空間で定義された paramName 置換を認識していないようです。しかし、なぜ JAXB がそのような振る舞いをするのか、私には想像できません。私の間違いはどこですか?何か案は?