Browse Source

Allow Validator config in XML websocket namespace

This commit adds a new "validator" XML attribute to the
`<websocket:message-broker/>` element. This allows configuring a
specific Validator to be used for payload validation.

Issue: SPR-13996
pull/996/merge
Brian Clozel 9 years ago
parent
commit
8ca6a18dae
  1. 1
      spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
  2. 28
      spring-websocket/src/main/java/org/springframework/web/socket/config/MessageBrokerBeanDefinitionParser.java
  3. 11
      spring-websocket/src/main/resources/org/springframework/web/socket/config/spring-websocket-4.3.xsd
  4. 22
      spring-websocket/src/test/java/org/springframework/web/socket/config/MessageBrokerBeanDefinitionParserTests.java
  5. 4
      spring-websocket/src/test/resources/org/springframework/web/socket/config/websocket-config-broker-customchannels.xml

1
spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java

@ -853,6 +853,7 @@ public class MvcNamespaceTests {
ContentNegotiationManager manager = (ContentNegotiationManager) accessor.getPropertyValue(beanName); ContentNegotiationManager manager = (ContentNegotiationManager) accessor.getPropertyValue(beanName);
assertNotNull(manager); assertNotNull(manager);
assertSame(manager, this.appContext.getBean(ContentNegotiationManager.class)); assertSame(manager, this.appContext.getBean(ContentNegotiationManager.class));
assertSame(manager, this.appContext.getBean("mvcContentNegotiationManager"));
} }
@Test @Test

