SOAP WS-сделать @WebParam необязательным

у меня есть довольно простой метод, который я использую в WS API по аннотациям JAX-WS:

@WebMethod
public MyResponse sendSingle2(
    @WebParam(name="username") String username,
    @WebParam(name="password") String password,
    @WebParam(name="newParam") String newParam) {
        // the code
    }

Теперь я хочу, чтобы newParam был необязательным. Я имею в виду, что я хочу, чтобы метод все еще работал не только тогда, когда параметр пуст в переданном xml:

<ws:sendSingle2>
    <username>user</username>
    <password>pass</password>
    <newParam></newParam>
</ws:sendSingle2>

но и когда он отсутствует:

<ws:sendSingle2>
    <username>user</username>
    <password>pass</password>
</ws:sendSingle2>

мне нужно, чтобы он не нарушал существующий API, который работает без нового param.

2 ответов


@WebParam сопоставляет часть сообщения с параметром, и части не могут быть необязательными. См.дополнительные части сообщения в WSDL. Поэтому короткий ответ заключается в том, что именно то, что вы просите не может быть сделано. Но если вы можете выполнить рефакторинг этого метода, вы можете использовать один из подходов, описанных ниже.

обычно optionality параметра устанавливается через schema minOccurs=0. Кроме того, вместо использования нескольких параметров вы можете определить один параметр запроса в своем схема, которую вы определяете как параметр для вашего WebMethod. Теперь optionality инкапсулируется внутри параметра, и тот же метод вызывается для вызова с или без необязательных параметров.

я предпочитаю сначала определить контракт, а не полагаться на автоматически сгенерированные файлы. Как только вы выяснили, как xsd, SOAP и WSDL играют вместе, вы вряд ли захотите использовать аннотации / определения на основе кода, поскольку вы более гибки другим способом вокруг.

Код-Пример:

<xs:schema
    targetNamespace="http://your.namespace.com"
    xmlns:tns="http://your.namespace.com"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    elementFromDefault="qualified"
    attributeFromDefault="qualified">

...

<xs:element name="MyRequest" type="tns:MyRequestType" />
<xs:element name="MyResponse" type="tns:MyResponseType" />

<xs:complexType name"MyRequestType">
    <xs:sequence>
        <xs:element name="username" type="xs:string" minOccurs="1" maxOccurs="1" />
        <xs:element name="password" type="xs:string" minOccurs="1" maxOccurs="1" />
        <xs:element name="newParam" type="xs:string" minOccurs="0" maxOccurs="1" />
    </xs:sequence>
</xs:complexType>

...

</xs:schema>

в вашем файле WSDL вы определяете сообщение следующим образом:

<wsdl:definitions
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:msg="http://your.namespace.com"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    targetNamespace="http://your.namespace.com">

    <wsdl:types>
        <xs:schema>
            <!-- either import the externalized schema -->
            <xs:import namespace="http://your.namespace.com"
                       schemaLocation="someDir/yourMessageSchema.xsd" />
        </xs:schema>
        <!-- or define the schema within the WSDL - just copy the schema here -->
        <xs:schema
            targetNamespace="http://your.namespace.com"
            xmlns:tns="http://your.namespace.com"
            xmlns:xs="http://www.w3.org/2001/XMLSchema"
            elementFromDefault="qualified"
            attributeFromDefault="qualified">
                ...
        </xs:schema>
    </wsdl:types>

    ...

    <wsdl:message name="sendSingle2Request">
        <wsdl:part name="in" element="msg:MyRequest" />
    </wsdl:message>

    <wsdl:message name="sendSingle2Response">
        <wsdl:part name="out" element="msg:MyResponse" />
    </wsdl:message>

    ...

    <wsdl:portType name="YourServiceEndpoint">
        <wsdl:operation name="sendSingle2">
            <wsdl:input message="tns:sendSingle2Request" />
            <wsdl:output message="tns:sendSingle2Response" />
        </wsdl:operation>
        ...
    </wsdl:portType>

    <wsdl:binding name="YourServiceBinding" type="YourServiceEndpoint">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
        <wsdl:operation name=""sendSingle2">
            <soap:operation soapAction="http://your.namespace.com/SendSingle2" style="document" />
            <wsdl:input>
                <soap:body parts="in" use="literal" />
            </wsdl:input>
            <wsdl:output>
                <soap:body parts="out" use="literal" />
            </wsdl:output>
        </wsdl:operation>
        ...
    </wsdl:binding>

    <wsdl:service name="YourService">
        <wsdl:port name="YourServicePort binding="tns:YourServiceBinding">
            <soap:address location="http://your.server:port/path/to/the/service" />
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>

контракт WSDL здесь определяет, чтобы использовать стиль:document/literal и с помощью схемы фактическое сообщение SOAP будет document/literal wrapped еще с WS-я уступчивый.

ваш метод поэтому изменится на public MyResponse sendSinge2(MyRequest request) здесь request теперь инкапсулирует username, passowrd и newParam. В случае newParam не было отправлено с SOAP запрос он просто вернет null, поэтому лучше проверить, если сначала, прежде чем использовать его.

если вы придерживаетесь подхода code-first, вам нужно будет определить свой MyRequest сначала класс, который вы используете в качестве параметра запроса вместо этих 2 или 3 значений.

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "MyRequest", namespace="http://your.namespace.com")
public class MyRequest implements Serializable
{
   @XmlElement(name = "username", required = true)
   protected String username;
   @XmlElement(name = "password", required = true)
   protected String password;
   @XmlElement(name = "newParam", required = false)
   protected String newParam;
   ...
}

то же самое следует сделать для MyResult если вы еще не сделали этого. Веб-метод теперь может выглядеть примерно так:

@WebMethod(operationName = "sendSingle2")
@WebResult(name = "sendSingle2Response", targetNamespace = "http://your.namespace.com")
public MyResult sendSingle2(@WebParam(name = "sendSingle2Request") MyRequest request)
{
   ...
}

опять request инкапсулирует 3 параметра, где вы fist должен проверить, являются ли необязательные параметры null.

HTH


все зависит от вашего класса реализации, где вы используете эти параметры. В интерфейсе конечной точки просто добавьте этот параметр как webparam.

убедитесь, что в классе реализации, если вы используете этот параметр в любом месте, добавьте альтернативный код (Else part) для выполнения операции или выполнения без этого параметра.

Я думаю, что все параметры рассматриваются как необязательные, пока вы не проверите их или не используете их в своем классе реализации как рекомендуемый.