diff --git a/core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/package.html b/core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/package.html index 762be767..2e3faec4 100644 --- a/core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/package.html +++ b/core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/package.html @@ -1,6 +1,6 @@ -Provides JAXB2-based implementations of the the MethodArgumentResolver and +Provides JAXB2-based implementations of the MethodArgumentResolver and MethodReturnValueHandler interfaces. diff --git a/core/src/main/java/org/springframework/ws/server/endpoint/mapping/jaxb/XmlRootElementEndpointMapping.java b/core/src/main/java/org/springframework/ws/server/endpoint/mapping/jaxb/XmlRootElementEndpointMapping.java new file mode 100644 index 00000000..e5faf07d --- /dev/null +++ b/core/src/main/java/org/springframework/ws/server/endpoint/mapping/jaxb/XmlRootElementEndpointMapping.java @@ -0,0 +1,113 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.server.endpoint.mapping.jaxb; + +import java.lang.reflect.Method; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.JAXBIntrospector; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.namespace.QName; + +import org.springframework.core.MethodParameter; +import org.springframework.ws.context.MessageContext; +import org.springframework.ws.server.endpoint.mapping.AbstractAnnotationMethodEndpointMapping; +import org.springframework.ws.server.endpoint.support.PayloadRootUtils; +import org.springframework.xml.transform.TransformerHelper; + +/** + * Implementation of the {@link org.springframework.ws.server.EndpointMapping EndpointMapping} interface that uses the + * JAXB2 {@link XmlRootElement} annotation to map methods to request payload root elements. + *

+ * Endpoints typically have the following form: + *

+ * @Endpoint
+ * public class MyEndpoint{
+ *    public void doSomethingWithRequest(@RequestBody MyRootElement rootElement) {
+ *       ...
+ *    }
+ * }
+ * 
+ * where MyRootElement is annotated with {@code @XmlRootElement}: + *
+ * @XmlRootElement(name = "myRoot", namespace = "http://springframework.org/spring-ws")
+ * public class MyRootElement {
+ *   ...
+ * }
+ * 
+ * + * @author Arjen Poutsma + * @since 2.0 + */ +public class XmlRootElementEndpointMapping extends AbstractAnnotationMethodEndpointMapping { + + private TransformerHelper transformerHelper = new TransformerHelper(); + + public void setTransformerHelper(TransformerHelper transformerHelper) { + this.transformerHelper = transformerHelper; + } + + @Override + protected QName getLookupKeyForMethod(Method method) { + Class[] parameterTypes = method.getParameterTypes(); + for (int i = 0; i < parameterTypes.length; i++) { + MethodParameter methodParameter = new MethodParameter(method, i); + Class parameterType = methodParameter.getParameterType(); + if (parameterType.isAnnotationPresent(XmlRootElement.class)) { + QName result = handleRootElement(parameterType); + if (result != null) { + return result; + } + } + + } + return null; + } + + private QName handleRootElement(Class parameterType) { + try { + Object param = parameterType.newInstance(); + QName result = getElementName(parameterType, param); + if (result != null) { + return result; + } + } + catch (InstantiationException e) { + // ignore + } + catch (IllegalAccessException ex) { + // ignore + } + return null; + } + + private QName getElementName(Class parameterType, Object param) { + try { + JAXBContext context = JAXBContext.newInstance(parameterType); + JAXBIntrospector introspector = context.createJAXBIntrospector(); + return introspector.getElementName(param); + } + catch (JAXBException ex) { + return null; + } + } + + @Override + protected QName getLookupKeyForMessage(MessageContext messageContext) throws Exception { + return PayloadRootUtils.getPayloadRootQName(messageContext.getRequest().getPayloadSource(), transformerHelper); + } +} diff --git a/core/src/main/java/org/springframework/ws/server/endpoint/mapping/jaxb/package.html b/core/src/main/java/org/springframework/ws/server/endpoint/mapping/jaxb/package.html new file mode 100644 index 00000000..ffc138ac --- /dev/null +++ b/core/src/main/java/org/springframework/ws/server/endpoint/mapping/jaxb/package.html @@ -0,0 +1,5 @@ + + +Provides JAXB2-based EndpointMapping implementations. + + diff --git a/core/src/main/resources/org/springframework/ws/soap/server/SoapMessageDispatcher.properties b/core/src/main/resources/org/springframework/ws/soap/server/SoapMessageDispatcher.properties index c26fade3..960edab3 100644 --- a/core/src/main/resources/org/springframework/ws/soap/server/SoapMessageDispatcher.properties +++ b/core/src/main/resources/org/springframework/ws/soap/server/SoapMessageDispatcher.properties @@ -9,4 +9,7 @@ org.springframework.ws.server.EndpointAdapter=org.springframework.ws.server.endp org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter org.springframework.ws.server.EndpointExceptionResolver=org.springframework.ws.soap.server.endpoint.SimpleSoapExceptionResolver,\ - org.springframework.ws.soap.server.endpoint.SoapFaultAnnotationExceptionResolver \ No newline at end of file + org.springframework.ws.soap.server.endpoint.SoapFaultAnnotationExceptionResolver + +org.springframework.ws.server.EndpointMapping=org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping,\ + org.springframework.ws.soap.server.endpoint.mapping.SoapActionAnnotationMethodEndpointMapping \ No newline at end of file diff --git a/core/src/test/java/org/springframework/ws/server/endpoint/mapping/jaxb/XmlRootElementEndpointMappingTest.java b/core/src/test/java/org/springframework/ws/server/endpoint/mapping/jaxb/XmlRootElementEndpointMappingTest.java new file mode 100644 index 00000000..a0b91c9b --- /dev/null +++ b/core/src/test/java/org/springframework/ws/server/endpoint/mapping/jaxb/XmlRootElementEndpointMappingTest.java @@ -0,0 +1,52 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.server.endpoint.mapping.jaxb; + +import java.lang.reflect.Method; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.namespace.QName; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class XmlRootElementEndpointMappingTest { + + private XmlRootElementEndpointMapping mapping; + + @Before + public void createMapping() throws NoSuchMethodException { + mapping = new XmlRootElementEndpointMapping(); + } + + @Test + public void rootElement() throws NoSuchMethodException { + Method rootElement = getClass().getMethod("rootElement", MyRootElement.class); + QName name = mapping.getLookupKeyForMethod(rootElement); + assertEquals(new QName("myNamespace", "myRoot"), name); + } + + public void rootElement(MyRootElement rootElement) { + } + + @XmlRootElement(name = "myRoot", namespace = "myNamespace") + public static class MyRootElement { + + } + +}