28
spring-websocket/src/main/java/org/springframework/web/socket/config/MessageBrokerBeanDefinitionParser.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2002-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -109,6 +109,9 @@ class MessageBrokerBeanDefinitionParser implements BeanDefinitionParser {
private static final boolean jackson2Present = ClassUtils.isPresent( private static final boolean jackson2Present = ClassUtils.isPresent(
"com.fasterxml.jackson.databind.ObjectMapper", MessageBrokerBeanDefinitionParser.class.getClassLoader()); "com.fasterxml.jackson.databind.ObjectMapper", MessageBrokerBeanDefinitionParser.class.getClassLoader());
private static final boolean javaxValidationPresent =
ClassUtils.isPresent("javax.validation.Validator", MessageBrokerBeanDefinitionParser.class.getClassLoader());
@Override @Override
public BeanDefinition parse(Element element, ParserContext context) { public BeanDefinition parse(Element element, ParserContext context) {
@ -516,6 +519,11 @@ class MessageBrokerBeanDefinitionParser implements BeanDefinitionParser {
beanDef.getPropertyValues().add("pathMatcher", new RuntimeBeanReference(pathMatcherRef)); beanDef.getPropertyValues().add("pathMatcher", new RuntimeBeanReference(pathMatcherRef));
} }
RuntimeBeanReference validatorRef = getValidator(messageBrokerElement, source, context);
if (validatorRef != null) {
beanDef.getPropertyValues().add("validator", validatorRef);
}
Element resolversElement = DomUtils.getChildElementByTagName(messageBrokerElement, "argument-resolvers"); Element resolversElement = DomUtils.getChildElementByTagName(messageBrokerElement, "argument-resolvers");
if (resolversElement != null) { if (resolversElement != null) {
values.add("customArgumentResolvers", extractBeanSubElements(resolversElement, context)); values.add("customArgumentResolvers", extractBeanSubElements(resolversElement, context));
@ -529,6 +537,24 @@ class MessageBrokerBeanDefinitionParser implements BeanDefinitionParser {
registerBeanDef(beanDef, context, source); registerBeanDef(beanDef, context, source);
} }
private RuntimeBeanReference getValidator(Element messageBrokerElement, Object source, ParserContext parserContext) {
if (messageBrokerElement.hasAttribute("validator")) {
return new RuntimeBeanReference(messageBrokerElement.getAttribute("validator"));
}
else if (javaxValidationPresent) {
RootBeanDefinition validatorDef = new RootBeanDefinition(
"org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean");
validatorDef.setSource(source);
validatorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String validatorName = parserContext.getReaderContext().registerWithGeneratedName(validatorDef);
parserContext.registerComponent(new BeanComponentDefinition(validatorDef, validatorName));
return new RuntimeBeanReference(validatorName);
}
else {
return null;
}
}
private ManagedList<Object> extractBeanSubElements(Element parentElement, ParserContext parserContext) { private ManagedList<Object> extractBeanSubElements(Element parentElement, ParserContext parserContext) {
ManagedList<Object> list = new ManagedList<Object>(); ManagedList<Object> list = new ManagedList<Object>();
list.setSource(parserContext.extractSource(parentElement)); list.setSource(parserContext.extractSource(parentElement));

11
spring-websocket/src/main/resources/org/springframework/web/socket/config/spring-websocket-4.3.xsd

@ -21,7 +21,7 @@
<xsd:annotation> <xsd:annotation>
<xsd:documentation><![CDATA[ <xsd:documentation><![CDATA[
A path that maps a particular request to a handler. A path that maps a particular request to a handler.
Exact path mapping URIs (such as "/myPath") are supported as well as Ant-stype path patterns (such as /myPath/**). Exact path mapping URIs (such as "/myPath") are supported as well as Ant-type path patterns (such as /myPath/**).
]]></xsd:documentation> ]]></xsd:documentation>
</xsd:annotation> </xsd:annotation>
</xsd:attribute> </xsd:attribute>
@ -916,9 +916,16 @@
<xsd:annotation> <xsd:annotation>
<xsd:documentation><![CDATA[ <xsd:documentation><![CDATA[
The bean name of the UrlPathHelper to use for the HandlerMapping used to map handshake requests. The bean name of the UrlPathHelper to use for the HandlerMapping used to map handshake requests.
]]></xsd:documentation> ]]></xsd:documentation>
</xsd:annotation> </xsd:annotation>
</xsd:attribute> </xsd:attribute>
<xsd:attribute name="validator" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
The bean name of the Validator instance used for validating @Payload arguments.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:schema> </xsd:schema>

22
spring-websocket/src/test/java/org/springframework/web/socket/config/MessageBrokerBeanDefinitionParserTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2002-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -60,6 +60,8 @@ import org.springframework.mock.web.test.MockServletContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.util.MimeTypeUtils; import org.springframework.util.MimeTypeUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.web.HttpRequestHandler; import org.springframework.web.HttpRequestHandler;
import org.springframework.web.context.support.GenericWebApplicationContext; import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.HandlerMapping;
@ -356,6 +358,14 @@ public class MessageBrokerBeanDefinitionParserTests {
public void customChannels() { public void customChannels() {
loadBeanDefinitions("websocket-config-broker-customchannels.xml"); loadBeanDefinitions("websocket-config-broker-customchannels.xml");
SimpAnnotationMethodMessageHandler annotationMethodMessageHandler =
this.appContext.getBean(SimpAnnotationMethodMessageHandler.class);
Validator validator = annotationMethodMessageHandler.getValidator();
assertNotNull(validator);
assertSame(this.appContext.getBean("myValidator"), validator);
assertThat(validator, Matchers.instanceOf(TestValidator.class));
List<Class<? extends MessageHandler>> subscriberTypes = List<Class<? extends MessageHandler>> subscriberTypes =
Arrays.<Class<? extends MessageHandler>>asList(SimpAnnotationMethodMessageHandler.class, Arrays.<Class<? extends MessageHandler>>asList(SimpAnnotationMethodMessageHandler.class,
UserDestinationMessageHandler.class, SimpleBrokerMessageHandler.class); UserDestinationMessageHandler.class, SimpleBrokerMessageHandler.class);
@ -520,3 +530,13 @@ class TestWebSocketHandlerDecorator extends WebSocketHandlerDecorator {
class TestStompErrorHandler extends StompSubProtocolErrorHandler { class TestStompErrorHandler extends StompSubProtocolErrorHandler {
} }
class TestValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return false;
}
@Override
public void validate(Object target, Errors errors) { }
}

4
spring-websocket/src/test/resources/org/springframework/web/socket/config/websocket-config-broker-customchannels.xml

@ -4,7 +4,7 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd"> http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd">
<websocket:message-broker application-destination-prefix="/app" user-destination-prefix="/personal"> <websocket:message-broker application-destination-prefix="/app" user-destination-prefix="/personal" validator="myValidator">
<websocket:stomp-endpoint path="/foo,/bar"> <websocket:stomp-endpoint path="/foo,/bar">
<websocket:handshake-handler ref="myHandler"/> <websocket:handshake-handler ref="myHandler"/>
</websocket:stomp-endpoint> </websocket:stomp-endpoint>
@ -31,4 +31,6 @@
<bean id="myInterceptor" class="org.springframework.web.socket.config.TestChannelInterceptor"/> <bean id="myInterceptor" class="org.springframework.web.socket.config.TestChannelInterceptor"/>
<bean id="myValidator" class="org.springframework.web.socket.config.TestValidator"/>
</beans> </beans>

Loading…
Cancel
Save