This commit is contained in:
Arjen Poutsma
2007-11-05 22:56:26 +00:00
parent 47760ade38
commit 02541be5ff
12 changed files with 535 additions and 77 deletions

View File

@@ -1,4 +1,5 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>spring-ws</artifactId>
<groupId>org.springframework.ws</groupId>
@@ -39,6 +40,10 @@
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-oxm-tiger</artifactId>
</dependency>
<!-- Spring dependencies -->
<dependency>
<groupId>org.springframework</groupId>
@@ -73,4 +78,4 @@
<version>2.2</version>
</dependency>
</dependencies>
</project>
</project>

View File

@@ -0,0 +1,108 @@
/*
* Copyright 2007 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;
import java.lang.reflect.Method;
import org.springframework.oxm.GenericMarshaller;
import org.springframework.oxm.GenericUnmarshaller;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.server.endpoint.MethodEndpoint;
/**
* Subclass of {@link MarshallingMethodEndpointAdapter} that supports {@link GenericMarshaller} and {@link
* GenericUnmarshaller}. More specifically, this adapter is aware of the {@link Method#getGenericParameterTypes()} and
* {@link Method#getGenericReturnType()}.
* <p/>
* Prefer to use this adapter rather than the plain {@link MarshallingMethodEndpointAdapter} in combination with Java 5
* marshallers, such as the {@link Jaxb2Marshaller}.
*
* @author Arjen Poutsma
* @since 1.0.2
*/
public class GenericMarshallingMethodEndpointAdapter extends MarshallingMethodEndpointAdapter {
/**
* Creates a new <code>GenericMarshallingMethodEndpointAdapter</code>. The {@link Marshaller} and {@link
* Unmarshaller} must be injected using properties.
*
* @see #setMarshaller(org.springframework.oxm.Marshaller)
* @see #setUnmarshaller(org.springframework.oxm.Unmarshaller)
*/
public GenericMarshallingMethodEndpointAdapter() {
}
/**
* Creates a new <code>GenericMarshallingMethodEndpointAdapter</code> with the given marshaller. If the given {@link
* Marshaller} also implements the {@link Unmarshaller} interface, it is used for both marshalling and
* unmarshalling. Otherwise, an exception is thrown.
* <p/>
* Note that all {@link Marshaller} implementations in Spring-WS also implement the {@link Unmarshaller} interface,
* so that you can safely use this constructor.
*
* @param marshaller object used as marshaller and unmarshaller
* @throws IllegalArgumentException when <code>marshaller</code> does not implement the {@link Unmarshaller}
* interface
*/
public GenericMarshallingMethodEndpointAdapter(Marshaller marshaller) {
super(marshaller);
}
/**
* Creates a new <code>GenericMarshallingMethodEndpointAdapter</code> with the given marshaller and unmarshaller.
*
* @param marshaller the marshaller to use
* @param unmarshaller the unmarshaller to use
*/
public GenericMarshallingMethodEndpointAdapter(Marshaller marshaller, Unmarshaller unmarshaller) {
super(marshaller, unmarshaller);
}
protected boolean supportsInternal(MethodEndpoint methodEndpoint) {
Method method = methodEndpoint.getMethod();
return supportsReturnType(method) && supportsParameters(method);
}
private boolean supportsReturnType(Method method) {
if (Void.TYPE.equals(method.getReturnType())) {
return true;
}
else {
if (getMarshaller() instanceof GenericMarshaller) {
return ((GenericMarshaller) getMarshaller()).supports(method.getGenericReturnType());
}
else {
return getMarshaller().supports(method.getReturnType());
}
}
}
private boolean supportsParameters(Method method) {
if (method.getParameterTypes().length != 1) {
return false;
}
else if (getUnmarshaller() instanceof GenericUnmarshaller) {
GenericUnmarshaller genericUnmarshaller = (GenericUnmarshaller) getUnmarshaller();
return genericUnmarshaller.supports(method.getGenericParameterTypes()[0]);
}
else {
return getUnmarshaller().supports(method.getParameterTypes()[0]);
}
}
}

