SWS-351 - Arbitrary parameter injection for @Endpoints
This commit is contained in:
@@ -33,6 +33,7 @@ import org.springframework.ws.server.endpoint.adapter.method.MethodArgumentResol
|
||||
import org.springframework.ws.server.endpoint.adapter.method.MethodReturnValueHandler;
|
||||
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.XPathParamMethodArgumentResolver;
|
||||
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;
|
||||
@@ -114,6 +115,7 @@ public class DefaultMethodEndpointAdapter extends AbstractMethodEndpointAdapter
|
||||
methodArgumentResolvers.add(new DomPayloadMethodProcessor());
|
||||
methodArgumentResolvers.add(new MessageContextMethodArgumentResolver());
|
||||
methodArgumentResolvers.add(new SourcePayloadMethodProcessor());
|
||||
methodArgumentResolvers.add(new XPathParamMethodArgumentResolver());
|
||||
try {
|
||||
Class<MethodArgumentResolver> soapMethodArgumentResolverClass =
|
||||
(Class<MethodArgumentResolver>) ClassUtils
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.dom.DOMResult;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.ConversionServiceFactory;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.server.endpoint.annotation.XPathParam;
|
||||
import org.springframework.ws.server.endpoint.support.NamespaceUtils;
|
||||
import org.springframework.xml.transform.TransformerObjectSupport;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* Implementation of {@link MethodArgumentResolver} that supports the {@link XPathParam @XPathParam} annotation.
|
||||
* <p/>
|
||||
* This resolver supports parameters annotated with {@link XPathParam @XPathParam} that specifies the XPath expression
|
||||
* that should be bound to that parameter. The parameter can either a "natively supported" XPath type ({@link Boolean
|
||||
* boolean}, {@link Double double}, {@link String}, {@link Node}, or {@link NodeList}), or a type that is {@linkplain
|
||||
* ConversionService#canConvert(Class, Class) supported} by the {@link ConversionService}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 2.0
|
||||
*/
|
||||
public class XPathParamMethodArgumentResolver extends TransformerObjectSupport implements MethodArgumentResolver {
|
||||
|
||||
private final XPathFactory xpathFactory = createXPathFactory();
|
||||
|
||||
private ConversionService conversionService = ConversionServiceFactory.createDefaultConversionService();
|
||||
|
||||
/**
|
||||
* Sets the conversion service to use.
|
||||
* <p/>
|
||||
* Defaults to the {@linkplain ConversionServiceFactory#createDefaultConversionService() default conversion
|
||||
* service}.
|
||||
*/
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
if (parameter.getParameterAnnotation(XPathParam.class) == null) {
|
||||
return false;
|
||||
}
|
||||
Class<?> parameterType = parameter.getParameterType();
|
||||
if (Boolean.class.equals(parameterType) || Boolean.TYPE.equals(parameterType) ||
|
||||
Double.class.equals(parameterType) || Double.TYPE.equals(parameterType) ||
|
||||
Node.class.isAssignableFrom(parameterType) || NodeList.class.isAssignableFrom(parameterType) ||
|
||||
String.class.isAssignableFrom(parameterType)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return conversionService.canConvert(String.class, parameterType);
|
||||
}
|
||||
}
|
||||
|
||||
public Object resolveArgument(MessageContext messageContext, MethodParameter parameter)
|
||||
throws TransformerException, XPathExpressionException {
|
||||
Class<?> parameterType = parameter.getParameterType();
|
||||
QName evaluationReturnType = getReturnType(parameterType);
|
||||
boolean useConversionService = false;
|
||||
if (evaluationReturnType == null) {
|
||||
evaluationReturnType = XPathConstants.STRING;
|
||||
useConversionService = true;
|
||||
}
|
||||
|
||||
XPath xpath = createXPath();
|
||||
xpath.setNamespaceContext(NamespaceUtils.getNamespaceContext(parameter.getMethod()));
|
||||
|
||||
Element rootElement = getRootElement(messageContext.getRequest().getPayloadSource());
|
||||
String expression = parameter.getParameterAnnotation(XPathParam.class).value();
|
||||
Object result = xpath.evaluate(expression, rootElement, evaluationReturnType);
|
||||
return useConversionService ? conversionService.convert(result, parameterType) : result;
|
||||
}
|
||||
|
||||
private QName getReturnType(Class<?> parameterType) {
|
||||
if (Boolean.class.equals(parameterType) || Boolean.TYPE.equals(parameterType)) {
|
||||
return XPathConstants.BOOLEAN;
|
||||
}
|
||||
else if (Double.class.equals(parameterType) || Double.TYPE.equals(parameterType)) {
|
||||
return XPathConstants.NUMBER;
|
||||
}
|
||||
else if (Node.class.equals(parameterType)) {
|
||||
return XPathConstants.NODE;
|
||||
}
|
||||
else if (NodeList.class.equals(parameterType)) {
|
||||
return XPathConstants.NODESET;
|
||||
}
|
||||
else if (String.class.equals(parameterType)) {
|
||||
return XPathConstants.STRING;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private XPath createXPath() {
|
||||
synchronized (xpathFactory) {
|
||||
return xpathFactory.newXPath();
|
||||
}
|
||||
}
|
||||
|
||||
private Element getRootElement(Source source) throws TransformerException {
|
||||
DOMResult domResult = new DOMResult();
|
||||
transform(source, domResult);
|
||||
Document document = (Document) domResult.getNode();
|
||||
return document.getDocumentElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code XPathFactory} that this resolver will use to create {@link XPath} objects.
|
||||
* <p/>
|
||||
* Can be overridden in subclasses, adding further initialization of the factory. The resulting factory is cached,
|
||||
* so this method will only be called once.
|
||||
*
|
||||
* @return the created factory
|
||||
*/
|
||||
protected XPathFactory createXPathFactory() {
|
||||
return XPathFactory.newInstance();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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.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;
|
||||
import javax.xml.XMLConstants;
|
||||
|
||||
/**
|
||||
* Sets up a namespace to be used in an {@link Endpoint @Endpoint} method, class, or package.
|
||||
* <p/>
|
||||
* Typically used in combination with {@link XPathParam @XPathParam}, or {@link PayloadRoot @PayloadRoot}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see XPathParam
|
||||
* @see PayloadRoot
|
||||
* @since 2.0
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.PACKAGE, ElementType.TYPE, ElementType.METHOD})
|
||||
public @interface Namespace {
|
||||
|
||||
/**
|
||||
* Signifies the prefix of the namespace.
|
||||
*
|
||||
* @see #uri()
|
||||
*/
|
||||
String prefix() default XMLConstants.DEFAULT_NS_PREFIX;
|
||||
|
||||
/**
|
||||
* Signifies the URI of the namespace.
|
||||
*
|
||||
* @see #prefix()
|
||||
*/
|
||||
String uri();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.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;
|
||||
|
||||
/**
|
||||
* Sets the namespaces to be used in an {@link Endpoint @Endpoint} method, class, or package.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see Namespace
|
||||
* @since 2.0
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.PACKAGE, ElementType.TYPE, ElementType.METHOD})
|
||||
public @interface Namespaces {
|
||||
|
||||
Namespace[] value();
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Method;
|
||||
import javax.xml.namespace.NamespaceContext;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.ws.server.endpoint.annotation.Namespace;
|
||||
import org.springframework.ws.server.endpoint.annotation.Namespaces;
|
||||
import org.springframework.xml.namespace.SimpleNamespaceContext;
|
||||
|
||||
/**
|
||||
* Helper class for handling {@link Namespace @Namespace} annotations.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class NamespaceUtils {
|
||||
|
||||
private NamespaceUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code NamespaceContext} for the specified method, based on {@link Namespaces @Namespaces} and {@link
|
||||
* Namespace @Namespace} annotations.
|
||||
* <p/>
|
||||
* This method will search for {@link Namespaces @Namespaces} and {@link Namespace @Namespace} annotation in the
|
||||
* given method, its class, and its package, in reverse order. That is: package-level annotations are overridden by
|
||||
* class-level annotations, which again are overridden by method-level annotations.
|
||||
*
|
||||
* @param method the method to create the namespace context for
|
||||
* @return the namespace context
|
||||
*/
|
||||
public static NamespaceContext getNamespaceContext(Method method) {
|
||||
Assert.notNull(method, "'method' must not be null");
|
||||
SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext();
|
||||
Class<?> endpointClass = method.getDeclaringClass();
|
||||
Package endpointPackage = endpointClass.getPackage();
|
||||
if (endpointPackage != null) {
|
||||
addNamespaceAnnotations(endpointPackage, namespaceContext);
|
||||
}
|
||||
addNamespaceAnnotations(endpointClass, namespaceContext);
|
||||
addNamespaceAnnotations(method, namespaceContext);
|
||||
return namespaceContext;
|
||||
}
|
||||
|
||||
private static void addNamespaceAnnotations(AnnotatedElement annotatedElement,
|
||||
SimpleNamespaceContext namespaceContext) {
|
||||
if (annotatedElement.isAnnotationPresent(Namespaces.class)) {
|
||||
Namespaces namespacesAnn = annotatedElement.getAnnotation(Namespaces.class);
|
||||
for (Namespace namespaceAnn : namespacesAnn.value()) {
|
||||
namespaceContext.bindNamespaceUri(namespaceAnn.prefix(), namespaceAnn.uri());
|
||||
}
|
||||
}
|
||||
if (annotatedElement.isAnnotationPresent(Namespace.class)) {
|
||||
Namespace namespaceAnn = annotatedElement.getAnnotation(Namespace.class);
|
||||
namespaceContext.bindNamespaceUri(namespaceAnn.prefix(), namespaceAnn.uri());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.ws.MockWebServiceMessage;
|
||||
import org.springframework.ws.MockWebServiceMessageFactory;
|
||||
import org.springframework.ws.context.DefaultMessageContext;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.server.endpoint.annotation.Namespace;
|
||||
import org.springframework.ws.server.endpoint.annotation.Namespaces;
|
||||
import org.springframework.ws.server.endpoint.annotation.XPathParam;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
@Namespaces(@Namespace(prefix = "tns", uri = "http://springframework.org/spring-ws"))
|
||||
public class XPathParamMethodArgumentResolverTest {
|
||||
|
||||
private static final String CONTENTS = "<root><child><text>text</text><number>42</number></child></root>";
|
||||
|
||||
private XPathParamMethodArgumentResolver resolver;
|
||||
|
||||
private MethodParameter booleanParameter;
|
||||
|
||||
private MethodParameter doubleParameter;
|
||||
|
||||
private MethodParameter nodeParameter;
|
||||
|
||||
private MethodParameter nodeListParameter;
|
||||
|
||||
private MethodParameter stringParameter;
|
||||
|
||||
private MethodParameter convertedParameter;
|
||||
|
||||
private MethodParameter unsupportedParameter;
|
||||
|
||||
private MethodParameter namespaceMethodParameter;
|
||||
|
||||
private MethodParameter namespaceClassParameter;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
resolver = new XPathParamMethodArgumentResolver();
|
||||
Method supportedTypes = getClass()
|
||||
.getMethod("supportedTypes", Boolean.TYPE, Double.TYPE, Node.class, NodeList.class, String.class);
|
||||
booleanParameter = new MethodParameter(supportedTypes, 0);
|
||||
doubleParameter = new MethodParameter(supportedTypes, 1);
|
||||
nodeParameter = new MethodParameter(supportedTypes, 2);
|
||||
nodeListParameter = new MethodParameter(supportedTypes, 3);
|
||||
stringParameter = new MethodParameter(supportedTypes, 4);
|
||||
convertedParameter = new MethodParameter(getClass().getMethod("convertedType", Integer.TYPE), 0);
|
||||
unsupportedParameter = new MethodParameter(getClass().getMethod("unsupported", String.class), 0);
|
||||
namespaceMethodParameter = new MethodParameter(getClass().getMethod("namespacesMethod", String.class), 0);
|
||||
namespaceClassParameter = new MethodParameter(getClass().getMethod("namespacesClass", String.class), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsParameter() {
|
||||
assertTrue("resolver does not support boolean parameter", resolver.supportsParameter(booleanParameter));
|
||||
assertTrue("resolver does not support double parameter", resolver.supportsParameter(doubleParameter));
|
||||
assertTrue("resolver does not support Node parameter", resolver.supportsParameter(nodeParameter));
|
||||
assertTrue("resolver does not support NodeList parameter", resolver.supportsParameter(nodeListParameter));
|
||||
assertTrue("resolver does not support String parameter", resolver.supportsParameter(stringParameter));
|
||||
assertTrue("resolver does not support String parameter", resolver.supportsParameter(convertedParameter));
|
||||
assertFalse("resolver supports parameter without @XPathParam", resolver.supportsParameter(unsupportedParameter));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveBoolean() throws Exception {
|
||||
MockWebServiceMessage request = new MockWebServiceMessage(CONTENTS);
|
||||
MessageContext messageContext = new DefaultMessageContext(request, new MockWebServiceMessageFactory());
|
||||
|
||||
Object result = resolver.resolveArgument(messageContext, booleanParameter);
|
||||
|
||||
assertTrue("resolver does not return boolean", result instanceof Boolean);
|
||||
Boolean b = (Boolean) result;
|
||||
assertTrue("Invalid boolean value", b);
|
||||
}
|
||||
@Test
|
||||
public void resolveDouble() throws Exception {
|
||||
MockWebServiceMessage request = new MockWebServiceMessage(CONTENTS);
|
||||
MessageContext messageContext = new DefaultMessageContext(request, new MockWebServiceMessageFactory());
|
||||
|
||||
Object result = resolver.resolveArgument(messageContext, doubleParameter);
|
||||
|
||||
assertTrue("resolver does not return double", result instanceof Double);
|
||||
Double d = (Double) result;
|
||||
assertEquals("Invalid double value", 42D, d, 0D);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveNode() throws Exception {
|
||||
MockWebServiceMessage request = new MockWebServiceMessage(CONTENTS);
|
||||
MessageContext messageContext = new DefaultMessageContext(request, new MockWebServiceMessageFactory());
|
||||
|
||||
Object result = resolver.resolveArgument(messageContext, nodeParameter);
|
||||
|
||||
assertTrue("resolver does not return Node", result instanceof Node);
|
||||
Node node = (Node) result;
|
||||
assertEquals("Invalid node value", "child", node.getLocalName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveNodeList() throws Exception {
|
||||
MockWebServiceMessage request = new MockWebServiceMessage(CONTENTS);
|
||||
MessageContext messageContext = new DefaultMessageContext(request, new MockWebServiceMessageFactory());
|
||||
|
||||
Object result = resolver.resolveArgument(messageContext, nodeListParameter);
|
||||
|
||||
assertTrue("resolver does not return NodeList", result instanceof NodeList);
|
||||
NodeList nodeList = (NodeList) result;
|
||||
assertEquals("Invalid NodeList value", 1, nodeList.getLength());
|
||||
assertEquals("Invalid Node value", "child", nodeList.item(0).getLocalName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveString() throws Exception {
|
||||
MockWebServiceMessage request = new MockWebServiceMessage(CONTENTS);
|
||||
MessageContext messageContext = new DefaultMessageContext(request, new MockWebServiceMessageFactory());
|
||||
|
||||
Object result = resolver.resolveArgument(messageContext, stringParameter);
|
||||
|
||||
assertTrue("resolver does not return String", result instanceof String);
|
||||
String s = (String) result;
|
||||
assertEquals("Invalid string value", "text", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveConvertedType() throws Exception {
|
||||
MockWebServiceMessage request = new MockWebServiceMessage(CONTENTS);
|
||||
MessageContext messageContext = new DefaultMessageContext(request, new MockWebServiceMessageFactory());
|
||||
|
||||
Object result = resolver.resolveArgument(messageContext, convertedParameter);
|
||||
|
||||
assertTrue("resolver does not return String", result instanceof Integer);
|
||||
Integer i = (Integer) result;
|
||||
assertEquals("Invalid integer value", new Integer(42), i);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveNamespacesMethod() throws Exception {
|
||||
MockWebServiceMessage request = new MockWebServiceMessage(
|
||||
"<root xmlns=\"http://springframework.org/spring-ws\">text</root>");
|
||||
MessageContext messageContext = new DefaultMessageContext(request, new MockWebServiceMessageFactory());
|
||||
|
||||
Object result = resolver.resolveArgument(messageContext, namespaceMethodParameter);
|
||||
|
||||
assertTrue("resolver does not return String", result instanceof String);
|
||||
String s = (String) result;
|
||||
assertEquals("Invalid string value", "text", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveNamespacesClass() throws Exception {
|
||||
MockWebServiceMessage request = new MockWebServiceMessage(
|
||||
"<root xmlns=\"http://springframework.org/spring-ws\">text</root>");
|
||||
MessageContext messageContext = new DefaultMessageContext(request, new MockWebServiceMessageFactory());
|
||||
|
||||
Object result = resolver.resolveArgument(messageContext, namespaceClassParameter);
|
||||
|
||||
assertTrue("resolver does not return String", result instanceof String);
|
||||
String s = (String) result;
|
||||
assertEquals("Invalid string value", "text", s);
|
||||
}
|
||||
|
||||
public void unsupported(String s) {
|
||||
}
|
||||
|
||||
public void supportedTypes(@XPathParam("/root/child")boolean param1,
|
||||
@XPathParam("/root/child/number")double param2,
|
||||
@XPathParam("/root/child") Node param3,
|
||||
@XPathParam("/root/*") NodeList param4,
|
||||
@XPathParam("/root/child/text")String param5) {
|
||||
}
|
||||
|
||||
public void convertedType(@XPathParam("/root/child/number")int param) {
|
||||
}
|
||||
|
||||
@Namespaces(@Namespace(prefix = "tns", uri = "http://springframework.org/spring-ws"))
|
||||
public void namespacesMethod(@XPathParam("/tns:root")String s) {
|
||||
}
|
||||
|
||||
public void namespacesClass(@XPathParam("/tns:root")String s) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.namespace.NamespaceContext;
|
||||
|
||||
import org.springframework.ws.server.endpoint.annotation.Namespace;
|
||||
import org.springframework.ws.server.endpoint.annotation.Namespaces;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@Namespaces({@Namespace(prefix = "prefix1", uri = "class1"), @Namespace(uri = "class2")})
|
||||
public class NamespaceUtilsTest {
|
||||
|
||||
@Test
|
||||
public void getNamespaceContextMethod() throws NoSuchMethodException {
|
||||
Method method = getClass().getMethod("method");
|
||||
NamespaceContext namespaceContext = NamespaceUtils.getNamespaceContext(method);
|
||||
assertEquals("method1", namespaceContext.getNamespaceURI("prefix1"));
|
||||
assertEquals("method2", namespaceContext.getNamespaceURI(XMLConstants.DEFAULT_NS_PREFIX));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNamespaceContextClass() throws NoSuchMethodException {
|
||||
Method method = getClass().getMethod("getNamespaceContextClass");
|
||||
NamespaceContext namespaceContext = NamespaceUtils.getNamespaceContext(method);
|
||||
assertEquals("class1", namespaceContext.getNamespaceURI("prefix1"));
|
||||
assertEquals("class2", namespaceContext.getNamespaceURI(XMLConstants.DEFAULT_NS_PREFIX));
|
||||
|
||||
}
|
||||
|
||||
@Namespaces({@Namespace(prefix = "prefix1", uri = "method1"), @Namespace(uri = "method2")})
|
||||
public void method() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,20 +16,17 @@
|
||||
|
||||
package org.springframework.xml.namespace;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.namespace.NamespaceContext;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* Simple <code>javax.xml.namespace.NamespaceContext</code> implementation. Follows the standard
|
||||
@@ -41,9 +38,9 @@ import org.springframework.util.MultiValueMap;
|
||||
*/
|
||||
public class SimpleNamespaceContext implements NamespaceContext {
|
||||
|
||||
private Map<String, String> prefixToNamespaceUri = new HashMap<String, String>();
|
||||
private Map<String, String> prefixToNamespaceUri = new LinkedHashMap<String, String>();
|
||||
|
||||
private MultiValueMap<String, String> namespaceUriToPrefixes = new LinkedMultiValueMap<String, String>();
|
||||
private Map<String, Set<String>> namespaceUriToPrefixes = new LinkedHashMap<String, Set<String>>();
|
||||
|
||||
public String getNamespaceURI(String prefix) {
|
||||
Assert.notNull(prefix, "prefix is null");
|
||||
@@ -60,12 +57,14 @@ public class SimpleNamespaceContext implements NamespaceContext {
|
||||
}
|
||||
|
||||
public String getPrefix(String namespaceUri) {
|
||||
List<String> prefixes = getPrefixesInternal(namespaceUri);
|
||||
return prefixes.isEmpty() ? null : prefixes.get(0);
|
||||
Iterator<String> iterator = getPrefixes(namespaceUri);
|
||||
return iterator.hasNext() ? iterator.next() : null;
|
||||
}
|
||||
|
||||
public Iterator<String> getPrefixes(String namespaceUri) {
|
||||
return getPrefixesInternal(namespaceUri).iterator();
|
||||
Set<String> prefixes = getPrefixesInternal(namespaceUri);
|
||||
prefixes = Collections.unmodifiableSet(prefixes);
|
||||
return prefixes.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,23 +124,24 @@ public class SimpleNamespaceContext implements NamespaceContext {
|
||||
public Iterator<String> getBoundPrefixes() {
|
||||
Set<String> prefixes = new HashSet<String>(prefixToNamespaceUri.keySet());
|
||||
prefixes.remove(XMLConstants.DEFAULT_NS_PREFIX);
|
||||
prefixes = Collections.unmodifiableSet(prefixes);
|
||||
return prefixes.iterator();
|
||||
}
|
||||
|
||||
private List<String> getPrefixesInternal(String namespaceUri) {
|
||||
private Set<String> getPrefixesInternal(String namespaceUri) {
|
||||
if (XMLConstants.XML_NS_URI.equals(namespaceUri)) {
|
||||
return Collections.singletonList(XMLConstants.XML_NS_PREFIX);
|
||||
return Collections.singleton(XMLConstants.XML_NS_PREFIX);
|
||||
}
|
||||
else if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceUri)) {
|
||||
return Collections.singletonList(XMLConstants.XMLNS_ATTRIBUTE);
|
||||
return Collections.singleton(XMLConstants.XMLNS_ATTRIBUTE);
|
||||
}
|
||||
else {
|
||||
List<String> list = namespaceUriToPrefixes.get(namespaceUri);
|
||||
if (list == null) {
|
||||
list = new ArrayList<String>();
|
||||
namespaceUriToPrefixes.put(namespaceUri, list);
|
||||
Set<String> set = namespaceUriToPrefixes.get(namespaceUri);
|
||||
if (set == null) {
|
||||
set = new LinkedHashSet<String>();
|
||||
namespaceUriToPrefixes.put(namespaceUri, set);
|
||||
}
|
||||
return list;
|
||||
return set;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ public class SimpleNamespaceContext implements NamespaceContext {
|
||||
*/
|
||||
public void removeBinding(String prefix) {
|
||||
String namespaceUri = prefixToNamespaceUri.get(prefix);
|
||||
List<String> prefixes = getPrefixesInternal(namespaceUri);
|
||||
Set<String> prefixes = getPrefixesInternal(namespaceUri);
|
||||
prefixes.remove(prefix);
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,17 @@ public class SimpleNamespaceContextTest {
|
||||
assertPrefixes(XMLConstants.XML_NS_URI, XMLConstants.XML_NS_PREFIX);
|
||||
assertPrefixes(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, XMLConstants.XMLNS_ATTRIBUTE);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void unmodifiableGetPrefixes() {
|
||||
String namespaceUri = "namespaceUri";
|
||||
context.bindNamespaceUri("prefix1", namespaceUri);
|
||||
context.bindNamespaceUri("prefix2", namespaceUri);
|
||||
|
||||
Iterator<String> prefixes = context.getPrefixes(namespaceUri);
|
||||
prefixes.next();
|
||||
prefixes.remove();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiplePrefixes() {
|
||||
|
||||
Reference in New Issue
Block a user