SWS-273
This commit is contained in:
@@ -19,23 +19,34 @@ package org.springframework.ws.server.endpoint.mapping;
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.ws.server.endpoint.annotation.Endpoint;
|
||||
|
||||
/**
|
||||
* Abstract base for {@link org.springframework.ws.server.EndpointMapping} implementations that map classes tagged with
|
||||
* an annotation. By default the annotation is {@link Endpoint}, but this can be overriden in subclasses.
|
||||
* <p/>
|
||||
* The methods of each bean carrying @Endpoint will be registered using {@link #registerMethods(Object)}.
|
||||
* The methods of each bean carrying @Endpoint will be registered using {@link #registerMethods(String)}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public abstract class AbstractAnnotationMethodEndpointMapping extends AbstractMethodEndpointMapping
|
||||
implements BeanPostProcessor {
|
||||
public abstract class AbstractAnnotationMethodEndpointMapping extends AbstractMethodEndpointMapping {
|
||||
|
||||
public final Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
private boolean detectEndpointsInAncestorContexts = false;
|
||||
|
||||
/**
|
||||
* Set whether to detect endpoint beans in ancestor ApplicationContexts.
|
||||
* <p/>
|
||||
* Default is "false": Only endpoint beans in the current ApplicationContext will be detected, i.e. only in the
|
||||
* context that this EndpointMapping itself is defined in (typically the current MessageDispatcherServlet's
|
||||
* context).
|
||||
* <p/>
|
||||
* Switch this flag on to detect endpoint beans in ancestor contexts (typically the Spring root
|
||||
* WebApplicationContext) as well.
|
||||
*/
|
||||
public void setDetectEndpointsInAncestorContexts(boolean detectEndpointsInAncestorContexts) {
|
||||
this.detectEndpointsInAncestorContexts = detectEndpointsInAncestorContexts;
|
||||
}
|
||||
|
||||
/** Returns the 'endpoint' annotation type. Default is {@link Endpoint}. */
|
||||
@@ -43,12 +54,21 @@ public abstract class AbstractAnnotationMethodEndpointMapping extends AbstractMe
|
||||
return Endpoint.class;
|
||||
}
|
||||
|
||||
public final Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
Class endpointClass = getEndpointClass(bean);
|
||||
if (endpointClass != null && endpointClass.getAnnotation(getEndpointAnnotationType()) != null) {
|
||||
registerMethods(bean);
|
||||
protected final void initApplicationContext() throws BeansException {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Looking for endpoints in application context: " + getApplicationContext());
|
||||
}
|
||||
String[] beanNames = (this.detectEndpointsInAncestorContexts ?
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
|
||||
getApplicationContext().getBeanNamesForType(Object.class));
|
||||
|
||||
for (int i = 0; i < beanNames.length; i++) {
|
||||
String beanName = beanNames[i];
|
||||
Class endpointClass = getApplicationContext().getType(beanName);
|
||||
if (endpointClass != null && endpointClass.getAnnotation(getEndpointAnnotationType()) != null) {
|
||||
registerMethods(beanName);
|
||||
}
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ws.server.endpoint.mapping;
|
||||
|
||||
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
|
||||
|
||||
class OtherBean {
|
||||
|
||||
@PayloadRoot(localPart = "Request2", namespace = "http://springframework.org/spring-ws")
|
||||
public void doIt() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,11 +16,12 @@
|
||||
|
||||
package org.springframework.ws.server.endpoint.mapping;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.ws.server.endpoint.MethodEndpoint;
|
||||
import org.springframework.ws.server.endpoint.annotation.Endpoint;
|
||||
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
|
||||
|
||||
public class PayloadRootAnnotationMethodEndpointMappingTest extends TestCase {
|
||||
|
||||
@@ -31,7 +32,7 @@ public class PayloadRootAnnotationMethodEndpointMappingTest extends TestCase {
|
||||
protected void setUp() throws Exception {
|
||||
applicationContext = new StaticApplicationContext();
|
||||
applicationContext.registerSingleton("mapping", PayloadRootAnnotationMethodEndpointMapping.class);
|
||||
applicationContext.registerSingleton("endpoint", MyEndpoint.class);
|
||||
applicationContext.registerSingleton("endpoint", PayloadRootEndpoint.class);
|
||||
applicationContext.registerSingleton("other", OtherBean.class);
|
||||
applicationContext.refresh();
|
||||
mapping = (PayloadRootAnnotationMethodEndpointMapping) applicationContext.getBean("mapping");
|
||||
@@ -40,30 +41,12 @@ public class PayloadRootAnnotationMethodEndpointMappingTest extends TestCase {
|
||||
public void testRegistration() throws NoSuchMethodException {
|
||||
MethodEndpoint endpoint = mapping.lookupEndpoint("{http://springframework.org/spring-ws}Request");
|
||||
assertNotNull("MethodEndpoint not registered", endpoint);
|
||||
MethodEndpoint expected = new MethodEndpoint(applicationContext.getBean("endpoint"), "doIt", new Class[0]);
|
||||
Method doIt = PayloadRootEndpoint.class.getMethod("doIt", new Class[0]);
|
||||
MethodEndpoint expected = new MethodEndpoint("endpoint", applicationContext, doIt);
|
||||
assertEquals("Invalid endpoint registered", expected, endpoint);
|
||||
|
||||
assertNull("Invalid endpoint registered",
|
||||
mapping.lookupEndpoint("{http://springframework.org/spring-ws}Request2"));
|
||||
}
|
||||
|
||||
@Endpoint
|
||||
private static class MyEndpoint {
|
||||
|
||||
@PayloadRoot(localPart = "Request", namespace = "http://springframework.org/spring-ws")
|
||||
public void doIt() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class OtherBean {
|
||||
|
||||
@PayloadRoot(localPart = "Request2", namespace = "http://springframework.org/spring-ws")
|
||||
public void doIt() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ws.server.endpoint.mapping;
|
||||
|
||||
import org.springframework.ws.server.endpoint.annotation.Endpoint;
|
||||
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
|
||||
|
||||
@Endpoint
|
||||
class PayloadRootEndpoint {
|
||||
|
||||
@PayloadRoot(localPart = "Request", namespace = "http://springframework.org/spring-ws")
|
||||
public void doIt() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,8 +16,11 @@
|
||||
|
||||
package org.springframework.ws.soap.server.endpoint.mapping;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import static org.easymock.EasyMock.*;
|
||||
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.ws.WebServiceMessageFactory;
|
||||
import org.springframework.ws.context.DefaultMessageContext;
|
||||
@@ -43,18 +46,19 @@ public class SoapActionAnnotationMethodEndpointMappingTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testRegistration() throws Exception {
|
||||
SoapMessage requestMock = createMock(SoapMessage.class);
|
||||
expect(requestMock.getSoapAction()).andReturn("http://springframework.org/spring-ws/SoapAction");
|
||||
WebServiceMessageFactory factoryMock = createMock(WebServiceMessageFactory.class);
|
||||
replay(requestMock, factoryMock);
|
||||
SoapMessage requestMock = createMock(SoapMessage.class);
|
||||
expect(requestMock.getSoapAction()).andReturn("http://springframework.org/spring-ws/SoapAction");
|
||||
WebServiceMessageFactory factoryMock = createMock(WebServiceMessageFactory.class);
|
||||
replay(requestMock, factoryMock);
|
||||
|
||||
MessageContext context = new DefaultMessageContext(requestMock, factoryMock);
|
||||
MessageContext context = new DefaultMessageContext(requestMock, factoryMock);
|
||||
EndpointInvocationChain chain = mapping.getEndpoint(context);
|
||||
assertNotNull("MethodEndpoint not registered", chain);
|
||||
MethodEndpoint expected = new MethodEndpoint(applicationContext.getBean("endpoint"), "doIt", new Class[0]);
|
||||
Method doIt = MyEndpoint.class.getMethod("doIt", new Class[0]);
|
||||
MethodEndpoint expected = new MethodEndpoint("endpoint", applicationContext, doIt);
|
||||
assertEquals("Invalid endpoint registered", expected, chain.getEndpoint());
|
||||
|
||||
verify(requestMock,factoryMock);
|
||||
|
||||
verify(requestMock, factoryMock);
|
||||
}
|
||||
|
||||
@Endpoint
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.ws.server.endpoint;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.core.JdkVersion;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -32,9 +33,11 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public final class MethodEndpoint {
|
||||
|
||||
private Object bean;
|
||||
private final Object bean;
|
||||
|
||||
private Method method;
|
||||
private final Method method;
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
/**
|
||||
* Constructs a new method endpoint with the given bean and method.
|
||||
@@ -47,6 +50,7 @@ public final class MethodEndpoint {
|
||||
Assert.notNull(method, "method must not be null");
|
||||
this.bean = bean;
|
||||
this.method = method;
|
||||
this.beanFactory = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,6 +66,26 @@ public final class MethodEndpoint {
|
||||
Assert.notNull(methodName, "method must not be null");
|
||||
this.bean = bean;
|
||||
this.method = bean.getClass().getMethod(methodName, parameterTypes);
|
||||
this.beanFactory = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new method endpoint with the given bean name and method. The bean name will be lazily initized when
|
||||
* {@link #invoke(Object[])} is called.
|
||||
*
|
||||
* @param beanName the bean name
|
||||
* @param beanFactory the bean factory to use for bean initialization
|
||||
* @param method the method
|
||||
*/
|
||||
public MethodEndpoint(String beanName, BeanFactory beanFactory, Method method) {
|
||||
Assert.hasText(beanName, "'beanName' must not be null");
|
||||
Assert.notNull(beanFactory, "'beanFactory' must not be null");
|
||||
Assert.notNull(method, "'method' must not be null");
|
||||
Assert.isTrue(beanFactory.containsBean(beanName),
|
||||
"Bean factory [" + beanFactory + "] does not contain bean " + "with name [" + beanName + "]");
|
||||
this.bean = beanName;
|
||||
this.beanFactory = beanFactory;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
/** Returns the object bean for this method endpoint. */
|
||||
@@ -82,8 +106,13 @@ public final class MethodEndpoint {
|
||||
* @throws Exception when the method invocation results in an exception
|
||||
*/
|
||||
public Object invoke(Object[] args) throws Exception {
|
||||
Object endpoint = bean;
|
||||
if (endpoint instanceof String) {
|
||||
String endpointName = (String) endpoint;
|
||||
endpoint = beanFactory.getBean(endpointName);
|
||||
}
|
||||
try {
|
||||
return this.method.invoke(this.bean, args);
|
||||
return this.method.invoke(endpoint, args);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
handleInvocationTargetException(ex);
|
||||
|
||||
@@ -124,6 +124,29 @@ public abstract class AbstractMethodEndpointMapping extends AbstractEndpointMapp
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that registers the methods of the given class. This method iterates over the methods of the class,
|
||||
* and calls {@link #getLookupKeyForMethod(Method)} for each. If this returns a string, the method is registered
|
||||
* using {@link #registerEndpoint(String,MethodEndpoint)}.
|
||||
*
|
||||
* @see #getLookupKeyForMethod(Method)
|
||||
*/
|
||||
protected void registerMethods(String beanName) {
|
||||
Assert.hasText(beanName, "'beanName' must not be empty");
|
||||
Class endpointClass = getApplicationContext().getType(beanName);
|
||||
Method[] methods = endpointClass.getMethods();
|
||||
for (int i = 0; i < methods.length; i++) {
|
||||
if (JdkVersion.isAtLeastJava15() && methods[i].isSynthetic() ||
|
||||
methods[i].getDeclaringClass().equals(Object.class)) {
|
||||
continue;
|
||||
}
|
||||
String key = getLookupKeyForMethod(methods[i]);
|
||||
if (StringUtils.hasLength(key)) {
|
||||
registerEndpoint(key, new MethodEndpoint(beanName, getApplicationContext(), methods[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the the endpoint keys for the given method. Returns <code>null</code> if the method is not to be
|
||||
* registered, which is the default.
|
||||
|
||||
Reference in New Issue
Block a user