Support null return value for JAXB

Support null return values for JAXB MethodReturnValueHandlers.\

Issue: SWS-867
This commit is contained in:
Arjen Poutsma
2014-03-20 14:05:24 +01:00
parent 9f4e2937c8
commit 06ff649b74
8 changed files with 98 additions and 44 deletions

View File

@@ -231,10 +231,7 @@ public class DefaultMethodEndpointAdapter extends AbstractMethodEndpointAdapter
Object[] args = getMethodArguments(messageContext, methodEndpoint);
if (logger.isTraceEnabled()) {
StringBuilder builder = new StringBuilder("Invoking [");
builder.append(methodEndpoint).append("] with arguments ");
builder.append(Arrays.asList(args));
logger.trace(builder.toString());
logger.trace("Invoking [" + methodEndpoint + "] with arguments " + Arrays.asList(args));
}
Object returnValue = methodEndpoint.invoke(args);

View File

@@ -151,6 +151,9 @@ public class MarshallingPayloadMethodProcessor extends AbstractPayloadMethodProc
public void handleReturnValue(MessageContext messageContext, MethodParameter returnType, Object returnValue)
throws Exception {
if (returnValue == null) {
return;
}
Marshaller marshaller = getMarshaller();
Assert.state(marshaller != null, "marshaller must not be null");

View File

@@ -42,6 +42,13 @@ import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
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;
import org.springframework.core.MethodParameter;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
@@ -50,12 +57,6 @@ import org.springframework.ws.stream.StreamingPayload;
import org.springframework.ws.stream.StreamingWebServiceMessage;
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;
/**
* Abstract base class for {@link org.springframework.ws.server.endpoint.adapter.method.MethodArgumentResolver
* MethodArgumentResolver} and {@link org.springframework.ws.server.endpoint.adapter.method.MethodReturnValueHandler
@@ -71,7 +72,18 @@ public abstract class AbstractJaxb2PayloadMethodProcessor extends AbstractPayloa
private final ConcurrentMap<Class, JAXBContext> jaxbContexts = new ConcurrentHashMap<Class, JAXBContext>();
/**
@Override
public final void handleReturnValue(MessageContext messageContext,
MethodParameter returnType, Object returnValue) throws Exception {
if (returnValue != null) {
handleReturnValueInternal(messageContext, returnType, returnValue);
}
}
protected abstract void handleReturnValueInternal(MessageContext messageContext,
MethodParameter returnType, Object returnValue) throws Exception;
/**
* Marshals the given {@code jaxbElement} to the response payload of the given message context.
*
* @param messageContext the message context to marshal to

View File

@@ -54,7 +54,8 @@ public class JaxbElementPayloadMethodProcessor extends AbstractJaxb2PayloadMetho
return JAXBElement.class.isAssignableFrom(parameterType);
}
public void handleReturnValue(MessageContext messageContext, MethodParameter returnType, Object returnValue)
@Override
protected void handleReturnValueInternal(MessageContext messageContext, MethodParameter returnType, Object returnValue)
throws JAXBException {
JAXBElement<?> element = (JAXBElement<?>) returnValue;
marshalToResponsePayload(messageContext, element.getDeclaredType(), element);

View File

@@ -60,7 +60,8 @@ public class XmlRootElementPayloadMethodProcessor extends AbstractJaxb2PayloadMe
return parameterType.isAnnotationPresent(XmlRootElement.class);
}
public void handleReturnValue(MessageContext messageContext, MethodParameter returnType, Object returnValue)
@Override
protected void handleReturnValueInternal(MessageContext messageContext, MethodParameter returnType, Object returnValue)
throws JAXBException {
Class<?> parameterType = returnType.getParameterType();
marshalToResponsePayload(messageContext, parameterType, returnValue);

View File

@@ -20,6 +20,11 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.MethodParameter;
import org.springframework.ws.MockWebServiceMessage;
import org.springframework.ws.MockWebServiceMessageFactory;
@@ -29,12 +34,6 @@ import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.ws.server.endpoint.adapter.method.MethodArgumentResolver;
import org.springframework.ws.server.endpoint.adapter.method.MethodReturnValueHandler;
import org.junit.Before;
import org.junit.Test;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
/** @author Arjen Poutsma */
public class DefaultMethodEndpointAdapterTest {
@@ -48,21 +47,25 @@ public class DefaultMethodEndpointAdapterTest {
private MethodEndpoint supportedEndpoint;
private MethodEndpoint nullReturnValue;
private MethodEndpoint unsupportedEndpoint;
private MethodEndpoint exceptionEndpoint;
private String supportedArgument;
@Before
@Before
public void setUp() throws Exception {
adapter = new DefaultMethodEndpointAdapter();
argumentResolver1 = createMock("stringResolver", MethodArgumentResolver.class);
argumentResolver2 = createMock("intResolver", MethodArgumentResolver.class);
returnValueHandler = createMock(MethodReturnValueHandler.class);
adapter.setMethodArgumentResolvers(Arrays.asList(argumentResolver1, argumentResolver2));
adapter.setMethodReturnValueHandlers(Collections.singletonList(returnValueHandler));
adapter.setMethodReturnValueHandlers(
Collections.singletonList(returnValueHandler));
supportedEndpoint = new MethodEndpoint(this, "supported", String.class, Integer.class);
nullReturnValue = new MethodEndpoint(this, "nullReturnValue", String.class);
unsupportedEndpoint = new MethodEndpoint(this, "unsupported", String.class);
exceptionEndpoint = new MethodEndpoint(this, "exception", String.class);
}
@@ -146,6 +149,27 @@ public class DefaultMethodEndpointAdapterTest {
verify(argumentResolver1, argumentResolver2, returnValueHandler);
}
@Test
public void invokeNullReturnValue() throws Exception {
MockWebServiceMessage request = new MockWebServiceMessage("<root xmlns='http://springframework.org'/>");
MessageContext messageContext = new DefaultMessageContext(request, new MockWebServiceMessageFactory());
String value = "Foo";
expect(argumentResolver1.supportsParameter(isA(MethodParameter.class))).andReturn(true);
expect(argumentResolver1.resolveArgument(eq(messageContext), isA(MethodParameter.class))).andReturn(value);
expect(returnValueHandler.supportsReturnType(isA(MethodParameter.class))).andReturn(true);
returnValueHandler.handleReturnValue(eq(messageContext), isA(MethodParameter.class), isNull());
replay(argumentResolver1, argumentResolver2, returnValueHandler);
adapter.invoke(messageContext, nullReturnValue);
assertEquals("Invalid argument passed", value, supportedArgument);
verify(argumentResolver1, argumentResolver2, returnValueHandler);
}
@Test
public void invokeException() throws Exception {
MockWebServiceMessage request = new MockWebServiceMessage("<root xmlns='http://springframework.org'/>");
@@ -177,6 +201,11 @@ public class DefaultMethodEndpointAdapterTest {
}
public String nullReturnValue(String s) {
supportedArgument = s;
return null;
}
public String unsupported(String s) {
return s;
}

View File

@@ -17,7 +17,6 @@
package org.springframework.ws.server.endpoint.adapter.method.jaxb;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlElement;
@@ -26,6 +25,11 @@ import javax.xml.namespace.QName;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.MethodParameter;
import org.springframework.ws.MockWebServiceMessage;
import org.springframework.ws.MockWebServiceMessageFactory;
@@ -38,14 +42,6 @@ import org.springframework.ws.soap.axiom.AxiomSoapMessage;
import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory;
import org.springframework.xml.transform.StringResult;
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 JaxbElementPayloadMethodProcessorTest {
private JaxbElementPayloadMethodProcessor processor;
@@ -88,7 +84,7 @@ public class JaxbElementPayloadMethodProcessorTest {
}
@Test
public void handleReturnValue() throws JAXBException, IOException, SAXException {
public void handleReturnValue() throws Exception {
MessageContext messageContext = new DefaultMessageContext(new MockWebServiceMessageFactory());
MyType type = new MyType();
@@ -101,7 +97,7 @@ public class JaxbElementPayloadMethodProcessorTest {
}
@Test
public void handleReturnValueString() throws JAXBException, IOException, SAXException {
public void handleReturnValueString() throws Exception {
MessageContext messageContext = new DefaultMessageContext(new MockWebServiceMessageFactory());
String s = "Foo";
@@ -112,6 +108,15 @@ public class JaxbElementPayloadMethodProcessorTest {
assertXMLEqual("<string xmlns='http://springframework.org'>Foo</string>", response.getPayloadAsString());
}
@Test
public void handleNullReturnValue() throws Exception {
MessageContext messageContext =
new DefaultMessageContext(new MockWebServiceMessageFactory());
processor.handleReturnValue(messageContext, stringReturnType, null);
assertFalse("context has response", messageContext.hasResponse());
}
@Test
public void handleReturnValueAxiom() throws Exception {
AxiomSoapMessageFactory messageFactory = new AxiomSoapMessageFactory();

View File

@@ -17,7 +17,6 @@
package org.springframework.ws.server.endpoint.adapter.method.jaxb;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@@ -25,6 +24,11 @@ import javax.xml.bind.annotation.XmlType;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.MethodParameter;
import org.springframework.ws.MockWebServiceMessage;
import org.springframework.ws.MockWebServiceMessageFactory;
@@ -37,14 +41,6 @@ import org.springframework.ws.soap.axiom.AxiomSoapMessage;
import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory;
import org.springframework.xml.transform.StringResult;
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;
@@ -67,13 +63,14 @@ public class XmlRootElementPayloadMethodProcessorTest {
public void supportsParameter() {
assertTrue("processor does not support @XmlRootElement parameter",
processor.supportsParameter(rootElementParameter));
assertTrue("processor does not support @XmlType parameter", processor.supportsParameter(typeParameter));
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));
processor.supportsReturnType(rootElementReturnType));
}
@Test
@@ -99,7 +96,7 @@ public class XmlRootElementPayloadMethodProcessorTest {
}
@Test
public void handleReturnValue() throws JAXBException, IOException, SAXException {
public void handleReturnValue() throws Exception {
MessageContext messageContext = new DefaultMessageContext(new MockWebServiceMessageFactory());
MyRootElement rootElement = new MyRootElement();
@@ -110,6 +107,15 @@ public class XmlRootElementPayloadMethodProcessorTest {
assertXMLEqual("<root xmlns='http://springframework.org'><string>Foo</string></root>", response.getPayloadAsString());
}
@Test
public void handleNullReturnValue() throws Exception {
MessageContext messageContext = new DefaultMessageContext(new MockWebServiceMessageFactory());
MyRootElement rootElement = null;
processor.handleReturnValue(messageContext, rootElementReturnType, rootElement);
assertFalse("context has response", messageContext.hasResponse());
}
@Test
public void handleReturnValueAxiom() throws Exception {
AxiomSoapMessageFactory messageFactory = new AxiomSoapMessageFactory();