View File

@@ -0,0 +1,185 @@
package org.springframework.ws.server.endpoint.adapter;
import java.lang.reflect.Method;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import junit.framework.TestCase;
import static org.easymock.EasyMock.*;
import org.springframework.oxm.GenericMarshaller;
import org.springframework.oxm.GenericUnmarshaller;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.context.DefaultMessageContext;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.xml.transform.StringResult;
import org.springframework.xml.transform.StringSource;
public class GenericMarshallingMethodEndpointAdapterTest extends TestCase {
private GenericMarshallingMethodEndpointAdapter adapter;
private boolean noResponseInvoked;
private GenericMarshaller marshallerMock;
private GenericUnmarshaller unmarshallerMock;
private boolean responseInvoked;
protected void setUp() throws Exception {
adapter = new GenericMarshallingMethodEndpointAdapter();
marshallerMock = createMock(GenericMarshaller.class);
adapter.setMarshaller(marshallerMock);
unmarshallerMock = createMock(GenericUnmarshaller.class);
adapter.setUnmarshaller(unmarshallerMock);
adapter.afterPropertiesSet();
}
public void testNoResponse() throws Exception {
WebServiceMessage messageMock = createMock(WebServiceMessage.class);
expect(messageMock.getPayloadSource()).andReturn(new StringSource("<request/>"));
WebServiceMessageFactory factoryMock = createMock(WebServiceMessageFactory.class);
MessageContext messageContext = new DefaultMessageContext(messageMock, factoryMock);
Method noResponse = getClass().getMethod("noResponse", MyGenericType.class);
MethodEndpoint methodEndpoint = new MethodEndpoint(this, noResponse);
expect(unmarshallerMock.unmarshal(isA(Source.class))).andReturn(new MyGenericType<MyType>());
replay(marshallerMock, unmarshallerMock, messageMock, factoryMock);
assertFalse("Method invoked", noResponseInvoked);
adapter.invoke(messageContext, methodEndpoint);
assertTrue("Method not invoked", noResponseInvoked);
verify(marshallerMock, unmarshallerMock, messageMock, factoryMock);
}
public void testNoRequestPayload() throws Exception {
WebServiceMessage messageMock = createMock(WebServiceMessage.class);
expect(messageMock.getPayloadSource()).andReturn(null);
WebServiceMessageFactory factoryMock = createMock(WebServiceMessageFactory.class);
MessageContext messageContext = new DefaultMessageContext(messageMock, factoryMock);
Method noResponse = getClass().getMethod("noResponse", MyGenericType.class);
MethodEndpoint methodEndpoint = new MethodEndpoint(this, noResponse);
replay(marshallerMock, unmarshallerMock, messageMock, factoryMock);
assertFalse("Method invoked", noResponseInvoked);
adapter.invoke(messageContext, methodEndpoint);
assertTrue("Method not invoked", noResponseInvoked);
verify(marshallerMock, unmarshallerMock, messageMock, factoryMock);
}
public void testResponse() throws Exception {
WebServiceMessage requestMock = createMock(WebServiceMessage.class);
expect(requestMock.getPayloadSource()).andReturn(new StringSource("<request/>"));
WebServiceMessage responseMock = createMock(WebServiceMessage.class);
expect(responseMock.getPayloadResult()).andReturn(new StringResult());
WebServiceMessageFactory factoryMock = createMock(WebServiceMessageFactory.class);
expect(factoryMock.createWebServiceMessage()).andReturn(responseMock);
MessageContext messageContext = new DefaultMessageContext(requestMock, factoryMock);
Method response = getClass().getMethod("response", MyGenericType.class);
MethodEndpoint methodEndpoint = new MethodEndpoint(this, response);
expect(unmarshallerMock.unmarshal(isA(Source.class))).andReturn(new MyGenericType<MyType>());
marshallerMock.marshal(isA(MyGenericType.class), isA(Result.class));
replay(marshallerMock, unmarshallerMock, requestMock, responseMock, factoryMock);
assertFalse("Method invoked", responseInvoked);
adapter.invoke(messageContext, methodEndpoint);
assertTrue("Method not invoked", responseInvoked);
verify(marshallerMock, unmarshallerMock, requestMock, responseMock, factoryMock);
}
public void testSupportedNoResponse() throws NoSuchMethodException {
Method noResponse = getClass().getMethod("noResponse", MyGenericType.class);
MethodEndpoint methodEndpoint = new MethodEndpoint(this, noResponse);
expect(unmarshallerMock.supports(noResponse.getGenericParameterTypes()[0])).andReturn(true);
replay(marshallerMock, unmarshallerMock);
assertTrue("Method unsupported", adapter.supportsInternal(methodEndpoint));
verify(marshallerMock, unmarshallerMock);
}
public void testSupportedResponse() throws NoSuchMethodException {
Method response = getClass().getMethod("response", MyGenericType.class);
MethodEndpoint methodEndpoint = new MethodEndpoint(this, response);
expect(unmarshallerMock.supports(response.getGenericParameterTypes()[0])).andReturn(true);
expect(marshallerMock.supports(response.getGenericReturnType())).andReturn(true);
replay(marshallerMock, unmarshallerMock);
assertTrue("Method unsupported", adapter.supportsInternal(methodEndpoint));
verify(marshallerMock, unmarshallerMock);
}
public void testUnsupportedMethodMultipleParams() throws NoSuchMethodException {
Method unsupported = getClass().getMethod("unsupportedMultipleParams", String.class, String.class);
replay(marshallerMock, unmarshallerMock);
assertFalse("Method supported", adapter.supportsInternal(new MethodEndpoint(this, unsupported)));
verify(marshallerMock, unmarshallerMock);
}
public void testUnsupportedMethodWrongParam() throws NoSuchMethodException {
Method unsupported = getClass().getMethod("unsupportedWrongParam", String.class);
expect(unmarshallerMock.supports(unsupported.getGenericParameterTypes()[0])).andReturn(false);
expect(marshallerMock.supports(unsupported.getGenericReturnType())).andReturn(true);
replay(marshallerMock, unmarshallerMock);
assertFalse("Method supported", adapter.supportsInternal(new MethodEndpoint(this, unsupported)));
verify(marshallerMock, unmarshallerMock);
}
public void testUnsupportedMethodWrongReturnType() throws NoSuchMethodException {
Method unsupported = getClass().getMethod("unsupportedWrongParam", String.class);
expect(marshallerMock.supports(unsupported.getGenericReturnType())).andReturn(false);
replay(marshallerMock, unmarshallerMock);
assertFalse("Method supported", adapter.supportsInternal(new MethodEndpoint(this, unsupported)));
verify(marshallerMock, unmarshallerMock);
}
public void noResponse(MyGenericType<MyType> type) {
noResponseInvoked = true;
}
public MyGenericType<MyType> response(MyGenericType<MyType> type) {
responseInvoked = true;
return type;
}
public void unsupportedMultipleParams(String s1, String s2) {
}
public String unsupportedWrongParam(String s) {
return s;
}
private static class MyType {
}
private static class MyGenericType<T> {
}
}

