/* * Copyright 2002-2016 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.messaging.handler.annotation.support; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Method; import java.util.Locale; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.core.MethodParameter; import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.messaging.Message; import org.springframework.messaging.converter.MessageConversionException; import org.springframework.messaging.converter.StringMessageConverter; import org.springframework.messaging.handler.annotation.Payload; import org.springframework.messaging.support.MessageBuilder; import org.springframework.validation.Errors; import org.springframework.validation.Validator; import org.springframework.validation.annotation.Validated; import static org.junit.Assert.*; /** * Test fixture for {@link PayloadArgumentResolver}. * * @author Rossen Stoyanchev * @author Brian Clozel * @author Stephane Nicoll */ public class PayloadArgumentResolverTests { private PayloadArgumentResolver resolver; private MethodParameter paramAnnotated; private MethodParameter paramAnnotatedNotRequired; private MethodParameter paramAnnotatedRequired; private MethodParameter paramWithSpelExpression; private MethodParameter paramNotAnnotated; private MethodParameter paramValidatedNotAnnotated; private MethodParameter paramValidated; @Rule public final ExpectedException thrown = ExpectedException.none(); @Before public void setup() throws Exception { this.resolver = new PayloadArgumentResolver(new StringMessageConverter(), testValidator()); Method payloadMethod = PayloadArgumentResolverTests.class.getDeclaredMethod( "handleMessage", String.class, String.class, Locale.class, String.class, String.class, String.class, String.class); this.paramAnnotated = new SynthesizingMethodParameter(payloadMethod, 0); this.paramAnnotatedNotRequired = new SynthesizingMethodParameter(payloadMethod, 1); this.paramAnnotatedRequired = new SynthesizingMethodParameter(payloadMethod, 2); this.paramWithSpelExpression = new SynthesizingMethodParameter(payloadMethod, 3); this.paramValidated = new SynthesizingMethodParameter(payloadMethod, 4); this.paramValidated.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); this.paramValidatedNotAnnotated = new SynthesizingMethodParameter(payloadMethod, 5); this.paramNotAnnotated = new SynthesizingMethodParameter(payloadMethod, 6); } @Test public void supportsParameter() throws Exception { assertTrue(this.resolver.supportsParameter(this.paramAnnotated)); assertTrue(this.resolver.supportsParameter(this.paramNotAnnotated)); PayloadArgumentResolver strictResolver = new PayloadArgumentResolver( new StringMessageConverter(), testValidator(), false); assertTrue(strictResolver.supportsParameter(this.paramAnnotated)); assertFalse(strictResolver.supportsParameter(this.paramNotAnnotated)); } @Test public void resolveRequired() throws Exception { Message<?> message = MessageBuilder.withPayload("ABC".getBytes()).build(); Object actual = this.resolver.resolveArgument(paramAnnotated, message); assertEquals("ABC", actual); } @Test public void resolveRequiredEmpty() throws Exception { Message<?> message = MessageBuilder.withPayload("").build(); thrown.expect(MethodArgumentNotValidException.class); // Required but empty this.resolver.resolveArgument(paramAnnotated, message); } @Test public void resolveRequiredEmptyNonAnnotatedParameter() throws Exception { Message<?> message = MessageBuilder.withPayload("").build(); thrown.expect(MethodArgumentNotValidException.class); // Required but empty this.resolver.resolveArgument(this.paramNotAnnotated, message); } @Test public void resolveNotRequired() throws Exception { Message<?> emptyByteArrayMessage = MessageBuilder.withPayload(new byte[0]).build(); assertNull(this.resolver.resolveArgument(this.paramAnnotatedNotRequired, emptyByteArrayMessage)); Message<?> emptyStringMessage = MessageBuilder.withPayload("").build(); assertNull(this.resolver.resolveArgument(this.paramAnnotatedNotRequired, emptyStringMessage)); Message<?> notEmptyMessage = MessageBuilder.withPayload("ABC".getBytes()).build(); assertEquals("ABC", this.resolver.resolveArgument(this.paramAnnotatedNotRequired, notEmptyMessage)); } @Test public void resolveNonConvertibleParam() throws Exception { Message<?> notEmptyMessage = MessageBuilder.withPayload(123).build(); thrown.expect(MessageConversionException.class); thrown.expectMessage("Cannot convert"); this.resolver.resolveArgument(this.paramAnnotatedRequired, notEmptyMessage); } @Test public void resolveSpelExpressionNotSupported() throws Exception { Message<?> message = MessageBuilder.withPayload("ABC".getBytes()).build(); thrown.expect(IllegalStateException.class); this.resolver.resolveArgument(paramWithSpelExpression, message); } @Test public void resolveValidation() throws Exception { Message<?> message = MessageBuilder.withPayload("ABC".getBytes()).build(); this.resolver.resolveArgument(this.paramValidated, message); } @Test public void resolveFailValidation() throws Exception { // See testValidator() Message<?> message = MessageBuilder.withPayload("invalidValue".getBytes()).build(); thrown.expect(MethodArgumentNotValidException.class); this.resolver.resolveArgument(this.paramValidated, message); } @Test public void resolveFailValidationNoConversionNecessary() throws Exception { Message<?> message = MessageBuilder.withPayload("invalidValue").build(); thrown.expect(MethodArgumentNotValidException.class); this.resolver.resolveArgument(this.paramValidated, message); } @Test public void resolveNonAnnotatedParameter() throws Exception { Message<?> notEmptyMessage = MessageBuilder.withPayload("ABC".getBytes()).build(); assertEquals("ABC", this.resolver.resolveArgument(this.paramNotAnnotated, notEmptyMessage)); Message<?> emptyStringMessage = MessageBuilder.withPayload("").build(); thrown.expect(MethodArgumentNotValidException.class); this.resolver.resolveArgument(this.paramValidated, emptyStringMessage); } @Test public void resolveNonAnnotatedParameterFailValidation() throws Exception { // See testValidator() Message<?> message = MessageBuilder.withPayload("invalidValue".getBytes()).build(); thrown.expect(MethodArgumentNotValidException.class); thrown.expectMessage("invalid value"); assertEquals("invalidValue", this.resolver.resolveArgument(this.paramValidatedNotAnnotated, message)); } private Validator testValidator() { return new Validator() { @Override public boolean supports(Class<?> clazz) { return String.class.isAssignableFrom(clazz); } @Override public void validate(Object target, Errors errors) { String value = (String) target; if ("invalidValue".equals(value)) { errors.reject("invalid value"); } } }; } @SuppressWarnings("unused") private void handleMessage( @Payload String param, @Payload(required=false) String paramNotRequired, @Payload(required=true) Locale nonConvertibleRequiredParam, @Payload("foo.bar") String paramWithSpelExpression, @MyValid @Payload String validParam, @Validated String validParamNotAnnotated, String paramNotAnnotated) { } @Validated @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface MyValid { } }