Support @Repeatable for @SoapAction @PayloadRoot

This commit introduces support for the JDK 8 @Repeatable annotation in
the @SoapAction and @PayloadRoot.

Issue: SWS-877
This commit is contained in:
Arjen Poutsma
2014-07-18 13:03:59 +02:00
parent e67efa79c3
commit fe4747d5fc
6 changed files with 171 additions and 28 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2007 the original author or authors.
* Copyright 2002-2014 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.
@@ -18,6 +18,7 @@ package org.springframework.ws.server.endpoint.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -33,6 +34,7 @@ import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(PayloadRoots.class)
public @interface PayloadRoot {
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2007 the original author or authors.
* Copyright 2002-2014 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.
@@ -18,6 +18,7 @@ package org.springframework.ws.soap.server.endpoint.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -33,6 +34,7 @@ import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(SoapActions.class)
public @interface SoapAction {
/** Signifies the value for the request {@code SOAPAction} header that is handled by the method. */

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2002-2014 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.soap.server.endpoint.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Marks an endpoint method as containing multiple {@link SoapAction SoapActions}.
*
* @author Arjen Poutsma
* @see org.springframework.ws.soap.server.endpoint.mapping.SoapActionAnnotationMethodEndpointMapping
* @since 2.2.1
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SoapActions {
SoapAction[] value();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2005-2014 the original author or authors.
* Copyright 2002-2014 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.
@@ -17,6 +17,8 @@
package org.springframework.ws.soap.server.endpoint.mapping;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
@@ -29,6 +31,7 @@ import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.server.SoapEndpointInvocationChain;
import org.springframework.ws.soap.server.SoapEndpointMapping;
import org.springframework.ws.soap.server.endpoint.annotation.SoapAction;
import org.springframework.ws.soap.server.endpoint.annotation.SoapActions;
/**
* Implementation of the {@link org.springframework.ws.server.EndpointMapping} interface that uses the {@link
@@ -112,4 +115,24 @@ public class SoapActionAnnotationMethodEndpointMapping extends AbstractAnnotatio
SoapAction soapAction = AnnotationUtils.findAnnotation(method, SoapAction.class);
return soapAction != null ? soapAction.value() : null;
}
@Override
protected List<String> getLookupKeysForMethod(Method method) {
List<String> result = new ArrayList<String>();
SoapActions soapActions = AnnotationUtils.findAnnotation(method,
SoapActions.class);
if (soapActions != null) {
for (SoapAction soapAction : soapActions.value()) {
result.add(soapAction.value());
}
}
else {
SoapAction soapAction = AnnotationUtils.findAnnotation(method, SoapAction.class);
if (soapAction != null) {
result.add(soapAction.value());
}
}
return result;
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2005-2011 the original author or authors.
* Copyright 2002-2014 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
* 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,
@@ -23,6 +23,11 @@ import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.Source;
import org.apache.commons.logging.LogFactory;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
@@ -42,12 +47,6 @@ import org.springframework.ws.soap.saaj.SaajSoapMessage;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
import org.springframework.ws.soap.server.SoapMessageDispatcher;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("payloadRootAnnotationMethodEndpointMapping.xml")
public class PayloadRootAnnotationMethodEndpointMappingTest {
@@ -69,7 +68,7 @@ public class PayloadRootAnnotationMethodEndpointMappingTest {
@Test
public void registrationMultiple() throws NoSuchMethodException {
Method doItMultiple = MyEndpoint.class.getMethod("doItMultiple", Source.class);
Method doItMultiple = MyEndpoint.class.getMethod("doItMultiple");
MethodEndpoint expected = new MethodEndpoint("endpoint", applicationContext, doItMultiple);
MethodEndpoint endpoint = mapping.lookupEndpoint(new QName("http://springframework.org/spring-ws", "Request1"));
@@ -81,6 +80,20 @@ public class PayloadRootAnnotationMethodEndpointMappingTest {
assertEquals("Invalid endpoint registered", expected, endpoint);
}
@Test
public void registrationRepeatable() throws NoSuchMethodException {
Method doItMultiple = MyEndpoint.class.getMethod("doItRepeatable");
MethodEndpoint expected = new MethodEndpoint("endpoint", applicationContext, doItMultiple);
MethodEndpoint endpoint = mapping.lookupEndpoint(new QName("http://springframework.org/spring-ws", "Request3"));
assertNotNull("MethodEndpoint not registered", endpoint);
assertEquals("Invalid endpoint registered", expected, endpoint);
endpoint = mapping.lookupEndpoint(new QName("http://springframework.org/spring-ws", "Request4"));
assertNotNull("MethodEndpoint not registered", endpoint);
assertEquals("Invalid endpoint registered", expected, endpoint);
}
@Test
public void registrationInvalid() {
assertNull("Invalid endpoint registered",
@@ -130,14 +143,20 @@ public class PayloadRootAnnotationMethodEndpointMappingTest {
logger.info("In doIt()");
}
@PayloadRoots({
@PayloadRoot(localPart = "Request1", namespace = "http://springframework.org/spring-ws"),
@PayloadRoot(localPart = "Request2", namespace = "http://springframework.org/spring-ws")
})
public void doItMultiple(@RequestPayload Source payload) {
doItInvoked = true;
logger.info("In doIt()");
}
@PayloadRoots({@PayloadRoot(localPart = "Request1",
namespace = "http://springframework.org/spring-ws"),
@PayloadRoot(localPart = "Request2",
namespace = "http://springframework.org/spring-ws")})
public void doItMultiple() {
}
@PayloadRoot(localPart = "Request3",
namespace = "http://springframework.org/spring-ws")
@PayloadRoot(localPart = "Request4",
namespace = "http://springframework.org/spring-ws")
public void doItRepeatable() {
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2005-2010 the original author or authors.
* Copyright 2002-2014 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.
@@ -18,6 +18,11 @@ package org.springframework.ws.soap.server.endpoint.mapping;
import java.lang.reflect.Method;
import static org.easymock.EasyMock.*;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.context.DefaultMessageContext;
@@ -27,12 +32,7 @@ import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.server.endpoint.annotation.SoapAction;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import static org.easymock.EasyMock.*;
import org.springframework.ws.soap.server.endpoint.annotation.SoapActions;
public class SoapActionAnnotationMethodEndpointMappingTest {
@@ -50,7 +50,7 @@ public class SoapActionAnnotationMethodEndpointMappingTest {
}
@Test
public void testRegistration() throws Exception {
public void registrationSingle() throws Exception {
SoapMessage requestMock = createMock(SoapMessage.class);
expect(requestMock.getSoapAction()).andReturn("http://springframework.org/spring-ws/SoapAction");
WebServiceMessageFactory factoryMock = createMock(WebServiceMessageFactory.class);
@@ -66,6 +66,52 @@ public class SoapActionAnnotationMethodEndpointMappingTest {
verify(requestMock, factoryMock);
}
@Test
public void registrationMultiple() throws Exception {
SoapMessage requestMock = createMock(SoapMessage.class);
expect(requestMock.getSoapAction()).andReturn("http://springframework.org/spring-ws/SoapAction1");
expect(requestMock.getSoapAction()).andReturn("http://springframework.org/spring-ws/SoapAction2");
WebServiceMessageFactory factoryMock = createMock(WebServiceMessageFactory.class);
replay(requestMock, factoryMock);
Method doItMultiple = MyEndpoint.class.getMethod("doItMultiple");
MethodEndpoint expected = new MethodEndpoint("endpoint", applicationContext, doItMultiple);
MessageContext context = new DefaultMessageContext(requestMock, factoryMock);
EndpointInvocationChain chain = mapping.getEndpoint(context);
Assert.assertNotNull("MethodEndpoint not registered", chain);
Assert.assertEquals("Invalid endpoint registered", expected, chain.getEndpoint());
chain = mapping.getEndpoint(context);
Assert.assertNotNull("MethodEndpoint not registered", chain);
Assert.assertEquals("Invalid endpoint registered", expected, chain.getEndpoint());
verify(requestMock, factoryMock);
}
@Test
public void registrationRepeatable() throws Exception {
SoapMessage requestMock = createMock(SoapMessage.class);
expect(requestMock.getSoapAction()).andReturn("http://springframework.org/spring-ws/SoapAction3");
expect(requestMock.getSoapAction()).andReturn("http://springframework.org/spring-ws/SoapAction4");
WebServiceMessageFactory factoryMock = createMock(WebServiceMessageFactory.class);
replay(requestMock, factoryMock);
Method doItRepeatable = MyEndpoint.class.getMethod("doItRepeatable");
MethodEndpoint expected = new MethodEndpoint("endpoint", applicationContext, doItRepeatable);
MessageContext context = new DefaultMessageContext(requestMock, factoryMock);
EndpointInvocationChain chain = mapping.getEndpoint(context);
Assert.assertNotNull("MethodEndpoint not registered", chain);
Assert.assertEquals("Invalid endpoint registered", expected, chain.getEndpoint());
chain = mapping.getEndpoint(context);
Assert.assertNotNull("MethodEndpoint not registered", chain);
Assert.assertEquals("Invalid endpoint registered", expected, chain.getEndpoint());
verify(requestMock, factoryMock);
}
@Endpoint
private static class MyEndpoint {
@@ -74,5 +120,17 @@ public class SoapActionAnnotationMethodEndpointMappingTest {
}
@SoapActions({@SoapAction("http://springframework.org/spring-ws/SoapAction1"),
@SoapAction("http://springframework.org/spring-ws/SoapAction2")})
public void doItMultiple() {
}
@SoapAction("http://springframework.org/spring-ws/SoapAction3")
@SoapAction("http://springframework.org/spring-ws/SoapAction4")
public void doItRepeatable() {
}
}
}