Documentation
This commit is contained in:
@@ -586,13 +586,13 @@
|
||||
Consider the following sample endpoint:
|
||||
<programlistingco>
|
||||
<areaspec>
|
||||
<area coords="9" id="server-endpoint-atEndpoint"/>
|
||||
<area coords="14" id="server-endpoint-constructor"/>
|
||||
<area coords="20" id="server-endpoint-order"/>
|
||||
<area coords="27" id="server-endpoint-getOrder"/>
|
||||
<area coords="10" id="server-endpoint-atEndpoint"/>
|
||||
<area coords="15" id="server-endpoint-constructor"/>
|
||||
<area coords="21" id="server-endpoint-order"/>
|
||||
<area coords="28" id="server-endpoint-getOrder"/>
|
||||
<areaset coords="" id="server-endpoint-payloadRoot">
|
||||
<area coords="19" id="server-endpoint-payloadRoot-1"/>
|
||||
<area coords="25" id="server-endpoint-payloadRoot-2"/>
|
||||
<area coords="20" id="server-endpoint-payloadRoot-1"/>
|
||||
<area coords="26" id="server-endpoint-payloadRoot-2"/>
|
||||
</areaset>
|
||||
</areaspec>
|
||||
<programlisting><![CDATA[package samples;
|
||||
@@ -602,6 +602,7 @@ import org.w3c.dom.Element;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.ws.server.endpoint.annotation.Endpoint;
|
||||
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
|
||||
import org.springframework.ws.soap.SoapHeader;
|
||||
|
||||
@Endpoint
|
||||
public class AnnotationOrderEndpoint {
|
||||
@@ -621,7 +622,8 @@ public class AnnotationOrderEndpoint {
|
||||
|
||||
@PayloadRoot(localPart = "orderRequest", namespace = "http://samples")
|
||||
@ResponsePayload
|
||||
public Order getOrder(@RequestPayload OrderRequest orderRequest) {
|
||||
public Order getOrder(@RequestPayload OrderRequest orderRequest, SoapHeader header) {
|
||||
checkSoapHeaderForSomething(header);
|
||||
return orderService.getOrder(orderRequest.getId());
|
||||
}
|
||||
|
||||
@@ -662,7 +664,9 @@ public class AnnotationOrderEndpoint {
|
||||
<interfacename>@XmlRootElement</interfacename>).
|
||||
This means that the payload of the message is passed on to this method as a unmarshalled
|
||||
object.
|
||||
The method is also annotated with <interfacename>@ResponseBody</interfacename>,
|
||||
The <interfacename>SoapHeader</interfacename> type is also given as a parameter.
|
||||
On invocation, this parameter will contain the SOAP header of the request message.
|
||||
The method is also annotated with <interfacename>@ResponsePayload</interfacename>,
|
||||
indicating that the return value (the <classname>Order</classname>) is used as the payload
|
||||
of the response message.
|
||||
</para>
|
||||
@@ -833,7 +837,7 @@ public void order(@RequestPayload Element orderElement) {
|
||||
and that is annotated with <interfacename>@XPathParam</interfacename>.
|
||||
</entry>
|
||||
<entry align="center">✗</entry>
|
||||
<entry>Enabled by default.</entry>
|
||||
<entry>Enabled by default, see <xref linkend="server-xpath-param" />.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry align="center">Message context</entry>
|
||||
@@ -909,451 +913,170 @@ public void order(@RequestPayload Element orderElement) {
|
||||
Refer to the class-level Javadoc of <classname>DefaultMethodEndpointAdapter</classname> and
|
||||
<interfacename>MethodArgumentResolver</interfacename> to see how.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Handling method return types</title>
|
||||
<para>
|
||||
To map the return value to the payload of the response message, you will need to annotate the
|
||||
method with the <interfacename>@ResponsePayload</interfacename> annotation.
|
||||
This annotation tells Spring-WS that the return value needs to be bound to the response payload.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title><classname>AbstractDomPayloadEndpoint</classname> and other DOM endpoints</title>
|
||||
<para>
|
||||
One of the most basic ways to handle the incoming XML payload is by using a DOM (Document Object Model)
|
||||
API. By extending from <classname>AbstractDomPayloadEndpoint</classname>, you can use the
|
||||
<package>org.w3c.dom.Element</package> and related classes to handle the request and create the
|
||||
response. When using the <classname>AbstractDomPayloadEndpoint</classname> as the baseclass for your
|
||||
endpoints you only have to override the <methodname>invokeInternal(Element, Document)</methodname>
|
||||
method, implement your logic, and return an <interfacename>Element</interfacename> if a response is
|
||||
necessary. Here is a short example consisting of a class and a declaration in the application context.
|
||||
</para>
|
||||
<programlisting><![CDATA[package samples;
|
||||
|
||||
public class SampleEndpoint extends AbstractDomPayloadEndpoint {
|
||||
|
||||
private String responseText;
|
||||
|
||||
public SampleEndpoint(String responseText) {
|
||||
this.responseText = responseText;
|
||||
}
|
||||
|
||||
protected Element invokeInternal(
|
||||
Element requestElement,
|
||||
Document document) throws Exception {
|
||||
String requestText = requestElement.getTextContent();
|
||||
System.out.println("Request text: " + requestText);
|
||||
|
||||
Element responseElement = document.createElementNS("http://samples", "response");
|
||||
responseElement.setTextContent(responseText);
|
||||
return responseElement;
|
||||
}
|
||||
}]]></programlisting>
|
||||
<programlisting><![CDATA[<bean id="sampleEndpoint" class="samples.SampleEndpoint">
|
||||
<constructor-arg value="Hello World!"/>
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
The above class and the declaration in the application context are all you need besides setting up an
|
||||
endpoint mapping (see the section entitled <xref linkend="server-endpoint-mapping"/>) to get this very
|
||||
simple endpoint working. The SOAP message handled by this endpoint will look something like:
|
||||
</para>
|
||||
<programlisting><![CDATA[<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<SOAP-ENV:Body>]]><emphasis role="bold"><![CDATA[
|
||||
<request xmlns="http://samples">
|
||||
Hello
|
||||
</request>]]></emphasis><![CDATA[
|
||||
</SOAP-ENV:Body>
|
||||
</SOAP-ENV:Envelope>]]></programlisting>
|
||||
<para>
|
||||
Though it could also handle the following Plain Old XML (POX) message, since we are only working on
|
||||
the <emphasis>payload</emphasis> of the message, and do not care whether it is SOAP or POX.
|
||||
</para>
|
||||
<programlisting><![CDATA[<request xmlns="http://samples">
|
||||
Hello
|
||||
</request>]]></programlisting>
|
||||
<para>
|
||||
The SOAP response looks like:
|
||||
</para>
|
||||
<programlisting><![CDATA[<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<SOAP-ENV:Body>]]><emphasis role="bold"><![CDATA[
|
||||
<response xmlns="http://samples">
|
||||
Hello World!
|
||||
</response>]]></emphasis><![CDATA[
|
||||
</SOAP-ENV:Body>
|
||||
</SOAP-ENV:Envelope>]]></programlisting>
|
||||
<para>
|
||||
Besides the <classname>AbstractDomPayloadEndpoint</classname>, which uses W3C DOM, there are other
|
||||
base classes which use alternative DOM APIs. Spring Web Services supports most DOM APIs, so that you
|
||||
can use the one you are familiar with. For instance, the
|
||||
<classname>AbstractJDomPayloadEndpoint</classname> allows you to use JDOM, and the
|
||||
<classname>AbstractXomPayloadEndpoint</classname> uses XOM to handle the XML. All of these endpoints
|
||||
have an <methodname>invokeInternal</methodname> method similar to above.
|
||||
Also, consider using Spring-WS's XPath support to extract the information you need out of the payload.
|
||||
(See the section entitled <xref linkend="xpath"/> for details.)
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title><classname>AbstractMarshallingPayloadEndpoint</classname></title>
|
||||
<para>
|
||||
Rather than handling XML directly using DOM, you can use marshalling to convert the payload of the XML
|
||||
message into a Java Object. Spring Web Services offers the
|
||||
<classname>AbstractMarshallingPayloadEndpoint</classname> for this purpose, which is built on the
|
||||
Spring's OXM package. The
|
||||
<classname>AbstractMarshallingPayloadEndpoint</classname> has two properties:
|
||||
<property>marshaller</property> and <property>unmarshaller</property>, in which you can inject in the
|
||||
constructor or by setters.
|
||||
</para>
|
||||
<para>
|
||||
When extending from <classname>AbstractMarshallingPayloadEndpoint</classname>, you have to override
|
||||
the <methodname>invokeInternal(Object)</methodname> method, where the passed
|
||||
<classname>Object</classname> represents the unmarshalled request payload, and return an
|
||||
<classname>Object</classname> that will be marshalled into the response payload. Here is an
|
||||
example:
|
||||
</para>
|
||||
<programlisting><![CDATA[package samples;
|
||||
|
||||
import org.springframework.oxm.Marshaller;
|
||||
import org.springframework.oxm.Unmarshaller;
|
||||
|
||||
public class MarshallingOrderEndpoint extends AbstractMarshallingPayloadEndpoint{
|
||||
|
||||
private final OrderService orderService;
|
||||
|
||||
public MarshallingOrderEndpoint(OrderService orderService, Marshaller marshaller) {
|
||||
super(marshaller);
|
||||
this.orderService = orderService;
|
||||
}
|
||||
|
||||
protected Object invokeInternal(Object request) throws Exception {
|
||||
OrderRequest orderRequest = (OrderRequest) request;
|
||||
Order order = orderService.getOrder(orderRequest.getId());
|
||||
return order;
|
||||
}
|
||||
}]]></programlisting>
|
||||
<programlisting><![CDATA[<beans>
|
||||
<bean id="orderEndpoint" class="samples.MarshallingOrderEndpoint">
|
||||
<constructor-arg ref="orderService"/>
|
||||
<constructor-arg ref="marshaller"/>
|
||||
</bean>
|
||||
|
||||
<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
|
||||
<property name="classesToBeBound">
|
||||
<list>
|
||||
<value>samples.OrderRequest</value>
|
||||
<value>samples.Order</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="orderService" class="samples.DefaultOrderService"/>
|
||||
|
||||
]]><lineannotation><!-- Other beans, such as the endpoint mapping --></lineannotation><![CDATA[
|
||||
</beans>]]></programlisting>
|
||||
<para>
|
||||
In this sample, we configure a
|
||||
<ulink url="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/oxm.html#oxm-jaxb2">Jaxb2Marshaller</ulink>
|
||||
for the
|
||||
<classname>OrderRequest</classname> and <classname>Order</classname> classes, and inject that
|
||||
marshaller together with the
|
||||
<classname>DefaultOrderService</classname> into our endpoint. This business service is not shown, but
|
||||
it is a normal transactional service, probably using DAOs to obtain data from a database.
|
||||
In the <methodname>invokeInternal</methodname> method, we cast the request object to an
|
||||
<classname>OrderRequest</classname> object, which is the JAXB object representing the payload of the
|
||||
request. Using the identifier of that request, we obtain an order from our business service and return
|
||||
it. The returned object is marshalled into XML, and used as the payload of the response message.
|
||||
The SOAP request handled by this endpoint will look like:
|
||||
</para>
|
||||
<programlisting id="server-order-request"><![CDATA[<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<SOAP-ENV:Body>
|
||||
<orderRequest xmlns="http://samples" id="42"/>
|
||||
</SOAP-ENV:Body>
|
||||
</SOAP-ENV:Envelope>
|
||||
]]></programlisting>
|
||||
<para>
|
||||
The resulting response will be something like:
|
||||
</para>
|
||||
<programlisting><![CDATA[<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<SOAP-ENV:Body>
|
||||
<order xmlns="http://samples" id="42">
|
||||
<item id="100">
|
||||
<quantity>1</quantity>
|
||||
<price>20.0</price>
|
||||
</item>
|
||||
<item id="101">
|
||||
<quantity>1</quantity>
|
||||
<price>10.0</price>
|
||||
</item>
|
||||
</order>
|
||||
</SOAP-ENV:Body>
|
||||
</SOAP-ENV:Envelope>]]></programlisting>
|
||||
<para>
|
||||
Instead of JAXB 2, we could have used <ulink
|
||||
url="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/oxm.html">any Spring OXM marshallers</ulink>.
|
||||
The only thing that would change in the above example is the configuration of the
|
||||
<literal>marshaller</literal> bean.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Using Spring <interfacename>Validator</interfacename> with Marshalling Endpoints</title>
|
||||
<para>
|
||||
It is possible to use <ulink url="http://static.springframework.org/spring/docs/2.5.x/reference/validation.html#validator"><interfacename>Validator</interfacename></ulink>
|
||||
objects in conjunction with marshalling endpoints in order to validate the unmarshalled payloads.
|
||||
Spring-WS provides 2 extensions of <classname>AbstractMarshallingPayloadEndpoint</classname> for that purpose:
|
||||
<classname>AbstractValidatingMarshallingPayloadEndpoint</classname> and
|
||||
<classname>AbstractFaultCreatingValidatingMarshallingPayloadEndpoint</classname>. The former is the most
|
||||
general whereas the latter specializes in creating SOAP faults in response to validation errors.
|
||||
</para>
|
||||
<para>
|
||||
Both classes support setting one or more <interfacename>Validator</interfacename> objects via the
|
||||
<property>validator</property> and <property>validators</property> properties respectively.
|
||||
Note that all of the injected validators
|
||||
<emphasis role="bold">must</emphasis> support the request object (through the <methodname>supports</methodname> method)
|
||||
or else an <exceptionname>IllegalArgumentException</exceptionname> will be thrown.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
The default request object name used in the validator is <literal>request</literal>.
|
||||
The error codes are generated in consequence. For instance, assuming a POJO with a
|
||||
"<property>name</property>" property of type <literal>java.lang.String</literal>,
|
||||
calling <methodname>errors.rejectValue("name","invalidValue")</methodname> in the
|
||||
<methodname>validate</methodname> method of a <interfacename>Validator</interfacename>
|
||||
generates the following error codes:
|
||||
<literal>invalidValue.request.name</literal>, <literal>invalidValue.name</literal>,
|
||||
<literal>invalidValue.java.lang.String</literal> and <literal>invalidValue</literal>.
|
||||
Similarly, calling <methodname>errors.reject("invalidValue")</methodname>
|
||||
generates <literal>invalidValue.request</literal> and <literal>invalidValue</literal> as error codes.
|
||||
</para>
|
||||
</note>
|
||||
<section>
|
||||
<title><classname>AbstractValidatingMarshallingPayloadEndpoint</classname></title>
|
||||
<para>
|
||||
Subclasses of <classname>AbstractValidatingMarshallingPayloadEndpoint</classname>
|
||||
implement the validation error handling logic by overriding the <methodname>onValidationErrors</methodname>
|
||||
method. This method is called when a validation error occurs and its return value
|
||||
indicates whether the endpoint should continue processing the request or not.
|
||||
</para>
|
||||
<para>
|
||||
In the following example, a custom error POJO is marshalled and sent as a response:
|
||||
</para>
|
||||
<programlisting><![CDATA[public class MyMarshallingEndpoint extends AbstractValidatingMarshallingPayloadEndpoint{
|
||||
|
||||
private MessageSource messageSource;
|
||||
|
||||
protected Object invokeInternal(Object requestObject) throws Exception {
|
||||
// process the payload
|
||||
}
|
||||
|
||||
protected boolean onValidationErrors(MessageContext messageContext, Object requestObject, Errors errors) {
|
||||
FieldError error = errors.getFieldError("name");
|
||||
CustomError customError = new CustomError();
|
||||
String message = messageSource.getMessage(error, Locale.ENGLISH);
|
||||
customError.setMessage(message);
|
||||
try {
|
||||
getMarshaller().marshal(customError, messageContext.getResponse().getPayloadResult());
|
||||
} catch (XmlMappingException ex) {
|
||||
// handle the exception
|
||||
} catch (IOException ex) {
|
||||
// handle the exception
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
]]></programlisting>
|
||||
</section>
|
||||
<section>
|
||||
<title><classname>AbstractFaultCreatingValidatingMarshallingPayloadEndpoint</classname></title>
|
||||
<para>
|
||||
Endpoints of this type generate a SOAP fault whenever a validation error occurs.
|
||||
By default, a fault detail element is generated for each validation error.
|
||||
The error codes are resolved using the application context message source.
|
||||
</para>
|
||||
<para>
|
||||
The properties of <classname>AbstractFaultCreatingValidatingMarshallingPayloadEndpoint</classname>
|
||||
have sensible defaults, which makes its subclasses quite simple to configure as in the following example:
|
||||
</para>
|
||||
<programlisting><![CDATA[<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
|
||||
<property name="basename" value="message"/>
|
||||
</bean>
|
||||
|
||||
<bean id="orderValidator" class="samples.OrderValidator"/>
|
||||
|
||||
<bean id="marshallingOrderEndpoint" class="samples.MarshallingOrderEndpoint">
|
||||
<property name="marshaller" ref="marshaller"/>
|
||||
<property name="unmarshaller" ref="marshaller"/>
|
||||
<property name="validator" ref="orderValidator"/>
|
||||
</bean>
|
||||
]]></programlisting>
|
||||
<para>
|
||||
In case of validation error, here is how the response might look like:
|
||||
</para>
|
||||
<programlisting><![CDATA[<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<SOAP-ENV:Header/>
|
||||
<SOAP-ENV:Body>
|
||||
<SOAP-ENV:Fault>
|
||||
<faultcode>SOAP-ENV:Client</faultcode>
|
||||
<faultstring xml:lang="en">Validation error</faultstring>
|
||||
<detail>
|
||||
<spring-ws:ValidationError xmlns:spring-ws="http://springframework.org/spring-ws">
|
||||
invalid user id: Ernie
|
||||
</spring-ws:ValidationError>
|
||||
<spring-ws:ValidationError xmlns:spring-ws="http://springframework.org/spring-ws">
|
||||
invalid order
|
||||
</spring-ws:ValidationError>
|
||||
</detail>
|
||||
</SOAP-ENV:Fault>
|
||||
</SOAP-ENV:Body>
|
||||
</SOAP-ENV:Envelope>
|
||||
]]></programlisting>
|
||||
<para>
|
||||
It is possible though to customize various aspects of the generated SOAP faults, such as the fault string
|
||||
and the soap detail.
|
||||
Please refer to the <ulink url="http://static.springframework.org/spring-ws/site/apidocs/org/springframework/ws/soap/server/endpoint/AbstractFaultCreatingValidatingMarshallingPayloadEndpoint.html">Javadoc</ulink>
|
||||
for the full list of available options.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section id="server-at-endpoint">
|
||||
<title><interfacename>@Endpoint</interfacename></title>
|
||||
<para>
|
||||
The previous two programming models were based on inheritance, and handled individual XML messages.
|
||||
Spring Web Services offer another endpoint with which you can aggregate multiple handling into one
|
||||
controller, thus grouping functionality together. This model is based on annotations, so you can use
|
||||
it only with Java 5 and higher. Here is an example that uses the same marshalled objects as above:
|
||||
</para>
|
||||
<programlisting><![CDATA[package samples;
|
||||
|
||||
import org.springframework.ws.server.endpoint.annotation.Endpoint;
|
||||
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
|
||||
|
||||
@Endpoint
|
||||
public class AnnotationOrderEndpoint {
|
||||
private final OrderService orderService;
|
||||
|
||||
public AnnotationOrderEndpoint(OrderService orderService) {
|
||||
this.orderService = orderService;
|
||||
}
|
||||
|
||||
@PayloadRoot(localPart = "orderRequest", namespace = "http://samples")
|
||||
public Order getOrder(OrderRequest orderRequest) {
|
||||
return orderService.getOrder(orderRequest.getId());
|
||||
}
|
||||
|
||||
@PayloadRoot(localPart = "order", namespace = "http://samples")
|
||||
public void order(Order order) {
|
||||
orderService.createOrder(order);
|
||||
}
|
||||
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
By annotating the class with <interfacename>@Endpoint</interfacename>, you mark it as a Spring-WS
|
||||
endpoint. Because the endpoint class can have multiple request handling methods, we need to instruct
|
||||
Spring-WS which method to invoke for which request. This is done using the
|
||||
<interfacename>@PayloadRoot</interfacename> annotation: the <methodname>getOrder</methodname> method
|
||||
will be invoked for requests with a <literal>orderRequest</literal> local name and a
|
||||
<uri>http://samples</uri> namespace URI; the <methodname>order</methodname> method for requests with
|
||||
a <literal>order</literal> local name. For more information about these annotations, refer to
|
||||
<xref linkend="server-method-endpoint-mapping"/>.
|
||||
We also need to configure Spring-WS to support the JAXB objects <classname>OrderRequest</classname> and
|
||||
<classname>Order</classname> by defining a <classname>Jaxb2Marshaller</classname>:
|
||||
</para>
|
||||
<programlisting><![CDATA[<beans>
|
||||
|
||||
<bean id="orderEndpoint" class="samples.AnnotationOrderEndpoint">
|
||||
<constructor-arg ref="orderService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="orderService" class="samples.DefaultOrderService"/>
|
||||
|
||||
<bean class="org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter">
|
||||
<constructor-arg ref="marshaller"/>
|
||||
</bean>
|
||||
|
||||
<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
|
||||
<property name="classesToBeBound">
|
||||
<list>
|
||||
<value>samples.OrderRequest</value>
|
||||
<value>samples.Order</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping"/>
|
||||
|
||||
</beans>]]></programlisting>
|
||||
<para>
|
||||
The <classname>GenericMarshallingMethodEndpointAdapter</classname> converts the incoming
|
||||
XML messages to marshalled objects used as parameters and return value; the
|
||||
<classname>PayloadRootAnnotationMethodEndpointMapping</classname> is the mapping that detects and
|
||||
handles the <interfacename>@PayloadRoot</interfacename> annotations.
|
||||
</para>
|
||||
<section>
|
||||
<title><interfacename>@XPathParam</interfacename></title>
|
||||
<para>
|
||||
As an alternative to using marshalling, we could have used <link linkend="xpath">XPath</link> to
|
||||
extract the information out of the incoming XML request. Spring-WS offers another annotation for
|
||||
this purpose: <interfacename>@XPathParam</interfacename>. You simply annotate one or more method
|
||||
parameter with this annotation (each), and each such annotated parameter will be bound to the
|
||||
evaluation of that annotation. Here is an example:
|
||||
</para>
|
||||
<programlisting id="server-payload-root-annotation"><![CDATA[package samples;
|
||||
<section id="server-xpath-param">
|
||||
<title><interfacename>@XPathParam</interfacename></title>
|
||||
<para>
|
||||
One parameter type needs some extra explanation: <interfacename>@XPathParam</interfacename>.
|
||||
The idea here is that you simply annotate one or more method
|
||||
parameter with an XPath expression, and that each such annotated parameter will be bound to the
|
||||
evaluation of the expression.
|
||||
Here is an example:
|
||||
</para>
|
||||
<programlisting id="server-payload-root-annotation">package samples;
|
||||
|
||||
import javax.xml.transform.Source;
|
||||
|
||||
import org.springframework.ws.server.endpoint.annotation.Endpoint;
|
||||
import org.springframework.ws.server.endpoint.annotation.Namespace;
|
||||
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
|
||||
import org.springframework.ws.server.endpoint.annotation.XPathParam;
|
||||
|
||||
@Endpoint
|
||||
public class AnnotationOrderEndpoint {
|
||||
|
||||
private final OrderService orderService;
|
||||
private final OrderService orderService;
|
||||
|
||||
public AnnotationOrderEndpoint(OrderService orderService) {
|
||||
this.orderService = orderService;
|
||||
}
|
||||
public AnnotationOrderEndpoint(OrderService orderService) {
|
||||
this.orderService = orderService;
|
||||
}
|
||||
|
||||
@PayloadRoot(localPart = "orderRequest", namespace = "http://samples")
|
||||
public Source getOrder(]]><emphasis role="bold"><![CDATA[@XPathParam("/s:orderRequest/@id") double orderId]]></emphasis><![CDATA[) {
|
||||
Order order = orderService.getOrder((int) orderId);
|
||||
]]><lineannotation>// create <interfacename>Source</interfacename> from order and return it</lineannotation><![CDATA[
|
||||
}
|
||||
@PayloadRoot(localPart = "orderRequest", namespace = "http://samples")
|
||||
<emphasis role="bold">@Namespace(prefix = "s", uri="http://samples")</emphasis>
|
||||
public Order getOrder(<emphasis role="bold">@XPathParam("/s:orderRequest/@id") int orderId</emphasis>) {
|
||||
Order order = orderService.getOrder(orderId);
|
||||
<lineannotation>// create <interfacename>Source</interfacename> from order and return it</lineannotation>
|
||||
}
|
||||
|
||||
}]]></programlisting>
|
||||
}</programlisting>
|
||||
<para>
|
||||
Since we use the prefix '<literal>s</literal>' in our XPath expression, we must bind it to the
|
||||
<uri>http://samples</uri> namespace.
|
||||
This is accomplished with the <interfacename>@Namespace</interfacename> annotation.
|
||||
Alternatively, we could have placed this annotation on the type-level to use the same namespace
|
||||
mapping for all handler methods, or even the package-level
|
||||
(in <filename>package-info.java</filename>) to use it for multiple endpoints.
|
||||
</para>
|
||||
<para>
|
||||
Using the <interfacename>@XPathParam</interfacename>, you can bind to all the data types
|
||||
supported by XPath:
|
||||
<itemizedlist>
|
||||
<listitem><para><type>boolean</type> or <classname>Boolean</classname></para></listitem>
|
||||
<listitem><para><type>double</type> or <classname>Double</classname></para></listitem>
|
||||
<listitem><para><classname>String</classname></para></listitem>
|
||||
<listitem><para><interfacename>Node</interfacename></para></listitem>
|
||||
<listitem><para><interfacename>NodeList</interfacename></para></listitem>
|
||||
</itemizedlist>
|
||||
In addition to this list, you can use any type that can be converted from a
|
||||
<classname>String</classname> by a Spring 3
|
||||
<ulink url="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/validation.html#core-convert">conversion service</ulink>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
<section>
|
||||
<title>Handling method return types</title>
|
||||
<para>
|
||||
Since we use the prefix '<literal>s</literal>' in our XPath expression, we must bind it to the
|
||||
<uri>http://samples</uri> namespace:
|
||||
To send a response message, the handling needs to specify a return type.
|
||||
If no response message is required, the method can simply declare a <literal>void</literal> return
|
||||
type.
|
||||
Most commonly, the return type is used to create the payload of the response message, but it is
|
||||
also possible to map to other parts of the response message.
|
||||
This section will describe the return types you can use in your handling method signatures.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<beans>
|
||||
<bean id="orderEndpoint" class="samples.AnnotationOrderEndpoint">
|
||||
<constructor-arg ref="orderService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="orderService" class="samples.DefaultOrderService"/>
|
||||
|
||||
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping"/>
|
||||
|
||||
]]><emphasis role="bold"><![CDATA[<bean class="org.springframework.ws.server.endpoint.adapter.XPathParamAnnotationMethodEndpointAdapter">
|
||||
<property name="namespaces">
|
||||
<props>
|
||||
<prop key="s">http://samples</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>]]></emphasis><![CDATA[
|
||||
|
||||
</beans>]]></programlisting>
|
||||
<para>
|
||||
Using the <interfacename>@XPathParam</interfacename>, you can bind to all the data types supported by
|
||||
XPath:
|
||||
<itemizedlist>
|
||||
<listitem><para><type>boolean</type> or <classname>Boolean</classname></para></listitem>
|
||||
<listitem><para><type>double</type> or <classname>Double</classname></para></listitem>
|
||||
<listitem><para><classname>String</classname></para></listitem>
|
||||
<listitem><para><interfacename>Node</interfacename></para></listitem>
|
||||
<listitem><para><interfacename>NodeList</interfacename></para></listitem>
|
||||
</itemizedlist>
|
||||
To map the return value to the payload of the response message, you will need to annotate the
|
||||
method with the <interfacename>@ResponsePayload</interfacename> annotation.
|
||||
This annotation tells Spring-WS that the return value needs to be bound to the response payload.
|
||||
</para>
|
||||
<para>
|
||||
The following table describes the supported return types.
|
||||
It shows the supported types, whether the parameter should be annotated with
|
||||
<interfacename>@ResponsePayload</interfacename>, and any additional notes.
|
||||
<informaltable>
|
||||
<tgroup cols="4">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Name</entry>
|
||||
<entry>Supported return types</entry>
|
||||
<entry><interfacename>@ResponsePayload</interfacename> required?</entry>
|
||||
<entry>Additional notes</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry align="center">No response</entry>
|
||||
<entry>
|
||||
<literal>void</literal>
|
||||
</entry>
|
||||
<entry align="center">✗</entry>
|
||||
<entry>Enabled by default.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry align="center">TrAX</entry>
|
||||
<entry>
|
||||
<interfacename>javax.xml.transform.Source</interfacename> and sub-interfaces
|
||||
(<interfacename>DOMSource</interfacename>, <interfacename>SAXSource</interfacename>,
|
||||
<interfacename>StreamSource</interfacename>, and <interfacename>StAXSource</interfacename>)
|
||||
</entry>
|
||||
<entry align="center">✓</entry>
|
||||
<entry>Enabled by default.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry align="center">W3C DOM</entry>
|
||||
<entry><interfacename>org.w3c.dom.Element</interfacename></entry>
|
||||
<entry align="center">✓</entry>
|
||||
<entry>Enabled by default</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry align="center">dom4j</entry>
|
||||
<entry><interfacename>org.dom4j.Element</interfacename></entry>
|
||||
<entry align="center">✓</entry>
|
||||
<entry>Enabled when dom4j is on the classpath.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry align="center">JDOM</entry>
|
||||
<entry><classname>org.jdom.Element</classname></entry>
|
||||
<entry align="center">✓</entry>
|
||||
<entry>Enabled when JDOM is on the classpath.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry align="center">XOM</entry>
|
||||
<entry><classname>nu.xom.Element</classname></entry>
|
||||
<entry align="center">✓</entry>
|
||||
<entry>Enabled when XOM is on the classpath.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry align="center">JAXB2</entry>
|
||||
<entry>
|
||||
Any type that is annotated with
|
||||
<interfacename>javax.xml.bind.annotation.XmlRootElement</interfacename>,
|
||||
and <classname>javax.xml.bind.JAXBElement</classname>.
|
||||
</entry>
|
||||
<entry align="center">✓</entry>
|
||||
<entry>Enabled when JAXB2 is on the classpath.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry align="center">OXM</entry>
|
||||
<entry>
|
||||
Any type supported by a Spring OXM
|
||||
<ulink url="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/oxm.html#d0e26096"><interfacename>Marshaller</interfacename></ulink>.
|
||||
</entry>
|
||||
<entry align="center">✓</entry>
|
||||
<entry>
|
||||
Enabled when the <literal>marshaller</literal> attribute of
|
||||
<literal><sws:annotation-driven/></literal> is specified.
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
<para>
|
||||
As you can see, there are a lot of possibilities when it comes to defining handling method
|
||||
signatures.
|
||||
It is even possible to extend this mechanism, and to support your own parameter types.
|
||||
Refer to the class-level Javadoc of <classname>DefaultMethodEndpointAdapter</classname> and
|
||||
<interfacename>MethodReturnValueHandler</interfacename> to see how.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
@@ -1361,8 +1084,8 @@ public class AnnotationOrderEndpoint {
|
||||
<section id="server-endpoint-mapping">
|
||||
<title>Endpoint mappings</title>
|
||||
<para>
|
||||
The endpoint mapping is responsible for mapping incoming messages to appropriate endpoints. There are some
|
||||
endpoint mappings you can use out of the box, for example, the
|
||||
The endpoint mapping is responsible for mapping incoming messages to appropriate endpoints.
|
||||
There are some endpoint mappings you can use out of the box, for example, the
|
||||
<classname>PayloadRootQNameEndpointMapping</classname> or the
|
||||
<classname>SoapActionEndpointMapping</classname>, but let's first examine the general concept of an
|
||||
<interfacename>EndpointMapping</interfacename>.
|
||||
|
||||
Reference in New Issue
Block a user