SWS-351 - Arbitrary parameter injection for @Endpoints

This commit is contained in:
Arjen Poutsma
2010-05-06 11:38:55 +00:00
parent 324775f666
commit cd4a08330e
22 changed files with 825 additions and 75 deletions

View File

@@ -16,19 +16,29 @@
package org.springframework.ws.server.endpoint.adapter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.MethodParameter;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.ws.server.endpoint.adapter.method.MessageContextMethodArgumentResolver;
import org.springframework.ws.server.endpoint.adapter.method.MethodArgumentResolver;
import org.springframework.ws.server.endpoint.adapter.method.MethodReturnValueHandler;
import org.springframework.ws.support.DefaultStrategiesHelper;
import org.springframework.ws.server.endpoint.adapter.method.SourcePayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.StaxPayloadMethodArgumentResolver;
import org.springframework.ws.server.endpoint.adapter.method.dom.Dom4jPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.dom.DomPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.dom.JDomPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.dom.XomPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.jaxb.JaxbElementPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.jaxb.XmlRootElementPayloadMethodProcessor;
/**
* Default extension of {@link AbstractMethodEndpointAdapter} with support for pluggable {@linkplain
@@ -37,19 +47,31 @@ import org.springframework.ws.support.DefaultStrategiesHelper;
* @author Arjen Poutsma
* @since 2.0
*/
public class DefaultMethodEndpointAdapter extends AbstractMethodEndpointAdapter {
public class DefaultMethodEndpointAdapter extends AbstractMethodEndpointAdapter
implements BeanClassLoaderAware, InitializingBean {
private static final String DOM4J_CLASS_NAME = "org.dom4j.Element";
private static final String JAXB2_CLASS_NAME = "javax.xml.bind.Binder";
private static final String JDOM_CLASS_NAME = "org.jdom.Element";
private static final String STAX_CLASS_NAME = "javax.xml.stream.XMLInputFactory";
private static final String XOM_CLASS_NAME = "nu.xom.Element";
private static final String SOAP_METHOD_ARGUMENT_RESOLVER_CLASS_NAME =
"org.springframework.ws.soap.server.endpoint.adapter.method.SoapMethodArgumentResolver";
private List<MethodArgumentResolver> methodArgumentResolvers;
private List<MethodReturnValueHandler> methodReturnValueHandlers;
/**
* Initializes a {@code DefaultMethodEndpointAdapter} with the default strategies.
*
* @see #initDefaultStrategies()
*/
public DefaultMethodEndpointAdapter() {
initDefaultStrategies();
private ClassLoader classLoader;
/** Returns the list of {@code MethodArgumentResolver}s to use. */
public List<MethodArgumentResolver> getMethodArgumentResolvers() {
return methodArgumentResolvers;
}
/** Sets the list of {@code MethodArgumentResolver}s to use. */
@@ -57,29 +79,102 @@ public class DefaultMethodEndpointAdapter extends AbstractMethodEndpointAdapter
this.methodArgumentResolvers = methodArgumentResolvers;
}
/** Returns the list of {@code MethodReturnValueHandler}s to use. */
public List<MethodReturnValueHandler> getMethodReturnValueHandlers() {
return methodReturnValueHandlers;
}
/** Sets the list of {@code MethodReturnValueHandler}s to use. */
public void setMethodReturnValueHandlers(List<MethodReturnValueHandler> methodReturnValueHandlers) {
this.methodReturnValueHandlers = methodReturnValueHandlers;
}
/** Initialize the default implementations for the adapter's strategies */
private ClassLoader getClassLoader() {
return this.classLoader != null ? this.classLoader : DefaultMethodEndpointAdapter.class.getClassLoader();
}
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
public void afterPropertiesSet() throws Exception {
initDefaultStrategies();
}
/** Initialize the default implementations for the adapter's strategies. */
protected void initDefaultStrategies() {
Resource resource =
new ClassPathResource(ClassUtils.getShortName(DefaultMethodEndpointAdapter.class) + ".properties",
DefaultMethodEndpointAdapter.class);
DefaultStrategiesHelper strategiesHelper = new DefaultStrategiesHelper(resource);
initMethodArgumentResolvers();
initMethodReturnValueHandlers();
}
@SuppressWarnings("unchecked")
private void initMethodArgumentResolvers() {
if (CollectionUtils.isEmpty(methodArgumentResolvers)) {
List<MethodArgumentResolver> methodArgumentResolvers =
strategiesHelper.getDefaultStrategies(MethodArgumentResolver.class);
List<MethodArgumentResolver> methodArgumentResolvers = new ArrayList<MethodArgumentResolver>();
methodArgumentResolvers.add(new DomPayloadMethodProcessor());
methodArgumentResolvers.add(new MessageContextMethodArgumentResolver());
methodArgumentResolvers.add(new SourcePayloadMethodProcessor());
try {
Class<MethodArgumentResolver> soapMethodArgumentResolverClass =
(Class<MethodArgumentResolver>) ClassUtils
.forName(SOAP_METHOD_ARGUMENT_RESOLVER_CLASS_NAME, getClassLoader());
methodArgumentResolvers.add(BeanUtils.instantiate(soapMethodArgumentResolverClass));
}
catch (ClassNotFoundException e) {
logger.warn("Could not find \"" + SOAP_METHOD_ARGUMENT_RESOLVER_CLASS_NAME + "\" on the classpath");
}
if (isPresent(DOM4J_CLASS_NAME)) {
methodArgumentResolvers.add(new Dom4jPayloadMethodProcessor());
}
if (isPresent(JAXB2_CLASS_NAME)) {
methodArgumentResolvers.add(new XmlRootElementPayloadMethodProcessor());
methodArgumentResolvers.add(new JaxbElementPayloadMethodProcessor());
}
if (isPresent(JDOM_CLASS_NAME)) {
methodArgumentResolvers.add(new JDomPayloadMethodProcessor());
}
if (isPresent(STAX_CLASS_NAME)) {
methodArgumentResolvers.add(new StaxPayloadMethodArgumentResolver());
}
if (isPresent(XOM_CLASS_NAME)) {
methodArgumentResolvers.add(new XomPayloadMethodProcessor());
}
if (logger.isDebugEnabled()) {
logger.debug("No MethodArgumentResolvers set, using defaults: " + methodArgumentResolvers);
}
setMethodArgumentResolvers(methodArgumentResolvers);
}
}
private void initMethodReturnValueHandlers() {
if (CollectionUtils.isEmpty(methodReturnValueHandlers)) {
List<MethodReturnValueHandler> methodReturnValueHandlers =
strategiesHelper.getDefaultStrategies(MethodReturnValueHandler.class);
List<MethodReturnValueHandler> methodReturnValueHandlers = new ArrayList<MethodReturnValueHandler>();
methodReturnValueHandlers.add(new DomPayloadMethodProcessor());
methodReturnValueHandlers.add(new SourcePayloadMethodProcessor());
if (isPresent(DOM4J_CLASS_NAME)) {
methodReturnValueHandlers.add(new Dom4jPayloadMethodProcessor());
}
if (isPresent(JAXB2_CLASS_NAME)) {
methodReturnValueHandlers.add(new XmlRootElementPayloadMethodProcessor());
methodReturnValueHandlers.add(new JaxbElementPayloadMethodProcessor());
}
if (isPresent(JDOM_CLASS_NAME)) {
methodReturnValueHandlers.add(new JDomPayloadMethodProcessor());
}
if (isPresent(XOM_CLASS_NAME)) {
methodArgumentResolvers.add(new XomPayloadMethodProcessor());
}
if (logger.isDebugEnabled()) {
logger.debug("No MethodReturnValueHandlers set, using defaults: " + methodReturnValueHandlers);
}
setMethodReturnValueHandlers(methodReturnValueHandlers);
}
}
private boolean isPresent(String className) {
return ClassUtils.isPresent(className, getClassLoader());
}
@Override
protected boolean supportsInternal(MethodEndpoint methodEndpoint) {
return supportsParameters(methodEndpoint.getMethodParameters()) &&
@@ -170,7 +265,7 @@ public class DefaultMethodEndpointAdapter extends AbstractMethodEndpointAdapter
/**
* Handle the return value for the given method endpoint.
* <p/>
* This implementation iterates over the set {@linkplain #setMethodReturnValueHandler(java.util.List) return value
* This implementation iterates over the set {@linkplain #setMethodReturnValueHandlers(java.util.List)} return value
* handlers} to resolve the return value.
*
* @param messageContext the current message context

View File

@@ -155,14 +155,7 @@ public class StaxPayloadMethodArgumentResolver extends TransformerObjectSupport
return XMLInputFactory.newInstance();
}
/**
* Converts the given source to a byte array input stream.
*
* @param source the source to convert
* @return the input stream
* @throws TransformerException in case of transformation errors
*/
protected ByteArrayInputStream convertToByteArrayInputStream(Source source) throws TransformerException {
private ByteArrayInputStream convertToByteArrayInputStream(Source source) throws TransformerException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
transform(source, new StreamResult(bos));
return new ByteArrayInputStream(bos.toByteArray());

View File

@@ -14,13 +14,14 @@
* limitations under the License.
*/
package org.springframework.ws.server.endpoint.adapter.method;
package org.springframework.ws.server.endpoint.adapter.method.dom;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import org.springframework.core.MethodParameter;
import org.springframework.ws.server.endpoint.adapter.method.AbstractPayloadSourceMethodProcessor;
import org.dom4j.Document;
import org.dom4j.Element;
@@ -29,7 +30,7 @@ import org.dom4j.io.DocumentResult;
import org.dom4j.io.DocumentSource;
/**
* Implementation of {@link MethodArgumentResolver} and {@link MethodReturnValueHandler} that supports dom4j
* Implementation of {@link org.springframework.ws.server.endpoint.adapter.method.MethodArgumentResolver} and {@link org.springframework.ws.server.endpoint.adapter.method.MethodReturnValueHandler} that supports dom4j
* {@linkplain Element elements}.
*
* @author Arjen Poutsma

View File

@@ -14,20 +14,21 @@
* limitations under the License.
*/
package org.springframework.ws.server.endpoint.adapter.method;
package org.springframework.ws.server.endpoint.adapter.method.dom;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import org.springframework.core.MethodParameter;
import org.springframework.ws.server.endpoint.adapter.method.AbstractPayloadSourceMethodProcessor;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* Implementation of {@link MethodArgumentResolver} and {@link MethodReturnValueHandler} that supports W3C DOM
* Implementation of {@link org.springframework.ws.server.endpoint.adapter.method.MethodArgumentResolver} and {@link org.springframework.ws.server.endpoint.adapter.method.MethodReturnValueHandler} that supports W3C DOM
* {@linkplain Element elements}.
*
* @author Arjen Poutsma

View File

@@ -14,12 +14,13 @@
* limitations under the License.
*/
package org.springframework.ws.server.endpoint.adapter.method;
package org.springframework.ws.server.endpoint.adapter.method.dom;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import org.springframework.core.MethodParameter;
import org.springframework.ws.server.endpoint.adapter.method.AbstractPayloadSourceMethodProcessor;
import org.jdom.Document;
import org.jdom.Element;
@@ -29,7 +30,7 @@ import org.jdom.transform.JDOMSource;
import org.w3c.dom.Node;
/**
* Implementation of {@link MethodArgumentResolver} and {@link MethodReturnValueHandler} that supports JDOM
* Implementation of {@link org.springframework.ws.server.endpoint.adapter.method.MethodArgumentResolver} and {@link org.springframework.ws.server.endpoint.adapter.method.MethodReturnValueHandler} that supports JDOM
* {@linkplain Element elements}.
*
* @author Arjen Poutsma

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.ws.server.endpoint.adapter.method;
package org.springframework.ws.server.endpoint.adapter.method.dom;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -26,6 +26,7 @@ import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import org.springframework.core.MethodParameter;
import org.springframework.ws.server.endpoint.adapter.method.AbstractPayloadSourceMethodProcessor;
import nu.xom.Builder;
import nu.xom.Document;
@@ -35,7 +36,7 @@ import nu.xom.converters.DOMConverter;
import org.w3c.dom.DOMImplementation;
/**
* Implementation of {@link MethodArgumentResolver} and {@link MethodReturnValueHandler} that supports XOM {@linkplain
* Implementation of {@link org.springframework.ws.server.endpoint.adapter.method.MethodArgumentResolver} and {@link org.springframework.ws.server.endpoint.adapter.method.MethodReturnValueHandler} that supports XOM {@linkplain
* Element elements}.
*
* @author Arjen Poutsma

View File

@@ -0,0 +1,6 @@
<html>
<body>
Provides DOM-based implementations of the the <code>MethodArgumentResolver</code> and
<code>MethodReturnValueHandler</code> interfaces.
</body>
</html>

View File

@@ -0,0 +1,266 @@
/*
* 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.adapter.method.jaxb;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamSource;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.adapter.method.AbstractPayloadMethodProcessor;
import org.springframework.xml.transform.TraxUtils;
import org.w3c.dom.Node;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.ext.LexicalHandler;
/**
* @author Arjen Poutsma
* @since 2.0
*/
public abstract class AbstractJaxb2PayloadMethodProcessor extends AbstractPayloadMethodProcessor {
private final ConcurrentMap<Class, JAXBContext> jaxbContexts = new ConcurrentHashMap<Class, JAXBContext>();
protected void marshalToResponse(MessageContext messageContext, Class<?> clazz, Object jaxbElement)
throws JAXBException {
if (logger.isDebugEnabled()) {
logger.debug("Marshalling [" + jaxbElement + "] to response payload");
}
Result responsePayload = getResponsePayload(messageContext);
try {
Jaxb2ResultCallback callback = new Jaxb2ResultCallback(clazz, jaxbElement);
TraxUtils.doWithResult(responsePayload, callback);
}
catch (Exception ex) {
throw convertToJaxbException(ex);
}
}
private Result getResponsePayload(MessageContext messageContext) {
WebServiceMessage response = messageContext.getResponse();
return response != null ? response.getPayloadResult() : null;
}
protected Object unmarshalFromRequest(MessageContext messageContext, Class<?> clazz) throws JAXBException {
Source requestPayload = getRequestPayload(messageContext);
if (requestPayload == null) {
return null;
}
try {
Jaxb2SourceCallback callback = new Jaxb2SourceCallback(clazz);
TraxUtils.doWithSource(requestPayload, callback);
if (logger.isDebugEnabled()) {
logger.debug("Unmarshalled payload request to [" + callback.result + "]");
}
return callback.result;
}
catch (Exception ex) {
throw convertToJaxbException(ex);
}
}
protected <T> JAXBElement<T> unmarshalElementFromRequest(MessageContext messageContext, Class<T> clazz)
throws JAXBException {
Source requestPayload = getRequestPayload(messageContext);
if (requestPayload == null) {
return null;
}
try {
JaxbElementSourceCallback<T> callback = new JaxbElementSourceCallback<T>(clazz);
TraxUtils.doWithSource(requestPayload, callback);
if (logger.isDebugEnabled()) {
logger.debug("Unmarshalled payload request to [" + callback.result + "]");
}
return callback.result;
}
catch (Exception ex) {
throw convertToJaxbException(ex);
}
}
private Source getRequestPayload(MessageContext messageContext) {
WebServiceMessage request = messageContext.getRequest();
return request != null ? request.getPayloadSource() : null;
}
private JAXBException convertToJaxbException(Exception ex) {
if (ex instanceof JAXBException) {
return (JAXBException) ex;
}
else {
return new JAXBException(ex);
}
}
private Marshaller createMarshaller(Class<?> clazz) throws JAXBException {
JAXBContext jaxbContext = getJaxbContext(clazz);
return jaxbContext.createMarshaller();
}
private Unmarshaller createUnmarshaller(Class<?> clazz) throws JAXBException {
JAXBContext jaxbContext = getJaxbContext(clazz);
return jaxbContext.createUnmarshaller();
}
private JAXBContext getJaxbContext(Class<?> clazz) throws JAXBException {
Assert.notNull(clazz, "'clazz' must not be null");
JAXBContext jaxbContext = jaxbContexts.get(clazz);
if (jaxbContext == null) {
jaxbContext = JAXBContext.newInstance(clazz);
jaxbContexts.putIfAbsent(clazz, jaxbContext);
}
return jaxbContext;
}
// Callbacks
@SuppressWarnings("Since15")
private class Jaxb2SourceCallback implements TraxUtils.SourceCallback {
private final Unmarshaller unmarshaller;
private Object result;
public Jaxb2SourceCallback(Class<?> clazz) throws JAXBException {
this.unmarshaller = createUnmarshaller(clazz);
}
public void domSource(Node node) throws JAXBException {
result = unmarshaller.unmarshal(node);
}
public void saxSource(XMLReader reader, InputSource inputSource) throws JAXBException {
result = unmarshaller.unmarshal(inputSource);
}
public void staxSource(XMLEventReader eventReader) throws JAXBException {
result = unmarshaller.unmarshal(eventReader);
}
public void staxSource(XMLStreamReader streamReader) throws JAXBException {
result = unmarshaller.unmarshal(streamReader);
}
public void streamSource(InputStream inputStream) throws IOException, JAXBException {
result = unmarshaller.unmarshal(inputStream);
}
public void streamSource(Reader reader) throws IOException, JAXBException {
result = unmarshaller.unmarshal(reader);
}
}
@SuppressWarnings("Since15")
private class JaxbElementSourceCallback<T> implements TraxUtils.SourceCallback {
private final Unmarshaller unmarshaller;
private final Class<T> declaredType;
private JAXBElement<T> result;
public JaxbElementSourceCallback(Class<T> declaredType) throws JAXBException {
this.unmarshaller = createUnmarshaller(declaredType);
this.declaredType = declaredType;
}
public void domSource(Node node) throws JAXBException {
result = unmarshaller.unmarshal(node, declaredType);
}
public void saxSource(XMLReader reader, InputSource inputSource) throws JAXBException {
result = unmarshaller.unmarshal(new SAXSource(reader, inputSource), declaredType);
}
public void staxSource(XMLEventReader eventReader) throws JAXBException {
result = unmarshaller.unmarshal(eventReader, declaredType);
}
public void staxSource(XMLStreamReader streamReader) throws JAXBException {
result = unmarshaller.unmarshal(streamReader, declaredType);
}
public void streamSource(InputStream inputStream) throws IOException, JAXBException {
result = unmarshaller.unmarshal(new StreamSource(inputStream), declaredType);
}
public void streamSource(Reader reader) throws IOException, JAXBException {
result = unmarshaller.unmarshal(new StreamSource(reader), declaredType);
}
}
@SuppressWarnings("Since15")
private class Jaxb2ResultCallback implements TraxUtils.ResultCallback {
private final Marshaller marshaller;
private final Object jaxbElement;
private Jaxb2ResultCallback(Class<?> clazz, Object jaxbElement) throws JAXBException {
this.marshaller = createMarshaller(clazz);
this.jaxbElement = jaxbElement;
}
public void domResult(Node node) throws JAXBException {
marshaller.marshal(jaxbElement, node);
}
public void saxResult(ContentHandler contentHandler, LexicalHandler lexicalHandler) throws JAXBException {
marshaller.marshal(jaxbElement, contentHandler);
}
public void staxResult(XMLEventWriter eventWriter) throws JAXBException {
marshaller.marshal(jaxbElement, eventWriter);
}
public void staxResult(XMLStreamWriter streamWriter) throws JAXBException {
marshaller.marshal(jaxbElement, streamWriter);
}
public void streamResult(OutputStream outputStream) throws JAXBException {
marshaller.marshal(jaxbElement, outputStream);
}
public void streamResult(Writer writer) throws JAXBException {
marshaller.marshal(jaxbElement, writer);
}
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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.adapter.method.jaxb;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import org.springframework.core.MethodParameter;
import org.springframework.ws.context.MessageContext;
/** @author Arjen Poutsma */
public class JaxbElementPayloadMethodProcessor extends AbstractJaxb2PayloadMethodProcessor {
@Override
protected boolean supportsRequestPayloadParameter(MethodParameter parameter) {
Class<?> parameterType = parameter.getParameterType();
Type genericType = parameter.getGenericParameterType();
return JAXBElement.class.equals(parameterType) && genericType instanceof ParameterizedType;
}
public JAXBElement<?> resolveArgument(MessageContext messageContext, MethodParameter parameter)
throws JAXBException {
ParameterizedType parameterizedType = (ParameterizedType) parameter.getGenericParameterType();
Class<?> clazz = (Class) parameterizedType.getActualTypeArguments()[0];
return unmarshalElementFromRequest(messageContext, clazz);
}
@Override
protected boolean supportsResponsePayloadReturnType(MethodParameter returnType) {
Class<?> parameterType = returnType.getParameterType();
return JAXBElement.class.isAssignableFrom(parameterType);
}
public void handleReturnValue(MessageContext messageContext, MethodParameter returnType, Object returnValue)
throws JAXBException {
JAXBElement<?> element = (JAXBElement<?>) returnValue;
marshalToResponse(messageContext, element.getDeclaredType(), element);
}
}

View File

@@ -0,0 +1,62 @@
/*
* 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.adapter.method.jaxb;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import org.springframework.core.MethodParameter;
import org.springframework.ws.context.MessageContext;
/** @author Arjen Poutsma */
public class XmlRootElementPayloadMethodProcessor extends AbstractJaxb2PayloadMethodProcessor {
@Override
protected boolean supportsRequestPayloadParameter(MethodParameter parameter) {
Class<?> parameterType = parameter.getParameterType();
return parameterType.isAnnotationPresent(XmlRootElement.class) ||
parameterType.isAnnotationPresent(XmlType.class);
}
public Object resolveArgument(MessageContext messageContext, MethodParameter parameter) throws JAXBException {
Class<?> parameterType = parameter.getParameterType();
if (parameterType.isAnnotationPresent(XmlRootElement.class)) {
return unmarshalFromRequest(messageContext, parameterType);
}
else {
JAXBElement<?> element = unmarshalElementFromRequest(messageContext, parameterType);
return element != null ? element.getValue() : null;
}
}
@Override
protected boolean supportsResponsePayloadReturnType(MethodParameter returnType) {
Class<?> parameterType = returnType.getParameterType();
return parameterType.isAnnotationPresent(XmlRootElement.class);
}
public void handleReturnValue(MessageContext messageContext, MethodParameter returnType, Object returnValue)
throws JAXBException {
Class<?> parameterType = returnType.getParameterType();
marshalToResponse(messageContext, parameterType, returnValue);
}
}

View File

@@ -0,0 +1,6 @@
<html>
<body>
Provides JAXB2-based implementations of the the <code>MethodArgumentResolver</code> and
<code>MethodReturnValueHandler</code> interfaces.
</body>
</html>

View File

@@ -0,0 +1,6 @@
<html>
<body>
Provides the <code>MethodArgumentResolver</code> and <code>MethodReturnValueHandler</code> abstractions, and various
implementations thereof.
</body>
</html>

View File

@@ -1,16 +0,0 @@
# Default implementation classes for DefaultMethodEndpointAdapter's strategy interfaces.
# Used as fallback when no matching beans are configured.
# Not meant to be customized by application developers.
org.springframework.ws.server.endpoint.adapter.method.MethodArgumentResolver=org.springframework.ws.server.endpoint.adapter.method.Dom4jPayloadMethodProcessor,\
org.springframework.ws.server.endpoint.adapter.method.DomPayloadMethodProcessor,\
org.springframework.ws.server.endpoint.adapter.method.JDomPayloadMethodProcessor,\
org.springframework.ws.server.endpoint.adapter.method.MessageContextMethodArgumentResolver,\
org.springframework.ws.server.endpoint.adapter.method.SourcePayloadMethodProcessor,\
org.springframework.ws.server.endpoint.adapter.method.StaxPayloadMethodArgumentResolver,\
org.springframework.ws.soap.server.endpoint.adapter.method.SoapMethodArgumentResolver
org.springframework.ws.server.endpoint.adapter.method.MethodReturnValueHandler=org.springframework.ws.server.endpoint.adapter.method.Dom4jPayloadMethodProcessor,\
org.springframework.ws.server.endpoint.adapter.method.DomPayloadMethodProcessor,\
org.springframework.ws.server.endpoint.adapter.method.JDomPayloadMethodProcessor,\
org.springframework.ws.server.endpoint.adapter.method.SourcePayloadMethodProcessor

View File

@@ -67,6 +67,16 @@ public class DefaultMethodEndpointAdapterTest {
exceptionEndpoint = new MethodEndpoint(this, "exception", String.class);
}
@Test
public void initDefaultStrategies() throws Exception {
adapter = new DefaultMethodEndpointAdapter();
adapter.setBeanClassLoader(DefaultMethodEndpointAdapterTest.class.getClassLoader());
adapter.afterPropertiesSet();
assertFalse("No default MethodArgumentResolvers loaded", adapter.getMethodArgumentResolvers().isEmpty());
assertFalse("No default MethodReturnValueHandlers loaded", adapter.getMethodReturnValueHandlers().isEmpty());
}
@Test
public void supportsSupported() throws Exception {
expect(argumentResolver1.supportsParameter(isA(MethodParameter.class))).andReturn(true);

View File

@@ -14,9 +14,11 @@
* limitations under the License.
*/
package org.springframework.ws.server.endpoint.adapter.method;
package org.springframework.ws.server.endpoint.adapter.method.dom;
import org.springframework.core.MethodParameter;
import org.springframework.ws.server.endpoint.adapter.method.AbstractPayloadMethodProcessorTestCase;
import org.springframework.ws.server.endpoint.adapter.method.AbstractPayloadSourceMethodProcessor;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;

View File

@@ -14,13 +14,15 @@
* limitations under the License.
*/
package org.springframework.ws.server.endpoint.adapter.method;
package org.springframework.ws.server.endpoint.adapter.method.dom;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.springframework.core.MethodParameter;
import org.springframework.ws.server.endpoint.adapter.method.AbstractPayloadMethodProcessorTestCase;
import org.springframework.ws.server.endpoint.adapter.method.AbstractPayloadSourceMethodProcessor;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;

View File

@@ -14,9 +14,11 @@
* limitations under the License.
*/
package org.springframework.ws.server.endpoint.adapter.method;
package org.springframework.ws.server.endpoint.adapter.method.dom;
import org.springframework.core.MethodParameter;
import org.springframework.ws.server.endpoint.adapter.method.AbstractPayloadMethodProcessorTestCase;
import org.springframework.ws.server.endpoint.adapter.method.AbstractPayloadSourceMethodProcessor;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;

View File

@@ -14,9 +14,11 @@
* limitations under the License.
*/
package org.springframework.ws.server.endpoint.adapter.method;
package org.springframework.ws.server.endpoint.adapter.method.dom;
import org.springframework.core.MethodParameter;
import org.springframework.ws.server.endpoint.adapter.method.AbstractPayloadMethodProcessorTestCase;
import org.springframework.ws.server.endpoint.adapter.method.AbstractPayloadSourceMethodProcessor;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;

View File

@@ -0,0 +1,115 @@
/*
* 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.adapter.method.jaxb;
import java.io.IOException;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlType;
import javax.xml.namespace.QName;
import org.springframework.core.MethodParameter;
import org.springframework.ws.MockWebServiceMessage;
import org.springframework.ws.MockWebServiceMessageFactory;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.DefaultMessageContext;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
import org.junit.Before;
import org.junit.Test;
import org.xml.sax.SAXException;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/** @author Arjen Poutsma */
public class JaxbElementPayloadMethodProcessorTest {
private JaxbElementPayloadMethodProcessor processor;
private MethodParameter supportedParameter;
private MethodParameter supportedReturnType;
@Before
public void setUp() throws Exception {
processor = new JaxbElementPayloadMethodProcessor();
supportedParameter = new MethodParameter(getClass().getMethod("supported", JAXBElement.class), 0);
supportedReturnType = new MethodParameter(getClass().getMethod("supported", JAXBElement.class), -1);
}
@Test
public void supportsParameter() {
assertTrue("processor does not support @JAXBElement parameter",
processor.supportsParameter(supportedParameter));
}
@Test
public void supportsReturnType() {
assertTrue("processor does not support @JAXBElement return type",
processor.supportsReturnType(supportedReturnType));
}
@Test
public void resolveArgument() throws JAXBException {
WebServiceMessage request = new MockWebServiceMessage("<myType><string>Foo</string></myType>");
MessageContext messageContext = new DefaultMessageContext(request, new MockWebServiceMessageFactory());
JAXBElement<?> result = processor.resolveArgument(messageContext, supportedParameter);
assertTrue("result not a MyType", result.getValue() instanceof MyType);
MyType type = (MyType) result.getValue();
assertEquals("invalid result", "Foo", type.getString());
}
@Test
public void handleReturnValue() throws JAXBException, IOException, SAXException {
MessageContext messageContext = new DefaultMessageContext(new MockWebServiceMessageFactory());
MyType type = new MyType();
type.setString("Foo");
JAXBElement<MyType> element = new JAXBElement<MyType>(new QName("type"), MyType.class, type);
processor.handleReturnValue(messageContext, supportedReturnType, element);
assertTrue("context has no response", messageContext.hasResponse());
MockWebServiceMessage response = (MockWebServiceMessage) messageContext.getResponse();
assertXMLEqual("<type><string>Foo</string></type>", response.getPayloadAsString());
}
@ResponsePayload
public JAXBElement<MyType> supported(@RequestPayload JAXBElement<MyType> element) {
return element;
}
@XmlType
public static class MyType {
private String string;
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
}
}

View File

@@ -0,0 +1,143 @@
/*
* 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.adapter.method.jaxb;
import java.io.IOException;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import org.springframework.core.MethodParameter;
import org.springframework.ws.MockWebServiceMessage;
import org.springframework.ws.MockWebServiceMessageFactory;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.DefaultMessageContext;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
import org.junit.Before;
import org.junit.Test;
import org.xml.sax.SAXException;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class XmlRootElementPayloadMethodProcessorTest {
private XmlRootElementPayloadMethodProcessor processor;
private MethodParameter rootElementParameter;
private MethodParameter typeParameter;
private MethodParameter rootElementReturnType;
@Before
public void setUp() throws Exception {
processor = new XmlRootElementPayloadMethodProcessor();
rootElementParameter = new MethodParameter(getClass().getMethod("rootElement", MyRootElement.class), 0);
typeParameter = new MethodParameter(getClass().getMethod("type", MyType.class), 0);
rootElementReturnType = new MethodParameter(getClass().getMethod("rootElement", MyRootElement.class), -1);
}
@Test
public void supportsParameter() {
assertTrue("processor does not support @XmlRootElement parameter",
processor.supportsParameter(rootElementParameter));
assertTrue("processor does not support @XmlType parameter", processor.supportsParameter(typeParameter));
}
@Test
public void supportsReturnType() {
assertTrue("processor does not support @XmlRootElement return type",
processor.supportsReturnType(rootElementReturnType));
}
@Test
public void resolveArgumentRootElement() throws JAXBException {
WebServiceMessage request = new MockWebServiceMessage("<myRootElement><string>Foo</string></myRootElement>");
MessageContext messageContext = new DefaultMessageContext(request, new MockWebServiceMessageFactory());
Object result = processor.resolveArgument(messageContext, rootElementParameter);
assertTrue("result not a MyRootElement", result instanceof MyRootElement);
MyRootElement rootElement = (MyRootElement) result;
assertEquals("invalid result", "Foo", rootElement.getString());
}
@Test
public void resolveArgumentType() throws JAXBException {
WebServiceMessage request = new MockWebServiceMessage("<myType><string>Foo</string></myType>");
MessageContext messageContext = new DefaultMessageContext(request, new MockWebServiceMessageFactory());
Object result = processor.resolveArgument(messageContext, typeParameter);
assertTrue("result not a MyType", result instanceof MyType);
MyType type = (MyType) result;
assertEquals("invalid result", "Foo", type.getString());
}
@Test
public void handleReturnValue() throws JAXBException, IOException, SAXException {
MessageContext messageContext = new DefaultMessageContext(new MockWebServiceMessageFactory());
MyRootElement rootElement = new MyRootElement();
rootElement.setString("Foo");
processor.handleReturnValue(messageContext, rootElementReturnType, rootElement);
assertTrue("context has no response", messageContext.hasResponse());
MockWebServiceMessage response = (MockWebServiceMessage) messageContext.getResponse();
assertXMLEqual("<myRootElement><string>Foo</string></myRootElement>", response.getPayloadAsString());
}
@ResponsePayload
public MyRootElement rootElement(@RequestPayload MyRootElement rootElement) {
return rootElement;
}
public void type(@RequestPayload MyType type) {
}
@XmlRootElement
public static class MyRootElement {
private String string;
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
}
@XmlType
public static class MyType {
private String string;
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
}
}

View File

@@ -7,6 +7,7 @@ Import-Template:
javax.activation.*;version="[1.1.0, 2.0.0)",
javax.servlet.*;version="[2.4.0, 3.0.0)",
javax.wsdl.*;version="[1.6.1, 2.0.0)";resolution:=optional,
javax.xml.bind.*;version="0";resolution:=optional,
javax.xml.namespace.*;version="0",
javax.xml.parsers.*;version="0",
javax.xml.transform.*;version="0",

View File

@@ -16,7 +16,6 @@
package org.springframework.xml.transform;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
@@ -44,7 +43,6 @@ import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.ext.LexicalHandler;
@@ -232,8 +230,7 @@ public abstract class TraxUtils {
* @param source source to look at
* @param callback the callback to invoke for each kind of source
*/
public static void doWithSource(Source source, SourceCallback callback)
throws XMLStreamException, IOException, SAXException {
public static void doWithSource(Source source, SourceCallback callback) throws Exception {
if (source instanceof DOMSource) {
callback.domSource(((DOMSource) source).getNode());
}
@@ -281,8 +278,7 @@ public abstract class TraxUtils {
* @param result result to look at
* @param callback the callback to invoke for each kind of result
*/
public static void doWithResult(Result result, ResultCallback callback)
throws XMLStreamException, IOException, SAXException {
public static void doWithResult(Result result, ResultCallback callback) throws Exception{
if (result instanceof DOMResult) {
callback.domResult(((DOMResult) result).getNode());
}
@@ -335,7 +331,7 @@ public abstract class TraxUtils {
*
* @param node the node
*/
void domSource(Node node);
void domSource(Node node) throws Exception;
/**
* Perform an operation on the {@code XMLReader} and {@code InputSource} contained in a {@link SAXSource}.
@@ -343,7 +339,7 @@ public abstract class TraxUtils {
* @param reader the reader, can be {@code null}
* @param inputSource the input source, can be {@code null}
*/
void saxSource(XMLReader reader, InputSource inputSource) throws IOException, SAXException;
void saxSource(XMLReader reader, InputSource inputSource) throws Exception;
/**
* Perform an operation on the {@code XMLEventReader} contained in a JAXP 1.4 {@link StAXSource} or Spring
@@ -351,7 +347,7 @@ public abstract class TraxUtils {
*
* @param eventReader the reader
*/
void staxSource(XMLEventReader eventReader) throws XMLStreamException;
void staxSource(XMLEventReader eventReader) throws Exception;
/**
* Perform an operation on the {@code XMLStreamReader} contained in a JAXP 1.4 {@link StAXSource} or Spring
@@ -359,21 +355,21 @@ public abstract class TraxUtils {
*
* @param streamReader the reader
*/
void staxSource(XMLStreamReader streamReader) throws XMLStreamException;
void staxSource(XMLStreamReader streamReader) throws Exception;
/**
* Perform an operation on the {@code InputStream} contained in a {@link StreamSource}.
*
* @param inputStream the input stream
*/
void streamSource(InputStream inputStream) throws IOException;
void streamSource(InputStream inputStream) throws Exception;
/**
* Perform an operation on the {@code Reader} contained in a {@link StreamSource}.
*
* @param reader the reader
*/
void streamSource(Reader reader) throws IOException;
void streamSource(Reader reader) throws Exception;
}
/**
@@ -388,7 +384,7 @@ public abstract class TraxUtils {
*
* @param node the node
*/
void domResult(Node node);
void domResult(Node node) throws Exception;
/**
* Perform an operation on the {@code ContentHandler} and {@code LexicalHandler} contained in a {@link
@@ -397,7 +393,7 @@ public abstract class TraxUtils {
* @param contentHandler the content handler
* @param lexicalHandler the lexicalHandler, can be {@code null}
*/
void saxResult(ContentHandler contentHandler, LexicalHandler lexicalHandler) throws IOException, SAXException;
void saxResult(ContentHandler contentHandler, LexicalHandler lexicalHandler) throws Exception;
/**
* Perform an operation on the {@code XMLEventWriter} contained in a JAXP 1.4 {@link StAXResult} or Spring
@@ -405,7 +401,7 @@ public abstract class TraxUtils {
*
* @param eventWriter the writer
*/
void staxResult(XMLEventWriter eventWriter) throws XMLStreamException;
void staxResult(XMLEventWriter eventWriter) throws Exception;
/**
* Perform an operation on the {@code XMLStreamWriter} contained in a JAXP 1.4 {@link StAXResult} or Spring
@@ -413,21 +409,21 @@ public abstract class TraxUtils {
*
* @param streamWriter the writer
*/
void staxResult(XMLStreamWriter streamWriter) throws XMLStreamException;
void staxResult(XMLStreamWriter streamWriter) throws Exception;
/**
* Perform an operation on the {@code OutputStream} contained in a {@link StreamResult}.
*
* @param outputStream the output stream
*/
void streamResult(OutputStream outputStream) throws IOException;
void streamResult(OutputStream outputStream) throws Exception;
/**
* Perform an operation on the {@code Writer} contained in a {@link StreamResult}.
*
* @param writer the writer
*/
void streamResult(Writer writer) throws IOException;
void streamResult(Writer writer) throws Exception;
}
/** Inner class to avoid a static JAXP 1.4 dependency. */