View File

@@ -19,6 +19,7 @@ package org.springframework.ws.server.endpoint;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.springframework.core.JdkVersion;
import org.springframework.util.Assert;
/**
@@ -120,6 +121,19 @@ public final class MethodEndpoint {
}
public String toString() {
return this.method.toString();
if (JdkVersion.getMajorJavaVersion() <= JdkVersion.JAVA_14) {
return this.method.toString();
}
else {
return GenericToStringProvider.toString(method);
}
}
/** Inner class to avoid a static JDK 1.5 dependency for generic string generation. */
private static class GenericToStringProvider {
public static String toString(Method method) {
return method.toGenericString();
}
}
}

View File

@@ -56,14 +56,6 @@ public class MarshallingMethodEndpointAdapter extends AbstractMethodEndpointAdap
private Unmarshaller unmarshaller;
public void setMarshaller(Marshaller marshaller) {
this.marshaller = marshaller;
}
public void setUnmarshaller(Unmarshaller unmarshaller) {
this.unmarshaller = unmarshaller;
}
/**
* Creates a new <code>MarshallingMethodEndpointAdapter</code>. The {@link Marshaller} and {@link Unmarshaller} must
* be injected using properties.
@@ -94,8 +86,8 @@ public class MarshallingMethodEndpointAdapter extends AbstractMethodEndpointAdap
"MarshallingMethodEndpointAdapter(Marshaller, Unmarshaller) constructor.");
}
else {
this.marshaller = marshaller;
this.unmarshaller = (Unmarshaller) marshaller;
this.setMarshaller(marshaller);
this.setUnmarshaller((Unmarshaller) marshaller);
}
}
@@ -108,13 +100,58 @@ public class MarshallingMethodEndpointAdapter extends AbstractMethodEndpointAdap
public MarshallingMethodEndpointAdapter(Marshaller marshaller, Unmarshaller unmarshaller) {
Assert.notNull(marshaller, "marshaller must not be null");
Assert.notNull(unmarshaller, "unmarshaller must not be null");
this.setMarshaller(marshaller);
this.setUnmarshaller(unmarshaller);
}
/** Returns the marshaller used for transforming objects into XML. */
public Marshaller getMarshaller() {
return marshaller;
}
/** Sets the marshaller used for transforming objects into XML. */
public final void setMarshaller(Marshaller marshaller) {
this.marshaller = marshaller;
}
/** Returns the unmarshaller used for transforming XML into objects. */
public Unmarshaller getUnmarshaller() {
return unmarshaller;
}
/** Sets the unmarshaller used for transforming XML into objects. */
public final void setUnmarshaller(Unmarshaller unmarshaller) {
this.unmarshaller = unmarshaller;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(marshaller, "marshaller is required");
Assert.notNull(unmarshaller, "unmarshaller is required");
Assert.notNull(getMarshaller(), "marshaller is required");
Assert.notNull(getUnmarshaller(), "unmarshaller is required");
}
protected void invokeInternal(MessageContext messageContext, MethodEndpoint methodEndpoint) throws Exception {
WebServiceMessage request = messageContext.getRequest();
Object requestObject = unmarshalRequest(request);
Object responseObject = methodEndpoint.invoke(new Object[]{requestObject});
if (responseObject != null) {
WebServiceMessage response = messageContext.getResponse();
marshalResponse(responseObject, response);
}
}
private Object unmarshalRequest(WebServiceMessage request) throws IOException {
Object requestObject = MarshallingUtils.unmarshal(getUnmarshaller(), request);
if (logger.isDebugEnabled()) {
logger.debug("Unmarshalled payload request to [" + requestObject + "]");
}
return requestObject;
}
private void marshalResponse(Object responseObject, WebServiceMessage response) throws IOException {
if (logger.isDebugEnabled()) {
logger.debug("Marshalling [" + responseObject + "] to response payload");
}
MarshallingUtils.marshal(getMarshaller(), responseObject, response);
}
/**
@@ -126,34 +163,19 @@ public class MarshallingMethodEndpointAdapter extends AbstractMethodEndpointAdap
*/
protected boolean supportsInternal(MethodEndpoint methodEndpoint) {
Method method = methodEndpoint.getMethod();
return (Void.TYPE.isAssignableFrom(method.getReturnType()) || marshaller.supports(method.getReturnType())) &&
method.getParameterTypes().length == 1 && unmarshaller.supports(method.getParameterTypes()[0]);
return supportsReturnType(method) && supportsParameters(method);
}
protected void invokeInternal(MessageContext messageContext, MethodEndpoint methodEndpoint) throws Exception {
WebServiceMessage request = messageContext.getRequest();
Object requestObject = unmarshalRequest(request);
Object responseObject = methodEndpoint.invoke(new Object[]{requestObject});
if (responseObject != null) {
WebServiceMessage response = messageContext.getResponse();
marshalResponse(responseObject, response);
private boolean supportsReturnType(Method method) {
return (Void.TYPE.equals(method.getReturnType()) || getMarshaller().supports(method.getReturnType()));
}
private boolean supportsParameters(Method method) {
if (method.getParameterTypes().length != 1) {
return false;
}
}
private Object unmarshalRequest(WebServiceMessage request) throws IOException {
Object requestObject = MarshallingUtils.unmarshal(unmarshaller, request);
if (logger.isDebugEnabled()) {
logger.debug("Unmarshalled payload request to [" + requestObject + "]");
else {
return getUnmarshaller().supports(method.getParameterTypes()[0]);
}
return requestObject;
}
private void marshalResponse(Object responseObject, WebServiceMessage response) throws IOException {
if (logger.isDebugEnabled()) {
logger.debug("Marshalling [" + responseObject + "] to response payload");
}
MarshallingUtils.marshal(marshaller, responseObject, response);
}
}

View File

@@ -160,7 +160,8 @@ public class MarshallingMethodEndpointAdapterTest extends TestCase {
return s;
}
public static class MyType {
private static class MyType {
}
}

View File

@@ -17,6 +17,8 @@
package org.springframework.ws.server.endpoint.adapter;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import junit.framework.TestCase;
import org.springframework.ws.MockWebServiceMessage;
@@ -42,12 +44,12 @@ public class PayloadMethodEndpointAdapterTest extends TestCase {
}
public void testSupportedNoResponse() throws NoSuchMethodException {
MethodEndpoint methodEndpoint = new MethodEndpoint(this, "noResponse", new Class[]{Source.class});
MethodEndpoint methodEndpoint = new MethodEndpoint(this, "noResponse", new Class[]{DOMSource.class});
assertTrue("Method unsupported", adapter.supportsInternal(methodEndpoint));
}
public void testSupportedResponse() throws NoSuchMethodException {
MethodEndpoint methodEndpoint = new MethodEndpoint(this, "response", new Class[]{Source.class});
MethodEndpoint methodEndpoint = new MethodEndpoint(this, "response", new Class[]{StreamSource.class});
assertTrue("Method unsupported", adapter.supportsInternal(methodEndpoint));
}
@@ -67,7 +69,7 @@ public class PayloadMethodEndpointAdapterTest extends TestCase {
}
public void testNoResponse() throws Exception {
MethodEndpoint methodEndpoint = new MethodEndpoint(this, "noResponse", new Class[]{Source.class});
MethodEndpoint methodEndpoint = new MethodEndpoint(this, "noResponse", new Class[]{DOMSource.class});
assertFalse("Method invoked", noResponseInvoked);
adapter.invoke(messageContext, methodEndpoint);
assertTrue("Method not invoked", noResponseInvoked);
@@ -76,17 +78,17 @@ public class PayloadMethodEndpointAdapterTest extends TestCase {
public void testResponse() throws Exception {
WebServiceMessage request = new MockWebServiceMessage("<request/>");
messageContext = new DefaultMessageContext(request, new MockWebServiceMessageFactory());
MethodEndpoint methodEndpoint = new MethodEndpoint(this, "response", new Class[]{Source.class});
MethodEndpoint methodEndpoint = new MethodEndpoint(this, "response", new Class[]{StreamSource.class});
assertFalse("Method invoked", responseInvoked);
adapter.invoke(messageContext, methodEndpoint);
assertTrue("Method not invoked", responseInvoked);
}
public void noResponse(Source request) {
public void noResponse(DOMSource request) {
noResponseInvoked = true;
}
public Source response(Source request) {
public Source response(StreamSource request) {
responseInvoked = true;
return request;
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2007 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.oxm;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
/**
* Extension of the {@link Marshaller} interface that supports Java 5 generics. More specifically, this marshaller adds
* support for the new {@link Type} hierarchy, returned by methods such as {@link Method#getGenericParameterTypes()} and
* {@link Method#getGenericReturnType()}.
*
* @author Arjen Poutsma
* @since 1.0.2
*/
public interface GenericMarshaller extends Marshaller {
/**
* Indicates whether this marshaller can marshal instances of the supplied type.
*
* @param type the type that this marshaller is being asked if it can marshal
* @return <code>true</code> if this marshaller can indeed marshal instances of the supplied type;
* <code>false</code> otherwise
*/
boolean supports(Type type);
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2007 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.oxm;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
/**
* Extension of the {@link Unmarshaller} interface that supports Java 5 generics. More specifically, this unmarshaller
* adds support for the new {@link Type} hierarchy, returned by methods such as {@link
* Method#getGenericParameterTypes()} and {@link Method#getGenericReturnType()}.
*
* @author Arjen Poutsma
* @since 1.0.2
*/
public interface GenericUnmarshaller extends Unmarshaller {
/**
* Indicates whether this unmarshaller can unmarshal instances of the supplied type.
*
* @param type the type that this unmarshaller is being asked if it can marshal
* @return <code>true</code> if this unmarshaller can indeed unmarshal to the supplied type; <code>false</code>
* otherwise
*/
boolean supports(Type type);
}

View File

@@ -21,11 +21,13 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Arrays;
import java.util.Map;
import java.util.UUID;
import javax.activation.DataHandler;
@@ -34,9 +36,10 @@ import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.JAXBIntrospector;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.attachment.AttachmentMarshaller;
import javax.xml.bind.attachment.AttachmentUnmarshaller;
@@ -45,6 +48,8 @@ import javax.xml.transform.Source;
import javax.xml.validation.Schema;
import org.springframework.core.io.Resource;
import org.springframework.oxm.GenericMarshaller;
import org.springframework.oxm.GenericUnmarshaller;
import org.springframework.oxm.XmlMappingException;
import org.springframework.oxm.mime.MimeContainer;
import org.springframework.oxm.mime.MimeMarshaller;
@@ -77,7 +82,8 @@ import org.springframework.xml.validation.SchemaLoaderUtils;
* @see #setAdapters(javax.xml.bind.annotation.adapters.XmlAdapter[])
* @since 1.0.0
*/
public class Jaxb2Marshaller extends AbstractJaxbMarshaller implements MimeMarshaller, MimeUnmarshaller {
public class Jaxb2Marshaller extends AbstractJaxbMarshaller
implements MimeMarshaller, MimeUnmarshaller, GenericMarshaller, GenericUnmarshaller {
private Resource[] schemaResources;
@@ -97,8 +103,6 @@ public class Jaxb2Marshaller extends AbstractJaxbMarshaller implements MimeMarsh
private boolean mtomEnabled = false;
private Map<Class, Boolean> supportedClasses = new HashMap<Class, Boolean>();
/**
* Sets the <code>XmlAdapter</code>s to be registered with the JAXB <code>Marshaller</code> and
* <code>Unmarshaller</code>
@@ -163,28 +167,56 @@ public class Jaxb2Marshaller extends AbstractJaxbMarshaller implements MimeMarsh
this.unmarshallerListener = unmarshallerListener;
}
public boolean supports(Class clazz) {
if (JAXBElement.class.isAssignableFrom(clazz)) {
return true;
public boolean supports(Type type) {
if (type instanceof Class) {
return supportsInternal((Class) type, true);
}
else if (!supportedClasses.containsKey(clazz)) {
boolean supported = false;
Object instance = null;
try {
instance = clazz.newInstance();
else if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
if (JAXBElement.class.equals(parameterizedType.getRawType())) {
Type[] typeArguments = parameterizedType.getActualTypeArguments();
for (int i = 0; i < typeArguments.length; i++) {
if (typeArguments[i] instanceof Class) {
if (!supportsInternal((Class) typeArguments[i], false)) {
return false;
}
}
else if (!supports(typeArguments[i])) {
return false;
}
}
return true;
}
catch (InstantiationException e) {
// not supported
}
catch (IllegalAccessException e) {
// not supported
}
JAXBIntrospector introspector = getJaxbContext().createJAXBIntrospector();
supported = introspector.isElement(instance);
supportedClasses.put(clazz, supported);
}
return supportedClasses.get(clazz);
return false;
}
public boolean supports(Class clazz) {
return supportsInternal(clazz, true);
}
private boolean supportsInternal(Class<?> clazz, boolean checkForXmlRootElement) {
if (checkForXmlRootElement && clazz.getAnnotation(XmlRootElement.class) == null) {
return false;
}
if (clazz.getAnnotation(XmlType.class) == null) {
return false;
}
if (StringUtils.hasLength(getContextPath())) {
String className = ClassUtils.getQualifiedName(clazz);
int lastDotIndex = className.lastIndexOf('.');
if (lastDotIndex == -1) {
return false;
}
String packageName = className.substring(0, lastDotIndex);
return getContextPath().startsWith(packageName);
}
else if (!ObjectUtils.isEmpty(classesToBeBound)) {
return Arrays.asList(classesToBeBound).contains(clazz);
}
return false;
}
/*
* JAXBContext
*/

View File

@@ -18,10 +18,12 @@ package org.springframework.oxm.jaxb;
import java.io.ByteArrayOutputStream;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.Collections;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.stream.XMLEventWriter;
@@ -39,6 +41,7 @@ import org.springframework.core.io.Resource;
import org.springframework.oxm.XmlMappingException;
import org.springframework.oxm.jaxb2.FlightType;
import org.springframework.oxm.jaxb2.Flights;
import org.springframework.oxm.jaxb2.ObjectFactory;
import org.springframework.oxm.mime.MimeContainer;
import org.springframework.util.FileCopyUtils;
import org.springframework.xml.transform.StaxResult;
@@ -192,8 +195,16 @@ public class Jaxb2MarshallerTest extends XMLTestCase {
}
public void testSupports() throws Exception {
assertTrue("Jaxb2Marshaller does not support Flights", marshaller.supports(Flights.class));
assertTrue("Jaxb2Marshaller does not support JAXBElement", marshaller.supports(JAXBElement.class));
Method createFlights = ObjectFactory.class.getDeclaredMethod("createFlights");
assertTrue("Jaxb2Marshaller does not support Flights",
marshaller.supports(createFlights.getGenericReturnType()));
Method createFlight = ObjectFactory.class.getDeclaredMethod("createFlight", FlightType.class);
assertTrue("Jaxb2Marshaller does not support JAXBElement<FlightsType>",
marshaller.supports(createFlight.getGenericReturnType()));
assertFalse("Jaxb2Marshaller supports non-parameterized JAXBElement", marshaller.supports(JAXBElement.class));
JAXBElement<Jaxb2MarshallerTest> testElement =
new JAXBElement<Jaxb2MarshallerTest>(new QName("something"), Jaxb2MarshallerTest.class, null, this);
assertFalse("Jaxb2Marshaller supports wrong JAXBElement", marshaller.supports(testElement.getClass()));
}
public void testMarshalAttachments() throws Exception {

View File

@@ -1,8 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd">
<!-- ===================== ENDPOINTS ===================================== -->
@@ -103,7 +101,7 @@
MarshallingMethodEndpointAdapter.
-->
<bean class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
<bean class="org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter">
<description>
This adapter allows for methods that need and returns marshalled objects. The MarshallingEndpoint
uses JAXB 2 objects.