Polishing

This commit is contained in:
Juergen Hoeller
2015-07-30 17:52:33 +02:00
parent ce50fc59ee
commit 7575271075
45 changed files with 597 additions and 529 deletions

View File

@@ -125,8 +125,10 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
Executor executorToUse = this.defaultExecutor;
String qualifier = getExecutorQualifier(method);
if (StringUtils.hasLength(qualifier)) {
Assert.notNull(this.beanFactory, "BeanFactory must be set on " + getClass().getSimpleName() +
" to access qualified executor '" + qualifier + "'");
if (this.beanFactory == null) {
throw new IllegalStateException("BeanFactory must be set on " + getClass().getSimpleName() +
" to access qualified executor '" + qualifier + "'");
}
executorToUse = BeanFactoryAnnotationUtils.qualifiedBeanOfType(
this.beanFactory, Executor.class, qualifier);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -679,7 +679,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
if (Modifier.isStatic(factoryMethod.getModifiers()) == isStatic &&
factoryMethod.getName().equals(mbd.getFactoryMethodName()) &&
factoryMethod.getParameterTypes().length >= minNrOfArgs) {
// No declared type variables to inspect, so just process the standard return type.
// Declared type variables to inspect?
if (factoryMethod.getTypeParameters().length > 0) {
try {
// Fully resolve parameter names and argument values.
@@ -833,8 +833,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
/**
* Obtain a "shortcut" singleton FactoryBean instance to use for a
* {@code getObjectType()} call, without full initialization
* of the FactoryBean.
* {@code getObjectType()} call, without full initialization of the FactoryBean.
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @return the FactoryBean instance, or {@code null} to indicate
@@ -875,8 +874,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
/**
* Obtain a "shortcut" non-singleton FactoryBean instance to use for a
* {@code getObjectType()} call, without full initialization
* of the FactoryBean.
* {@code getObjectType()} call, without full initialization of the FactoryBean.
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @return the FactoryBean instance, or {@code null} to indicate

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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.
@@ -25,10 +25,10 @@ import org.springframework.util.Assert;
/**
* A {@link ScopeMetadataResolver} implementation that by default checks for
* the presence of Spring's {@link Scope} annotation on the bean class.
* the presence of Spring's {@link Scope @Scope} annotation on the bean class.
*
* <p>The exact type of annotation that is checked for is configurable via the
* {@link #setScopeAnnotationType(Class)} property.
* <p>The exact type of annotation that is checked for is configurable via
* {@link #setScopeAnnotationType(Class)}.
*
* @author Mark Fisher
* @author Juergen Hoeller
@@ -43,7 +43,7 @@ public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
/**
* Create a new instance of the {@code AnnotationScopeMetadataResolver} class.
* Construct a new {@code AnnotationScopeMetadataResolver}.
* @see #AnnotationScopeMetadataResolver(ScopedProxyMode)
* @see ScopedProxyMode#NO
*/
@@ -52,8 +52,9 @@ public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
}
/**
* Create a new instance of the {@code AnnotationScopeMetadataResolver} class.
* @param defaultProxyMode the desired scoped-proxy mode
* Construct a new {@code AnnotationScopeMetadataResolver} using the
* supplied default {@link ScopedProxyMode}.
* @param defaultProxyMode the default scoped-proxy mode
*/
public AnnotationScopeMetadataResolver(ScopedProxyMode defaultProxyMode) {
Assert.notNull(defaultProxyMode, "'defaultProxyMode' must not be null");
@@ -63,7 +64,7 @@ public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
/**
* Set the type of annotation that is checked for by this
* {@link AnnotationScopeMetadataResolver}.
* {@code AnnotationScopeMetadataResolver}.
* @param scopeAnnotationType the target annotation type
*/
public void setScopeAnnotationType(Class<? extends Annotation> scopeAnnotationType) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -138,11 +138,11 @@ import org.springframework.core.Ordered;
public @interface EnableAsync {
/**
* Indicate the 'async' annotation type to be detected at either class
* or method level. By default, both the {@link Async} annotation and
* the EJB 3.1 {@code javax.ejb.Asynchronous} annotation will be
* detected. <p>This setter property exists so that developers can provide
* their own (non-Spring-specific) annotation type to indicate that a method
* Indicate the 'async' annotation type to be detected at either class or
* method level. By default, both the {@link Async} annotation and the
* EJB 3.1 {@code javax.ejb.Asynchronous} annotation will be detected.
* <p>This setter property exists so that developers can provide their
* own (non-Spring-specific) annotation type to indicate that a method
* (or all methods of a given class) should be invoked asynchronously.
*/
Class<? extends Annotation> annotation() default Annotation.class;
@@ -151,7 +151,6 @@ public @interface EnableAsync {
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}. <strong>
* Applicable only if {@link #mode()} is set to {@link AdviceMode#PROXY}</strong>.
*
* <p>Note that setting this attribute to {@code true} will affect <em>all</em>
* Spring-managed beans requiring proxying, not just those marked with {@code @Async}.
* For example, other beans marked with Spring's {@code @Transactional} annotation
@@ -176,4 +175,5 @@ public @interface EnableAsync {
* existing proxies rather than double-proxy.
*/
int order() default Ordered.LOWEST_PRECEDENCE;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -23,13 +23,12 @@ import org.springframework.context.annotation.Role;
import org.springframework.scheduling.config.TaskManagementConfigUtils;
/**
* {@code @Configuration} class that registers a {@link
* ScheduledAnnotationBeanPostProcessor} bean capable of processing Spring's @{@link
* Scheduled} annotation.
* {@code @Configuration} class that registers a {@link ScheduledAnnotationBeanPostProcessor}
* bean capable of processing Spring's @{@link Scheduled} annotation.
*
* <p>This configuration class is automatically imported when using the @{@link
* EnableScheduling} annotation. See {@code @EnableScheduling} Javadoc for complete usage
* details.
* <p>This configuration class is automatically imported when using the
* @{@link EnableScheduling} annotation. See {@code @EnableScheduling}'s javadoc
* for complete usage details.
*
* @author Chris Beams
* @since 3.1

View File

@@ -543,7 +543,7 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
* Return the primary Validator to apply after each binding step, if any.
*/
public Validator getValidator() {
return this.validators.size() > 0 ? this.validators.get(0) : null;
return (this.validators.size() > 0 ? this.validators.get(0) : null);
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -67,17 +67,6 @@ public class EnableAsyncTests {
asyncBean.work();
}
@Configuration
@EnableAsync
static class AsyncConfig {
@Bean
public AsyncBean asyncBean() {
return new AsyncBean();
}
}
@Test
public void withAsyncBeanWithExecutorQualifiedByName() throws ExecutionException, InterruptedException {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
@@ -95,49 +84,6 @@ public class EnableAsyncTests {
assertThat(workerThread3.get().getName(), startsWith("otherExecutor-"));
}
static class AsyncBeanWithExecutorQualifiedByName {
@Async
public Future<Thread> work0() {
return new AsyncResult<Thread>(Thread.currentThread());
}
@Async("e1")
public Future<Thread> work() {
return new AsyncResult<Thread>(Thread.currentThread());
}
@Async("otherExecutor")
public Future<Thread> work2() {
return new AsyncResult<Thread>(Thread.currentThread());
}
@Async("e2")
public Future<Thread> work3() {
return new AsyncResult<Thread>(Thread.currentThread());
}
}
static class AsyncBean {
private Thread threadOfExecution;
@Async
public void work() {
this.threadOfExecution = Thread.currentThread();
}
@Async
public void fail() {
throw new UnsupportedOperationException();
}
public Thread getThreadOfExecution() {
return threadOfExecution;
}
}
@Test
public void asyncProcessorIsOrderedLowestPrecedenceByDefault() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
@@ -148,7 +94,6 @@ public class EnableAsyncTests {
assertThat(bpp.getOrder(), is(Ordered.LOWEST_PRECEDENCE));
}
@Test
public void orderAttributeIsPropagated() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
@@ -159,17 +104,6 @@ public class EnableAsyncTests {
assertThat(bpp.getOrder(), is(Ordered.HIGHEST_PRECEDENCE));
}
@Configuration
@EnableAsync(order=Ordered.HIGHEST_PRECEDENCE)
static class OrderedAsyncConfig {
@Bean
public AsyncBean asyncBean() {
return new AsyncBean();
}
}
@Test
public void customAsyncAnnotationIsPropagated() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
@@ -188,51 +122,16 @@ public class EnableAsyncTests {
assertTrue("bean was not async advised as expected", isAsyncAdvised);
}
@Configuration
@EnableAsync(annotation=CustomAsync.class)
static class CustomAsyncAnnotationConfig {
@Bean
public CustomAsyncBean asyncBean() {
return new CustomAsyncBean();
}
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface CustomAsync {
}
static class CustomAsyncBean {
@CustomAsync
public void work() {
}
}
/**
* Fails with classpath errors on trying to classload AnnotationAsyncExecutionAspect
*/
@Test(expected=BeanDefinitionStoreException.class)
@Test(expected = BeanDefinitionStoreException.class)
public void aspectModeAspectJAttemptsToRegisterAsyncAspect() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AspectJAsyncAnnotationConfig.class);
ctx.refresh();
}
@Configuration
@EnableAsync(mode=AdviceMode.ASPECTJ)
static class AspectJAsyncAnnotationConfig {
@Bean
public AsyncBean asyncBean() {
return new AsyncBean();
}
}
@Test
public void customExecutorIsPropagated() throws InterruptedException {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
@@ -257,9 +156,112 @@ public class EnableAsyncTests {
}
static class AsyncBeanWithExecutorQualifiedByName {
@Async
public Future<Thread> work0() {
return new AsyncResult<Thread>(Thread.currentThread());
}
@Async("e1")
public Future<Thread> work() {
return new AsyncResult<Thread>(Thread.currentThread());
}
@Async("otherExecutor")
public Future<Thread> work2() {
return new AsyncResult<Thread>(Thread.currentThread());
}
@Async("e2")
public Future<Thread> work3() {
return new AsyncResult<Thread>(Thread.currentThread());
}
}
static class AsyncBean {
private Thread threadOfExecution;
@Async
public void work() {
this.threadOfExecution = Thread.currentThread();
}
@Async
public void fail() {
throw new UnsupportedOperationException();
}
public Thread getThreadOfExecution() {
return threadOfExecution;
}
}
@Configuration
@EnableAsync(annotation = CustomAsync.class)
static class CustomAsyncAnnotationConfig {
@Bean
public CustomAsyncBean asyncBean() {
return new CustomAsyncBean();
}
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface CustomAsync {
}
static class CustomAsyncBean {
@CustomAsync
public void work() {
}
}
@Configuration
@EnableAsync(order = Ordered.HIGHEST_PRECEDENCE)
static class OrderedAsyncConfig {
@Bean
public AsyncBean asyncBean() {
return new AsyncBean();
}
}
@Configuration
@EnableAsync(mode = AdviceMode.ASPECTJ)
static class AspectJAsyncAnnotationConfig {
@Bean
public AsyncBean asyncBean() {
return new AsyncBean();
}
}
@Configuration
@EnableAsync
static class AsyncConfig {
@Bean
public AsyncBean asyncBean() {
return new AsyncBean();
}
}
@Configuration
@EnableAsync
static class CustomExecutorAsyncConfig implements AsyncConfigurer {
@Bean
public AsyncBean asyncBean() {
return new AsyncBean();
@@ -275,7 +277,7 @@ public class EnableAsyncTests {
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return exceptionHandler();
return exceptionHandler();
}
@Bean
@@ -288,6 +290,7 @@ public class EnableAsyncTests {
@Configuration
@EnableAsync
static class AsyncWithExecutorQualifiedByNameConfig {
@Bean
public AsyncBeanWithExecutorQualifiedByName asyncBean() {
return new AsyncBeanWithExecutorQualifiedByName();
@@ -295,15 +298,14 @@ public class EnableAsyncTests {
@Bean
public Executor e1() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
return executor;
return new ThreadPoolTaskExecutor();
}
@Bean
@Qualifier("e2")
public Executor otherExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
return executor;
return new ThreadPoolTaskExecutor();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 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.
@@ -41,6 +41,7 @@ import static org.junit.Assert.*;
* Tests use of @EnableScheduling on @Configuration classes.
*
* @author Chris Beams
* @author Sam Brannen
* @since 3.1
*/
public class EnableSchedulingTests {
@@ -50,6 +51,7 @@ public class EnableSchedulingTests {
Assume.group(TestGroup.PERFORMANCE);
}
@Test
public void withFixedRateTask() throws InterruptedException {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
@@ -138,12 +140,17 @@ public class EnableSchedulingTests {
ctx.register(AmbiguousExplicitSchedulerConfig.class);
try {
ctx.refresh();
} catch (IllegalStateException ex) {
}
catch (IllegalStateException ex) {
assertThat(ex.getMessage(), startsWith("More than one TaskScheduler"));
throw ex;
}
finally {
ctx.close();
}
}
@EnableScheduling @Configuration
static class AmbiguousExplicitSchedulerConfig {
@@ -236,6 +243,7 @@ public class EnableSchedulingTests {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(SchedulingEnabled_withAmbiguousTaskSchedulers_butNoActualTasks.class);
ctx.refresh();
ctx.close();
}
@@ -265,10 +273,14 @@ public class EnableSchedulingTests {
ctx.register(SchedulingEnabled_withAmbiguousTaskSchedulers_andSingleTask.class);
try {
ctx.refresh();
} catch (IllegalStateException ex) {
assertThat(ex.getMessage(), startsWith("More than one TaskScheduler and/or"));
}
catch (IllegalStateException ex) {
assertThat(ex.getMessage(), startsWith("More than one TaskScheduler"));
throw ex;
}
finally {
ctx.close();
}
}
@@ -295,6 +307,7 @@ public class EnableSchedulingTests {
}
}
@Test
public void withAmbiguousTaskSchedulers_andSingleTask_disambiguatedByScheduledTaskRegistrarBean() throws InterruptedException {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
@@ -476,6 +489,7 @@ public class EnableSchedulingTests {
}
}
@Test
public void withInitiallyDelayedFixedRateTask() throws InterruptedException {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
@@ -486,8 +500,8 @@ public class EnableSchedulingTests {
AtomicInteger counter = ctx.getBean(AtomicInteger.class);
ctx.close();
assertThat(counter.get(), greaterThan(0)); // the @Scheduled method was called
assertThat(counter.get(), lessThanOrEqualTo(10)); // but not more than times the delay allows
assertThat(counter.get(), greaterThan(0)); // the @Scheduled method was called
assertThat(counter.get(), lessThanOrEqualTo(10)); // but not more than times the delay allows
}

View File

@@ -30,8 +30,9 @@ import org.springframework.util.Assert;
/**
* Helper class that encapsulates the specification of a method parameter, i.e.
* a Method or Constructor plus a parameter index and a nested type index for
* a declared generic type. Useful as a specification object to pass along.
* a {@link Method} or {@link Constructor} plus a parameter index and a nested
* type index for a declared generic type. Useful as a specification object to
* pass along.
*
* @author Juergen Hoeller
* @author Rob Harrop
@@ -66,20 +67,22 @@ public class MethodParameter {
/**
* Create a new MethodParameter for the given method, with nesting level 1.
* Create a new {@code MethodParameter} for the given method, with nesting level 1.
* @param method the Method to specify a parameter for
* @param parameterIndex the index of the parameter
* @param parameterIndex the index of the parameter: -1 for the method
* return type; 0 for the first method parameter; 1 for the second method
* parameter, etc.
*/
public MethodParameter(Method method, int parameterIndex) {
this(method, parameterIndex, 1);
}
/**
* Create a new MethodParameter for the given method.
* Create a new {@code MethodParameter} for the given method.
* @param method the Method to specify a parameter for
* @param parameterIndex the index of the parameter
* (-1 for the method return type; 0 for the first method parameter,
* 1 for the second method parameter, etc)
* @param parameterIndex the index of the parameter: -1 for the method
* return type; 0 for the first method parameter; 1 for the second method
* parameter, etc.
* @param nestingLevel the nesting level of the target type
* (typically 1; e.g. in case of a List of Lists, 1 would indicate the
* nested List, whereas 2 would indicate the element of the nested List)
@@ -197,7 +200,7 @@ public class MethodParameter {
/**
* Return the index of the method/constructor parameter.
* @return the parameter index (never negative)
* @return the parameter index (-1 in case of the return type)
*/
public int getParameterIndex() {
return this.parameterIndex;

View File

@@ -129,6 +129,7 @@ public class AntPathMatcher implements PathMatcher {
* turn it off when encountering too many patterns to cache at runtime
* (the threshold is 65536), assuming that arbitrary permutations of patterns
* are coming in, with little chance for encountering a recurring pattern.
* @since 4.0.1
* @see #getStringMatcher(String)
*/
public void setCachePatterns(boolean cachePatterns) {
@@ -413,18 +414,18 @@ public class AntPathMatcher implements PathMatcher {
public Map<String, String> extractUriTemplateVariables(String pattern, String path) {
Map<String, String> variables = new LinkedHashMap<String, String>();
boolean result = doMatch(pattern, path, true, variables);
Assert.state(result, "Pattern \"" + pattern + "\" is not a match for \"" + path + "\"");
if (!result) {
throw new IllegalStateException("Pattern \"" + pattern + "\" is not a match for \"" + path + "\"");
}
return variables;
}
/**
* Combine two patterns into a new pattern.
*
* <p>This implementation simply concatenates the two patterns, unless
* the first pattern contains a file extension match (e.g., {@code *.html}).
* In that case, the second pattern will be merged into the first. Otherwise,
* an {@code IllegalArgumentException} will be thrown.
*
* <h3>Examples</h3>
* <table border="1">
* <tr><th>Pattern 1</th><th>Pattern 2</th><th>Result</th></tr>
@@ -442,7 +443,6 @@ public class AntPathMatcher implements PathMatcher {
* <tr><td>/*.html</td><td>/hotels</td><td>/hotels.html</td></tr>
* <tr><td>/*.html</td><td>/*.txt</td><td>{@code IllegalArgumentException}</td></tr>
* </table>
*
* @param pattern1 the first pattern
* @param pattern2 the second pattern
* @return the combination of the two patterns
@@ -484,6 +484,7 @@ public class AntPathMatcher implements PathMatcher {
// simply concatenate the two patterns
return concat(pattern1, pattern2);
}
String extension1 = pattern1.substring(starDotPos1 + 1);
int dotPos2 = pattern2.indexOf('.');
String fileName2 = (dotPos2 == -1 ? pattern2 : pattern2.substring(0, dotPos2));
@@ -508,14 +509,18 @@ public class AntPathMatcher implements PathMatcher {
}
/**
* Given a full path, returns a {@link Comparator} suitable for sorting patterns in order of explicitness.
* <p>The returned {@code Comparator} will {@linkplain java.util.Collections#sort(java.util.List,
* java.util.Comparator) sort} a list so that more specific patterns (without uri templates or wild cards) come before
* generic patterns. So given a list with the following patterns: <ol> <li>{@code /hotels/new}</li>
* <li>{@code /hotels/{hotel}}</li> <li>{@code /hotels/*}</li> </ol> the returned comparator will sort this
* list so that the order will be as indicated.
* <p>The full path given as parameter is used to test for exact matches. So when the given path is {@code /hotels/2},
* the pattern {@code /hotels/2} will be sorted before {@code /hotels/1}.
* Given a full path, returns a {@link Comparator} suitable for sorting patterns in order of
* explicitness.
* <p>This{@code Comparator} will {@linkplain java.util.Collections#sort(List, Comparator) sort}
* a list so that more specific patterns (without uri templates or wild cards) come before
* generic patterns. So given a list with the following patterns:
* <ol>
* <li>{@code /hotels/new}</li>
* <li>{@code /hotels/{hotel}}</li> <li>{@code /hotels/*}</li>
* </ol>
* the returned comparator will sort this list so that the order will be as indicated.
* <p>The full path given as parameter is used to test for exact matches. So when the given path
* is {@code /hotels/2}, the pattern {@code /hotels/2} will be sorted before {@code /hotels/1}.
* @param path the full path to use for comparison
* @return a comparator capable of sorting patterns in order of explicitness
*/
@@ -542,11 +547,11 @@ public class AntPathMatcher implements PathMatcher {
public AntPathStringMatcher(String pattern) {
StringBuilder patternBuilder = new StringBuilder();
Matcher m = GLOB_PATTERN.matcher(pattern);
Matcher matcher = GLOB_PATTERN.matcher(pattern);
int end = 0;
while (m.find()) {
patternBuilder.append(quote(pattern, end, m.start()));
String match = m.group();
while (matcher.find()) {
patternBuilder.append(quote(pattern, end, matcher.start()));
String match = matcher.group();
if ("?".equals(match)) {
patternBuilder.append('.');
}
@@ -557,7 +562,7 @@ public class AntPathMatcher implements PathMatcher {
int colonIdx = match.indexOf(':');
if (colonIdx == -1) {
patternBuilder.append(DEFAULT_VARIABLE_PATTERN);
this.variableNames.add(m.group(1));
this.variableNames.add(matcher.group(1));
}
else {
String variablePattern = match.substring(colonIdx + 1, match.length() - 1);
@@ -568,7 +573,7 @@ public class AntPathMatcher implements PathMatcher {
this.variableNames.add(variableName);
}
}
end = m.end();
end = matcher.end();
}
patternBuilder.append(quote(pattern, end, pattern.length()));
this.pattern = Pattern.compile(patternBuilder.toString());
@@ -590,10 +595,12 @@ public class AntPathMatcher implements PathMatcher {
if (matcher.matches()) {
if (uriTemplateVariables != null) {
// SPR-8455
Assert.isTrue(this.variableNames.size() == matcher.groupCount(),
"The number of capturing groups in the pattern segment " + this.pattern +
" does not match the number of URI template variables it defines, which can occur if " +
" capturing groups are used in a URI template regex. Use non-capturing groups instead.");
if (this.variableNames.size() != matcher.groupCount()) {
throw new IllegalArgumentException("The number of capturing groups in the pattern segment " +
this.pattern + " does not match the number of URI template variables it defines, " +
"which can occur if capturing groups are used in a URI template regex. " +
"Use non-capturing groups instead.");
}
for (int i = 1; i <= matcher.groupCount(); i++) {
String name = this.variableNames.get(i - 1);
String value = matcher.group(i);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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,7 +17,7 @@
package org.springframework.expression;
/**
* Super class for exceptions that can occur whilst processing expressions
* Super class for exceptions that can occur whilst processing expressions.
*
* @author Andy Clement
* @since 3.0
@@ -27,11 +27,11 @@ public class ExpressionException extends RuntimeException {
protected String expressionString;
protected int position; // -1 if not known - but should be known in all reasonable cases
protected int position; // -1 if not known - but should be known in all reasonable cases
/**
* Creates a new expression exception.
* Construct a new expression exception.
* @param expressionString the expression string
* @param message a descriptive message
*/
@@ -42,7 +42,7 @@ public class ExpressionException extends RuntimeException {
}
/**
* Creates a new expression exception.
* Construct a new expression exception.
* @param expressionString the expression string
* @param position the position in the expression string where the problem occurred
* @param message a descriptive message
@@ -54,7 +54,7 @@ public class ExpressionException extends RuntimeException {
}
/**
* Creates a new expression exception.
* Construct a new expression exception.
* @param position the position in the expression string where the problem occurred
* @param message a descriptive message
*/
@@ -64,7 +64,7 @@ public class ExpressionException extends RuntimeException {
}
/**
* Creates a new expression exception.
* Construct a new expression exception.
* @param position the position in the expression string where the problem occurred
* @param message a descriptive message
* @param cause the underlying cause of this exception
@@ -75,21 +75,40 @@ public class ExpressionException extends RuntimeException {
}
/**
* Creates a new expression exception.
* Construct a new expression exception.
* @param message a descriptive message
*/
public ExpressionException(String message) {
super(message);
}
/**
* Construct a new expression exception.
* @param message a descriptive message
* @param cause the underlying cause of this exception
*/
public ExpressionException(String message, Throwable cause) {
super(message,cause);
}
/**
* Return the exception message. Since Spring 4.0 this method returns the same
* result as {@link #toDetailedString()}.
* Return the expression string.
*/
public final String getExpressionString() {
return this.expressionString;
}
/**
* Return the position in the expression string where the problem occurred.
*/
public final int getPosition() {
return this.position;
}
/**
* Return the exception message. Since Spring 4.0 this method returns the
* same result as {@link #toDetailedString()}.
* @see java.lang.Throwable#getMessage()
*/
@Override
@@ -98,35 +117,34 @@ public class ExpressionException extends RuntimeException {
}
/**
* Return the exception simple message without including the expression that caused
* the failure.
* Return a detailed description of this exception, including the expression
* String and position (if available) as well as the actual exception message.
*/
public String toDetailedString() {
if (this.expressionString != null) {
StringBuilder output = new StringBuilder();
output.append("Expression '");
output.append(this.expressionString);
output.append("'");
if (this.position != -1) {
output.append(" @ ");
output.append(this.position);
}
output.append(": ");
output.append(getSimpleMessage());
return output.toString();
}
else {
return getSimpleMessage();
}
}
/**
* Return the exception simple message without including the expression
* that caused the failure.
*/
public String getSimpleMessage() {
return super.getMessage();
}
public String toDetailedString() {
StringBuilder output = new StringBuilder();
if (this.expressionString!=null) {
output.append("Expression '");
output.append(this.expressionString);
output.append("'");
if (this.position!=-1) {
output.append(" @ ");
output.append(this.position);
}
output.append(": ");
}
output.append(getSimpleMessage());
return output.toString();
}
public final String getExpressionString() {
return this.expressionString;
}
public final int getPosition() {
return this.position;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -56,7 +56,7 @@ public class CodeFlow implements Opcodes {
* will be called after the main evaluation function has finished being generated.
*/
private List<FieldAdder> fieldAdders = null;
/**
* As SpEL ast nodes are called to generate code for the main evaluation method
* they can register to add code to a static initializer in the class. Any
@@ -64,19 +64,19 @@ public class CodeFlow implements Opcodes {
* has finished being generated.
*/
private List<ClinitAdder> clinitAdders = null;
/**
* Name of the class being generated. Typically used when generating code
* that accesses freshly generated fields on the generated type.
*/
private String clazzName;
/**
* When code generation requires holding a value in a class level field, this
* is used to track the next available field id (used as a name suffix).
*/
private int nextFieldId = 1;
/**
* When code generation requires an intermediate variable within a method,
* this method records the next available variable (variable 0 is 'this').
@@ -211,7 +211,7 @@ public class CodeFlow implements Opcodes {
/**
* Create the JVM signature descriptor for a method. This consists of the descriptors
* for the constructor parameters surrounded with parentheses, followed by the
* for the method parameters surrounded with parentheses, followed by the
* descriptor for the return type. Note the descriptors here are JVM descriptors,
* unlike the other descriptor forms the compiler is using which do not include the
* trailing semicolon.
@@ -232,11 +232,12 @@ public class CodeFlow implements Opcodes {
/**
* Create the JVM signature descriptor for a constructor. This consists of the
* descriptors for the constructor parameters surrounded with parentheses. Note the
* descriptors for the constructor parameters surrounded with parentheses, followed by
* the descriptor for the return type, which is always "V". Note the
* descriptors here are JVM descriptors, unlike the other descriptor forms the
* compiler is using which do not include the trailing semicolon.
* @param ctor the constructor
* @return a String signature descriptor (e.g. "(ILjava/lang/String;)")
* @return a String signature descriptor (e.g. "(ILjava/lang/String;)V")
*/
public static String createSignatureDescriptor(Constructor<?> ctor) {
Class<?>[] params = ctor.getParameterTypes();
@@ -657,7 +658,7 @@ public class CodeFlow implements Opcodes {
}
return descriptors;
}
/**
* Called after the main expression evaluation method has been generated, this
* method will callback any registered FieldAdders or ClinitAdders to add any
@@ -695,7 +696,7 @@ public class CodeFlow implements Opcodes {
}
/**
* Register a ClinitAdder which will add code to the static
* Register a ClinitAdder which will add code to the static
* initializer in the generated class to support the code
* produced by an ast nodes primary generateCode() method.
*/
@@ -717,11 +718,11 @@ public class CodeFlow implements Opcodes {
public String getClassname() {
return clazzName;
}
public interface FieldAdder {
public void generateField(ClassWriter cw, CodeFlow codeflow);
}
public interface ClinitAdder {
public void generateCode(MethodVisitor mv, CodeFlow codeflow);
}
@@ -743,11 +744,11 @@ public class CodeFlow implements Opcodes {
}
else {
mv.visitLdcInsn(value);
}
}
}
/**
* Produce appropriate bytecode to store a stack item in an array. The
* Produce appropriate bytecode to store a stack item in an array. The
* instruction to use varies depending on whether the type
* is a primitive or reference type.
* @param mv where to insert the bytecode
@@ -781,7 +782,7 @@ public class CodeFlow implements Opcodes {
public static int arrayCodeFor(String arraytype) {
switch (arraytype.charAt(0)) {
case 'I': return T_INT;
case 'J': return T_LONG;
case 'J': return T_LONG;
case 'F': return T_FLOAT;
case 'D': return T_DOUBLE;
case 'B': return T_BYTE;
@@ -805,9 +806,9 @@ public class CodeFlow implements Opcodes {
}
return false;
}
/**
* Produce the correct bytecode to build an array. The opcode to use and the
* Produce the correct bytecode to build an array. The opcode to use and the
* signature to pass along with the opcode can vary depending on the signature
* of the array type.
* @param mv the methodvisitor into which code should be inserted
@@ -825,7 +826,8 @@ public class CodeFlow implements Opcodes {
// is [[I then we want [I and not [I;
if (CodeFlow.isReferenceTypeArray(arraytype)) {
mv.visitTypeInsn(ANEWARRAY, arraytype+";");
} else {
}
else {
mv.visitTypeInsn(ANEWARRAY, arraytype);
}
}
@@ -835,5 +837,4 @@ public class CodeFlow implements Opcodes {
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -37,8 +37,10 @@ import static org.junit.Assert.*;
public class InitializeDatabaseIntegrationTests {
private String enabled;
private ClassPathXmlApplicationContext context;
@Before
public void init() {
enabled = System.setProperty("ENABLED", "true");
@@ -48,7 +50,8 @@ public class InitializeDatabaseIntegrationTests {
public void after() {
if (enabled != null) {
System.setProperty("ENABLED", enabled);
} else {
}
else {
System.clearProperty("ENABLED");
}
if (context != null) {
@@ -56,6 +59,7 @@ public class InitializeDatabaseIntegrationTests {
}
}
@Test
public void testCreateEmbeddedDatabase() throws Exception {
context = new ClassPathXmlApplicationContext("org/springframework/jdbc/config/jdbc-initialize-config.xml");
@@ -107,13 +111,15 @@ public class InitializeDatabaseIntegrationTests {
}
private void assertCorrectSetup(DataSource dataSource) {
JdbcTemplate t = new JdbcTemplate(dataSource);
assertEquals(1, t.queryForObject("select count(*) from T_TEST", Integer.class).intValue());
JdbcTemplate jt = new JdbcTemplate(dataSource);
assertEquals(1, jt.queryForObject("select count(*) from T_TEST", Integer.class).intValue());
}
public static class CacheData implements InitializingBean {
private JdbcTemplate jdbcTemplate;
private List<Map<String,Object>> cache;
public void setDataSource(DataSource dataSource) {
@@ -128,7 +134,6 @@ public class InitializeDatabaseIntegrationTests {
public void afterPropertiesSet() throws Exception {
cache = jdbcTemplate.queryForList("SELECT * FROM T_TEST");
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -120,7 +120,7 @@ public class JmsMessagingTemplate extends AbstractMessagingTemplate<Destination>
* to convert the payload of the message.
* <p>Consider configuring a {@link MessagingMessageConverter} with a different
* {@link MessagingMessageConverter#setPayloadConverter(MessageConverter) payload converter}
* for more advanced scenario.
* for more advanced scenarios.
* @see org.springframework.jms.support.converter.MessagingMessageConverter
*/
public void setJmsMessageConverter(MessageConverter jmsMessageConverter) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -40,8 +40,8 @@ import org.springframework.jms.support.destination.DynamicDestinationResolver;
import org.springframework.util.Assert;
/**
* An abstract {@link MessageListener} adapter providing the necessary infrastructure
* to extract the payload of a {@link Message}
* An abstract JMS {@link MessageListener} adapter providing the necessary
* infrastructure to extract the payload of a JMS {@link Message}.
*
* @author Juergen Hoeller
* @author Stephane Nicoll
@@ -217,7 +217,7 @@ public abstract class AbstractAdaptableMessageListener
return message;
}
catch (JMSException ex) {
throw new MessageConversionException("Could not unmarshal message", ex);
throw new MessageConversionException("Could not convert JMS message", ex);
}
}
@@ -246,10 +246,12 @@ public abstract class AbstractAdaptableMessageListener
sendResponse(session, destination, response);
}
catch (Exception ex) {
throw new ReplyFailureException("Failed to send reply with payload '" + result + "'", ex);
throw new ReplyFailureException("Failed to send reply with payload [" + result + "]", ex);
}
}
else {
// No JMS Session available
if (logger.isWarnEnabled()) {
logger.warn("Listener method returned result [" + result +
"]: not generating response message for it because of no JMS Session given");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -77,7 +77,7 @@ public class MessagingMessageListenerAdapter extends AbstractAdaptableMessageLis
return (Message<?>) getMessagingMessageConverter().fromMessage(jmsMessage);
}
catch (JMSException ex) {
throw new MessageConversionException("Could not unmarshal message", ex);
throw new MessageConversionException("Could not convert JMS message", ex);
}
}
@@ -90,8 +90,8 @@ public class MessagingMessageListenerAdapter extends AbstractAdaptableMessageLis
return this.handlerMethod.invoke(message, jmsMessage, session);
}
catch (MessagingException ex) {
throw new ListenerExecutionFailedException(createMessagingErrorMessage("Listener method could not " +
"be invoked with the incoming message"), ex);
throw new ListenerExecutionFailedException(
createMessagingErrorMessage("Listener method could not be invoked with incoming message"), ex);
}
catch (Exception ex) {
throw new ListenerExecutionFailedException("Listener method '" +

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -31,11 +31,11 @@ import org.springframework.messaging.MessageHeaders;
public interface MessageConverter {
/**
* Convert the payload of a {@link Message} from serialized form to a typed Object of
* the specified target class. The {@link MessageHeaders#CONTENT_TYPE} header should
* indicate the MIME type to convert from.
* <p>If the converter does not support the specified media type or cannot perform the
* conversion, it should return {@code null}.
* Convert the payload of a {@link Message} from a serialized form to a typed Object
* of the specified target class. The {@link MessageHeaders#CONTENT_TYPE} header
* should indicate the MIME type to convert from.
* <p>If the converter does not support the specified media type or cannot perform
* the conversion, it should return {@code null}.
* @param message the input message
* @param targetClass the target class for the conversion
* @return the result of the conversion, or {@code null} if the converter cannot
@@ -47,15 +47,15 @@ public interface MessageConverter {
* Create a {@link Message} whose payload is the result of converting the given
* payload Object to serialized form. The optional {@link MessageHeaders} parameter
* may contain a {@link MessageHeaders#CONTENT_TYPE} header to specify the target
* media type for the conversion and it may contain additional headers to be added to
* the message.
* <p>If the converter does not support the specified media type or cannot perform the
* conversion, it should return {@code null}.
* media type for the conversion and it may contain additional headers to be added
* to the message.
* <p>If the converter does not support the specified media type or cannot perform
* the conversion, it should return {@code null}.
* @param payload the Object to convert
* @param header optional headers for the message, may be {@code null}
* @return the new message or {@code null} if the converter does not support the
* @param headers optional headers for the message (may be {@code null})
* @return the new message, or {@code null} if the converter does not support the
* Object type or the target media type
*/
Message<?> toMessage(Object payload, MessageHeaders header);
Message<?> toMessage(Object payload, MessageHeaders headers);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -37,8 +37,8 @@ import org.springframework.validation.Validator;
* The default {@link MessageHandlerMethodFactory} implementation creating an
* {@link InvocableHandlerMethod} with the necessary
* {@link HandlerMethodArgumentResolver} instances to detect and process
* most of the use cases defined by
* {@link org.springframework.messaging.handler.annotation.MessageMapping MessageMapping}
* most of the use cases defined by
* {@link org.springframework.messaging.handler.annotation.MessageMapping MessageMapping}.
*
* <p>Extra method argument resolvers can be added to customize the method
* signature that can be handled.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -22,10 +22,11 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.messaging.Message;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
import org.springframework.util.ClassUtils;
/**
* A {@link HandlerMethodArgumentResolver} for {@link Message} parameters. Validates
* that the generic type of the payload matches with the message value.
* A {@link HandlerMethodArgumentResolver} for {@link Message} parameters.
* Validates that the generic type of the payload matches with the message value.
*
* @author Rossen Stoyanchev
* @author Stephane Nicoll
@@ -33,7 +34,6 @@ import org.springframework.messaging.handler.invocation.HandlerMethodArgumentRes
*/
public class MessageMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return Message.class.isAssignableFrom(parameter.getParameterType());
@@ -41,22 +41,19 @@ public class MessageMethodArgumentResolver implements HandlerMethodArgumentResol
@Override
public Object resolveArgument(MethodParameter parameter, Message<?> message) throws Exception {
Class<?> paramType = parameter.getParameterType();
if (!paramType.isAssignableFrom(message.getClass())) {
throw new MethodArgumentTypeMismatchException(message, parameter,
"The actual message type [" + message.getClass().getName() + "] " +
"does not match the expected type [" + paramType.getName() + "]");
"The actual message type [" + ClassUtils.getQualifiedName(message.getClass()) + "] " +
"does not match the expected type [" + ClassUtils.getQualifiedName(paramType) + "]");
}
Class<?> expectedPayloadType = getPayloadType(parameter);
Object payload = message.getPayload();
if (expectedPayloadType != null && !expectedPayloadType.isInstance(payload)) {
if (payload != null && expectedPayloadType != null && !expectedPayloadType.isInstance(payload)) {
throw new MethodArgumentTypeMismatchException(message, parameter,
"The expected Message<?> payload type [" + expectedPayloadType.getName() +
"] does not match the actual payload type [" + payload.getClass().getName() + "]");
"The expected Message<?> payload type [" + ClassUtils.getQualifiedName(expectedPayloadType) +
"] does not match the actual payload type [" + ClassUtils.getQualifiedName(payload.getClass()) + "]");
}
return message;

View File

@@ -455,7 +455,9 @@ public abstract class AbstractMethodMessageHandler<T>
processHandlerMethodException(handlerMethod, ex, message);
}
catch (Throwable ex) {
logger.error("Error while processing message " + message, ex);
if (logger.isErrorEnabled()) {
logger.error("Error while processing message " + message, ex);
}
}
}
@@ -495,9 +497,7 @@ public abstract class AbstractMethodMessageHandler<T>
protected abstract AbstractExceptionHandlerMethodResolver createExceptionHandlerMethodResolverFor(Class<?> beanType);
protected void handleNoMatch(Set<T> ts, String lookupDestination, Message<?> message) {
if (logger.isDebugEnabled()) {
logger.debug("No matching methods.");
}
logger.debug("No matching methods.");
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -46,7 +46,6 @@ public interface SimpMessageSendingOperations extends MessageSendingOperations<S
/**
* Send a message to the given user.
*
* @param user the user that should receive the message.
* @param destination the destination to send the message to.
* @param payload the payload to send
@@ -55,13 +54,11 @@ public interface SimpMessageSendingOperations extends MessageSendingOperations<S
/**
* Send a message to the given user.
*
* <p>By default headers are interpreted as native headers (e.g. STOMP) and
* are saved under a special key in the resulting Spring
* {@link org.springframework.messaging.Message Message}. In effect when the
* message leaves the application, the provided headers are included with it
* and delivered to the destination (e.g. the STOMP client or broker).
*
* <p>If the map already contains the key
* {@link org.springframework.messaging.support.NativeMessageHeaderAccessor#NATIVE_HEADERS "nativeHeaders"}
* or was prepared with
@@ -69,36 +66,31 @@ public interface SimpMessageSendingOperations extends MessageSendingOperations<S
* then the headers are used directly. A common expected case is providing a
* content type (to influence the message conversion) and native headers.
* This may be done as follows:
*
* <pre class="code">
* SimpMessageHeaderAccessor accessor = SimpMessageHeaderAccessor.create();
* accessor.setContentType(MimeTypeUtils.TEXT_PLAIN);
* accessor.setNativeHeader("foo", "bar");
* accessor.setLeaveMutable(true);
* MessageHeaders headers = accessor.getMessageHeaders();
*
* messagingTemplate.convertAndSendToUser(user, destination, payload, headers);
* </pre>
*
* <p><strong>Note:</strong> if the {@code MessageHeaders} are mutable as in
* the above example, implementations of this interface should take notice and
* update the headers in the same instance (rather than copy or re-create it)
* and then set it immutable before sending the final message.
*
* @param user the user that should receive the message, must not be {@code null}
* @param destination the destination to send the message to, must not be {@code null}
* @param payload the payload to send, may be {@code null}
* @param headers the message headers, may be {@code null}
* @param user the user that should receive the message (must not be {@code null})
* @param destination the destination to send the message to (must not be {@code null})
* @param payload the payload to send (may be {@code null})
* @param headers the message headers (may be {@code null})
*/
void convertAndSendToUser(String user, String destination, Object payload, Map<String, Object> headers)
throws MessagingException;
/**
* Send a message to the given user.
*
* @param user the user that should receive the message, must not be {@code null}
* @param destination the destination to send the message to, must not be {@code null}
* @param payload the payload to send, may be {@code null}
* @param user the user that should receive the message (must not be {@code null})
* @param destination the destination to send the message to (must not be {@code null})
* @param payload the payload to send (may be {@code null})
* @param postProcessor a postProcessor to post-process or modify the created message
*/
void convertAndSendToUser(String user, String destination, Object payload,
@@ -106,12 +98,10 @@ public interface SimpMessageSendingOperations extends MessageSendingOperations<S
/**
* Send a message to the given user.
*
* <p>See {@link #convertAndSend(Object, Object, java.util.Map)} for important
* notes regarding the input headers.
*
* @param user the user that should receive the message.
* @param destination the destination to send the message to.
* @param user the user that should receive the message
* @param destination the destination to send the message to
* @param payload the payload to send
* @param headers the message headers
* @param postProcessor a postProcessor to post-process or modify the created message

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -35,16 +35,16 @@ import org.springframework.messaging.simp.user.DestinationUserNameProvider;
import org.springframework.messaging.support.MessageHeaderInitializer;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* A {@link HandlerMethodReturnValueHandler} for sending to destinations specified in a
* {@link SendTo} or {@link SendToUser} method-level annotations.
*
* <p>The value returned from the method is converted, and turned to a {@link Message} and
* sent through the provided {@link MessageChannel}. The
* message is then enriched with the sessionId of the input message as well as the
* destination from the annotation(s). If multiple destinations are specified, a copy of
* the message is sent to each destination.
* sent through the provided {@link MessageChannel}. The message is then enriched with the
* session id of the input message as well as the destination from the annotation(s).
* If multiple destinations are specified, a copy of the message is sent to each destination.
*
* @author Rossen Stoyanchev
* @since 4.0
@@ -108,7 +108,6 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
/**
* Configure a {@link MessageHeaderInitializer} to apply to the headers of all
* messages sent to the client outbound channel.
*
* <p>By default this property is not set.
*/
public void setHeaderInitializer(MessageHeaderInitializer headerInitializer) {
@@ -125,8 +124,8 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
@Override
public boolean supportsReturnType(MethodParameter returnType) {
if ((returnType.getMethodAnnotation(SendTo.class) != null) ||
(returnType.getMethodAnnotation(SendToUser.class) != null)) {
if (returnType.getMethodAnnotation(SendTo.class) != null ||
returnType.getMethodAnnotation(SendToUser.class) != null) {
return true;
}
return (!this.annotationRequired);
@@ -137,10 +136,11 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
if (returnValue == null) {
return;
}
MessageHeaders headers = message.getHeaders();
String sessionId = SimpMessageHeaderAccessor.getSessionId(headers);
SendToUser sendToUser = returnType.getMethodAnnotation(SendToUser.class);
if (sendToUser != null) {
boolean broadcast = sendToUser.broadcast();
String user = getUserName(message, headers);
@@ -188,7 +188,9 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
}
String name = DestinationPatternsMessageCondition.LOOKUP_DESTINATION_HEADER;
String destination = (String) message.getHeaders().get(name);
Assert.hasText(destination, "No lookup destination header in " + message);
if (!StringUtils.hasText(destination)) {
throw new IllegalStateException("No lookup destination header in " + message);
}
return (destination.startsWith("/") ?
new String[] {defaultPrefix + destination} : new String[] {defaultPrefix + "/" + destination});

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -102,13 +102,14 @@ public class SubscriptionMethodReturnValueHandler implements HandlerMethodReturn
String sessionId = SimpMessageHeaderAccessor.getSessionId(headers);
String subscriptionId = SimpMessageHeaderAccessor.getSubscriptionId(headers);
Assert.state(subscriptionId != null,
"No subscriptionId in message=" + message + ", method=" + returnType.getMethod());
if (subscriptionId == null) {
throw new IllegalStateException(
"No subscriptionId in " + message + " returned by: " + returnType.getMethod());
}
if (logger.isDebugEnabled()) {
logger.debug("Reply to @SubscribeMapping: " + returnValue);
}
this.messagingTemplate.convertAndSend(destination, returnValue, createHeaders(sessionId, subscriptionId));
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -145,6 +145,7 @@ public class MessageMethodArgumentResolverTests {
assertSame(message, this.resolver.resolveArgument(parameter, message));
}
@SuppressWarnings("unused")
private void handleMessage(
Message<?> wildcardPayload,

View File

@@ -88,8 +88,8 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
private static final Method withRulesMethod;
static {
withRulesMethod = ReflectionUtils.findMethod(SpringJUnit4ClassRunner.class, "withRules", FrameworkMethod.class,
Object.class, Statement.class);
withRulesMethod = ReflectionUtils.findMethod(SpringJUnit4ClassRunner.class, "withRules",
FrameworkMethod.class, Object.class, Statement.class);
if (withRulesMethod == null) {
throw new IllegalStateException(
"Failed to find withRules() method: SpringJUnit4ClassRunner requires JUnit 4.9 or higher.");
@@ -101,7 +101,7 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
/**
* Constructs a new {@code SpringJUnit4ClassRunner} and initializes a
* Construct a new {@code SpringJUnit4ClassRunner} and initialize a
* {@link TestContextManager} to provide Spring testing functionality to
* standard JUnit tests.
* @param clazz the test class to be run
@@ -110,13 +110,13 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
public SpringJUnit4ClassRunner(Class<?> clazz) throws InitializationError {
super(clazz);
if (logger.isDebugEnabled()) {
logger.debug("SpringJUnit4ClassRunner constructor called with [" + clazz + "].");
logger.debug("SpringJUnit4ClassRunner constructor called with [" + clazz + "]");
}
this.testContextManager = createTestContextManager(clazz);
}
/**
* Creates a new {@link TestContextManager} for the supplied test class.
* Create a new {@link TestContextManager} for the supplied test class.
* <p>Can be overridden by subclasses.
* @param clazz the test class to be managed
*/
@@ -132,9 +132,9 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Returns a description suitable for an ignored test class if the test is
* Return a description suitable for an ignored test class if the test is
* disabled via {@code @IfProfileValue} at the class-level, and
* otherwise delegates to the parent implementation.
* otherwise delegate to the parent implementation.
* @see ProfileValueUtils#isTestEnabledInThisEnvironment(Class)
*/
@Override
@@ -146,10 +146,10 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Check whether the test is enabled in the first place. This prevents
* classes with a non-matching {@code @IfProfileValue} annotation from
* running altogether, even skipping the execution of
* {@code prepareTestInstance()} {@code TestExecutionListener} methods.
* Check whether the test is enabled in the current execution environment.
* <p>This prevents classes with a non-matching {@code @IfProfileValue}
* annotation from running altogether, even skipping the execution of
* {@code prepareTestInstance()} methods in {@code TestExecutionListeners}.
* @see ProfileValueUtils#isTestEnabledInThisEnvironment(Class)
* @see org.springframework.test.annotation.IfProfileValue
* @see org.springframework.test.context.TestExecutionListener
@@ -164,9 +164,9 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Wraps the {@link Statement} returned by the parent implementation with a
* {@link RunBeforeTestClassCallbacks} statement, thus preserving the
* default functionality but adding support for the Spring TestContext
* Wrap the {@link Statement} returned by the parent implementation with a
* {@code RunBeforeTestClassCallbacks} statement, thus preserving the
* default JUnit functionality while adding support for the Spring TestContext
* Framework.
* @see RunBeforeTestClassCallbacks
*/
@@ -177,9 +177,9 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Wraps the {@link Statement} returned by the parent implementation with a
* {@link RunAfterTestClassCallbacks} statement, thus preserving the default
* functionality but adding support for the Spring TestContext Framework.
* Wrap the {@link Statement} returned by the parent implementation with a
* {@code RunAfterTestClassCallbacks} statement, thus preserving the default
* JUnit functionality while adding support for the Spring TestContext Framework.
* @see RunAfterTestClassCallbacks
*/
@Override
@@ -189,10 +189,10 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Delegates to the parent implementation for creating the test instance and
* then allows the {@link #getTestContextManager() TestContextManager} to
* Delegate to the parent implementation for creating the test instance and
* then allow the {@link #getTestContextManager() TestContextManager} to
* prepare the test instance before returning it.
* @see TestContextManager#prepareTestInstance(Object)
* @see TestContextManager#prepareTestInstance
*/
@Override
protected Object createTest() throws Exception {
@@ -202,7 +202,7 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Performs the same logic as
* Perform the same logic as
* {@link BlockJUnit4ClassRunner#runChild(FrameworkMethod, RunNotifier)},
* except that tests are determined to be <em>ignored</em> by
* {@link #isTestMethodIgnored(FrameworkMethod)}.
@@ -226,25 +226,26 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Augments the default JUnit behavior
* {@link #withPotentialRepeat(FrameworkMethod, Object, Statement) with
* potential repeats} of the entire execution chain.
* <p>Furthermore, support for timeouts has been moved down the execution chain
* in order to include execution of {@link org.junit.Before @Before}
* and {@link org.junit.After @After} methods within the timed
* execution. Note that this differs from the default JUnit behavior of
* executing {@code @Before} and {@code @After} methods
* in the main thread while executing the actual test method in a separate
* thread. Thus, the end effect is that {@code @Before} and
* {@code @After} methods will be executed in the same thread as
* the test method. As a consequence, JUnit-specified timeouts will work
* fine in combination with Spring transactions. Note that JUnit-specific
* timeouts still differ from Spring-specific timeouts in that the former
* execute in a separate thread while the latter simply execute in the main
* thread (like regular tests).
* Augment the default JUnit behavior
* {@linkplain #withPotentialRepeat with potential repeats} of the entire
* execution chain.
* <p>Furthermore, support for timeouts has been moved down the execution
* chain in order to include execution of {@link org.junit.Before @Before}
* and {@link org.junit.After @After} methods within the timed execution.
* Note that this differs from the default JUnit behavior of executing
* {@code @Before} and {@code @After} methods in the main thread while
* executing the actual test method in a separate thread. Thus, the net
* effect is that {@code @Before} and {@code @After} methods will be
* executed in the same thread as the test method. As a consequence,
* JUnit-specified timeouts will work fine in combination with Spring
* transactions. However, JUnit-specific timeouts still differ from
* Spring-specific timeouts in that the former execute in a separate
* thread while the latter simply execute in the main thread (like regular
* tests).
* @see #possiblyExpectingExceptions(FrameworkMethod, Object, Statement)
* @see #withBefores(FrameworkMethod, Object, Statement)
* @see #withAfters(FrameworkMethod, Object, Statement)
* @see #withRulesReflectively(FrameworkMethod, Object, Statement)
* @see #withPotentialRepeat(FrameworkMethod, Object, Statement)
* @see #withPotentialTimeout(FrameworkMethod, Object, Statement)
*/
@@ -253,7 +254,6 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
Object testInstance;
try {
testInstance = new ReflectiveCallable() {
@Override
protected Object runReflectiveCall() throws Throwable {
return createTest();
@@ -271,7 +271,6 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
statement = withRulesReflectively(frameworkMethod, testInstance, statement);
statement = withPotentialRepeat(frameworkMethod, testInstance, statement);
statement = withPotentialTimeout(frameworkMethod, testInstance, statement);
return statement;
}
@@ -283,19 +282,19 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Returns {@code true} if {@link Ignore @Ignore} is present for the supplied
* {@link FrameworkMethod test method} or if the test method is disabled via
* {@code @IfProfileValue}.
* Return {@code true} if {@link Ignore @Ignore} is present for the supplied
* {@linkplain FrameworkMethod test method} or if the test method is disabled
* via {@code @IfProfileValue}.
* @see ProfileValueUtils#isTestEnabledInThisEnvironment(Method, Class)
*/
protected boolean isTestMethodIgnored(FrameworkMethod frameworkMethod) {
Method method = frameworkMethod.getMethod();
return (method.isAnnotationPresent(Ignore.class) || !ProfileValueUtils.isTestEnabledInThisEnvironment(method,
getTestClass().getJavaClass()));
return (method.isAnnotationPresent(Ignore.class) ||
!ProfileValueUtils.isTestEnabledInThisEnvironment(method, getTestClass().getJavaClass()));
}
/**
* Performs the same logic as
* Perform the same logic as
* {@link BlockJUnit4ClassRunner#possiblyExpectingExceptions(FrameworkMethod, Object, Statement)}
* except that the <em>expected exception</em> is retrieved using
* {@link #getExpectedException(FrameworkMethod)}.
@@ -303,29 +302,30 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
@Override
protected Statement possiblyExpectingExceptions(FrameworkMethod frameworkMethod, Object testInstance, Statement next) {
Class<? extends Throwable> expectedException = getExpectedException(frameworkMethod);
return expectedException != null ? new ExpectException(next, expectedException) : next;
return (expectedException != null ? new ExpectException(next, expectedException) : next);
}
/**
* Get the {@code exception} that the supplied {@link FrameworkMethod
* Get the {@code exception} that the supplied {@linkplain FrameworkMethod
* test method} is expected to throw.
* <p>Supports JUnit's {@link Test#expected() @Test(expected=...)} annotation.
* <p>Can be overridden by subclasses.
* @return the expected exception, or {@code null} if none was specified
*/
protected Class<? extends Throwable> getExpectedException(FrameworkMethod frameworkMethod) {
Test testAnnotation = frameworkMethod.getAnnotation(Test.class);
Class<? extends Throwable> junitExpectedException = (testAnnotation != null
&& testAnnotation.expected() != Test.None.class ? testAnnotation.expected() : null);
return junitExpectedException;
Test test = frameworkMethod.getAnnotation(Test.class);
return (test != null && test.expected() != Test.None.class ? test.expected() : null);
}
/**
* Supports both Spring's {@link Timed @Timed} and JUnit's
* {@link Test#timeout() @Test(timeout=...)} annotations, but not both
* simultaneously. Returns either a {@link SpringFailOnTimeout}, a
* {@link FailOnTimeout}, or the unmodified, supplied {@link Statement} as
* appropriate.
* Perform the same logic as
* {@link BlockJUnit4ClassRunner#withPotentialTimeout(FrameworkMethod, Object, Statement)}
* but with additional support for Spring's {@code @Timed} annotation.
* <p>Supports both Spring's {@link org.springframework.test.annotation.Timed @Timed}
* and JUnit's {@link Test#timeout() @Test(timeout=...)} annotations, but not both
* simultaneously.
* @return either a {@link SpringFailOnTimeout}, a {@link FailOnTimeout},
* or the supplied {@link Statement} as appropriate
* @see #getSpringTimeout(FrameworkMethod)
* @see #getJUnitTimeout(FrameworkMethod)
*/
@@ -335,10 +335,9 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
long springTimeout = getSpringTimeout(frameworkMethod);
long junitTimeout = getJUnitTimeout(frameworkMethod);
if (springTimeout > 0 && junitTimeout > 0) {
String msg = "Test method [" + frameworkMethod.getMethod()
+ "] has been configured with Spring's @Timed(millis=" + springTimeout
+ ") and JUnit's @Test(timeout=" + junitTimeout
+ ") annotations. Only one declaration of a 'timeout' is permitted per test method.";
String msg = String.format("Test method [%s] has been configured with Spring's @Timed(millis=%s) and " +
"JUnit's @Test(timeout=%s) annotations, but only one declaration of a 'timeout' is " +
"permitted per test method.", frameworkMethod.getMethod(), springTimeout, junitTimeout);
logger.error(msg);
throw new IllegalStateException(msg);
}
@@ -356,37 +355,37 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Retrieves the configured JUnit {@code timeout} from the {@link Test @Test}
* annotation on the supplied {@link FrameworkMethod test method}.
* @return the timeout, or {@code 0} if none was specified.
* Retrieve the configured JUnit {@code timeout} from the {@link Test @Test}
* annotation on the supplied {@linkplain FrameworkMethod test method}.
* @return the timeout, or {@code 0} if none was specified
*/
protected long getJUnitTimeout(FrameworkMethod frameworkMethod) {
Test testAnnotation = frameworkMethod.getAnnotation(Test.class);
return (testAnnotation != null && testAnnotation.timeout() > 0 ? testAnnotation.timeout() : 0);
Test test = frameworkMethod.getAnnotation(Test.class);
return (test != null && test.timeout() > 0 ? test.timeout() : 0);
}
/**
* Retrieves the configured Spring-specific {@code timeout} from the
* {@link Timed @Timed} annotation on the supplied
* {@link FrameworkMethod test method}.
* @return the timeout, or {@code 0} if none was specified.
* Retrieve the configured Spring-specific {@code timeout} from the
* {@link org.springframework.test.annotation.Timed @Timed} annotation
* on the supplied {@linkplain FrameworkMethod test method}.
* @return the timeout, or {@code 0} if none was specified
*/
protected long getSpringTimeout(FrameworkMethod frameworkMethod) {
AnnotationAttributes annAttrs = AnnotatedElementUtils.getAnnotationAttributes(frameworkMethod.getMethod(),
Timed.class.getName());
AnnotationAttributes annAttrs = AnnotatedElementUtils.getAnnotationAttributes(
frameworkMethod.getMethod(), Timed.class.getName());
if (annAttrs == null) {
return 0;
}
else {
long millis = annAttrs.<Long> getNumber("millis").longValue();
return millis > 0 ? millis : 0;
return (millis > 0 ? millis : 0);
}
}
/**
* Wraps the {@link Statement} returned by the parent implementation with a
* {@link RunBeforeTestMethodCallbacks} statement, thus preserving the
* default functionality but adding support for the Spring TestContext
* Wrap the {@link Statement} returned by the parent implementation with a
* {@code RunBeforeTestMethodCallbacks} statement, thus preserving the
* default functionality while adding support for the Spring TestContext
* Framework.
* @see RunBeforeTestMethodCallbacks
*/
@@ -394,13 +393,13 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
protected Statement withBefores(FrameworkMethod frameworkMethod, Object testInstance, Statement statement) {
Statement junitBefores = super.withBefores(frameworkMethod, testInstance, statement);
return new RunBeforeTestMethodCallbacks(junitBefores, testInstance, frameworkMethod.getMethod(),
getTestContextManager());
getTestContextManager());
}
/**
* Wraps the {@link Statement} returned by the parent implementation with a
* {@link RunAfterTestMethodCallbacks} statement, thus preserving the
* default functionality but adding support for the Spring TestContext
* Wrap the {@link Statement} returned by the parent implementation with a
* {@code RunAfterTestMethodCallbacks} statement, thus preserving the
* default functionality while adding support for the Spring TestContext
* Framework.
* @see RunAfterTestMethodCallbacks
*/
@@ -408,13 +407,13 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
protected Statement withAfters(FrameworkMethod frameworkMethod, Object testInstance, Statement statement) {
Statement junitAfters = super.withAfters(frameworkMethod, testInstance, statement);
return new RunAfterTestMethodCallbacks(junitAfters, testInstance, frameworkMethod.getMethod(),
getTestContextManager());
getTestContextManager());
}
/**
* Supports Spring's {@link Repeat @Repeat} annotation by returning a
* {@link SpringRepeat} statement initialized with the configured repeat
* count or {@code 1} if no repeat count is configured.
* Wrap the supplied {@link Statement} with a {@code SpringRepeat} statement.
* <p>Supports Spring's {@link org.springframework.test.annotation.Repeat @Repeat}
* annotation.
* @see SpringRepeat
*/
protected Statement withPotentialRepeat(FrameworkMethod frameworkMethod, Object testInstance, Statement next) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -511,7 +511,7 @@ public abstract class AbstractPlatformTransactionManager implements PlatformTran
}
/**
* Create a rae TransactionStatus instance for the given arguments.
* Create a TransactionStatus instance for the given arguments.
*/
protected DefaultTransactionStatus newTransactionStatus(
TransactionDefinition definition, Object transaction, boolean newTransaction,

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,
@@ -785,7 +785,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
try {
return simpleDateFormat.parse(headerValue).getTime();
}
catch (ParseException e) {
catch (ParseException ex) {
// ignore
}
}
@@ -811,8 +811,8 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
*/
@Override
public String getFirst(String headerName) {
List<String> headerValues = headers.get(headerName);
return headerValues != null ? headerValues.get(0) : null;
List<String> headerValues = this.headers.get(headerName);
return (headerValues != null ? headerValues.get(0) : null);
}
/**
@@ -825,7 +825,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
*/
@Override
public void add(String headerName, String headerValue) {
List<String> headerValues = headers.get(headerName);
List<String> headerValues = this.headers.get(headerName);
if (headerValues == null) {
headerValues = new LinkedList<String>();
this.headers.put(headerName, headerValues);
@@ -845,7 +845,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
public void set(String headerName, String headerValue) {
List<String> headerValues = new LinkedList<String>();
headerValues.add(headerValue);
headers.put(headerName, headerValues);
this.headers.put(headerName, headerValues);
}
@Override
@@ -858,7 +858,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
@Override
public Map<String, String> toSingleValueMap() {
LinkedHashMap<String, String> singleValueMap = new LinkedHashMap<String,String>(this.headers.size());
for (Entry<String, List<String>> entry : headers.entrySet()) {
for (Entry<String, List<String>> entry : this.headers.entrySet()) {
singleValueMap.put(entry.getKey(), entry.getValue().get(0));
}
return singleValueMap;

View File

@@ -153,12 +153,14 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
this.messageConverters.add(new AtomFeedHttpMessageConverter());
this.messageConverters.add(new RssChannelHttpMessageConverter());
}
if (jackson2XmlPresent) {
messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
}
else if (jaxb2Present) {
this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (jackson2Present) {
this.messageConverters.add(new MappingJackson2HttpMessageConverter());
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -26,7 +26,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.MethodParameter;
import org.springframework.util.Assert;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
@@ -61,7 +60,7 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return getArgumentResolver(parameter) != null;
return (getArgumentResolver(parameter) != null);
}
/**
@@ -73,7 +72,9 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
Assert.notNull(resolver, "Unknown parameter type [" + parameter.getParameterType().getName() + "]");
if (resolver == null) {
throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]");
}
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2015 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.
@@ -23,39 +23,36 @@ import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.servlet.ModelAndView;
/**
* SPI for resolving custom return values from a specific handler method. Typically implemented to detect special return
* types, resolving well-known result values for them.
* SPI for resolving custom return values from a specific handler method.
* Typically implemented to detect special return types, resolving
* well-known result values for them.
*
* <p>A typical implementation could look like as follows:
*
* <pre class="code">
* public class MyModelAndViewResolver implements ModelAndViewResolver {
*
* public ModelAndView resolveModelAndView(Method handlerMethod,
* Class handlerType,
* Object returnValue,
* ExtendedModelMap implicitModel,
* NativeWebRequest webRequest) {
* if (returnValue instanceof MySpecialRetVal.class)) {
* return new MySpecialRetVal(returnValue);
* public ModelAndView resolveModelAndView(Method handlerMethod, Class handlerType,
* Object returnValue, ExtendedModelMap implicitModel, NativeWebRequest webRequest) {
* if (returnValue instanceof MySpecialRetVal.class)) {
* return new MySpecialRetVal(returnValue);
* }
* return UNRESOLVED;
* }
* return UNRESOLVED;
* }
* }</pre>
*
* @author Arjen Poutsma
* @see org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#setCustomModelAndViewResolvers
* @see org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter#setCustomModelAndViewResolvers
* @since 3.0
*/
public interface ModelAndViewResolver {
/** Marker to be returned when the resolver does not know how to handle the given method parameter. */
/**
* Marker to be returned when the resolver does not know how to handle the given method parameter.
*/
ModelAndView UNRESOLVED = new ModelAndView();
ModelAndView resolveModelAndView(Method handlerMethod,
Class<?> handlerType,
Object returnValue,
ExtendedModelMap implicitModel,
NativeWebRequest webRequest);
ModelAndView resolveModelAndView(Method handlerMethod, Class<?> handlerType, Object returnValue,
ExtendedModelMap implicitModel, NativeWebRequest webRequest);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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.
@@ -29,10 +29,13 @@ import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;
/**
* Implementation of the {@link org.springframework.web.servlet.HandlerExceptionResolver HandlerExceptionResolver}
* interface that uses the {@link ResponseStatus @ResponseStatus} annotation to map exceptions to HTTP status codes.
* A {@link org.springframework.web.servlet.HandlerExceptionResolver
* HandlerExceptionResolver} that uses the {@link ResponseStatus @ResponseStatus}
* annotation to map exceptions to HTTP status codes.
*
* <p>This exception resolver is enabled by default in the {@link org.springframework.web.servlet.DispatcherServlet}.
* <p>This exception resolver is enabled by default in the
* {@link org.springframework.web.servlet.DispatcherServlet DispatcherServlet}
* and the MVC Java config and the MVC namespace.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
@@ -48,6 +51,7 @@ public class ResponseStatusExceptionResolver extends AbstractHandlerExceptionRes
this.messageSource = messageSource;
}
@Override
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
@@ -65,16 +69,20 @@ public class ResponseStatusExceptionResolver extends AbstractHandlerExceptionRes
}
/**
* Template method that handles {@link ResponseStatus @ResponseStatus} annotation. <p>Default implementation send a
* response error using {@link HttpServletResponse#sendError(int)}, or {@link HttpServletResponse#sendError(int,
* String)} if the annotation has a {@linkplain ResponseStatus#reason() reason}. Returns an empty ModelAndView.
* Template method that handles {@link ResponseStatus @ResponseStatus} annotation.
* <p>The default implementation sends a response error using
* {@link HttpServletResponse#sendError(int)} or
* {@link HttpServletResponse#sendError(int, String)} if the annotation has a
* {@linkplain ResponseStatus#reason() reason} and then returns an empty ModelAndView.
* @param responseStatus the annotation
* @param request current HTTP request
* @param response current HTTP response
* @param handler the executed handler, or {@code null} if none chosen at the time of the exception
* (for example, if multipart resolution failed)
* @param ex the exception that got thrown during handler execution
* @return a corresponding ModelAndView to forward to, or {@code null} for default processing
* @param handler the executed handler, or {@code null} if none chosen at the
* time of the exception (for example, if multipart resolution failed)
* @param ex the exception that got thrown during handler execution or the
* exception that has the ResponseStatus annotation if found on the cause.
* @return a corresponding ModelAndView to forward to, or {@code null}
* for default processing
*/
protected ModelAndView resolveResponseStatus(ResponseStatus responseStatus, HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) throws Exception {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -103,8 +103,8 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
List<String> fileExtensions) {
this.patterns = Collections.unmodifiableSet(prependLeadingSlash(patterns));
this.pathHelper = urlPathHelper != null ? urlPathHelper : new UrlPathHelper();
this.pathMatcher = pathMatcher != null ? pathMatcher : new AntPathMatcher();
this.pathHelper = (urlPathHelper != null ? urlPathHelper : new UrlPathHelper());
this.pathMatcher = (pathMatcher != null ? pathMatcher : new AntPathMatcher());
this.useSuffixPatternMatch = useSuffixPatternMatch;
this.useTrailingSlashMatch = useTrailingSlashMatch;
if (fileExtensions != null) {
@@ -220,7 +220,6 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
* {@link #getMatchingCondition(javax.servlet.http.HttpServletRequest)}.
* This method is provided as an alternative to be used if no request is available
* (e.g. introspection, tooling, etc).
*
* @param lookupPath the lookup path to match to existing patterns
* @return a collection of matching patterns sorted with the closest match at the top
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -31,13 +31,13 @@ import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondit
/**
* Encapsulates the following request mapping conditions:
* <ol>
* <li>{@link PatternsRequestCondition}
* <li>{@link RequestMethodsRequestCondition}
* <li>{@link ParamsRequestCondition}
* <li>{@link HeadersRequestCondition}
* <li>{@link ConsumesRequestCondition}
* <li>{@link ProducesRequestCondition}
* <li>{@code RequestCondition} (optional, custom request condition)
* <li>{@link PatternsRequestCondition}
* <li>{@link RequestMethodsRequestCondition}
* <li>{@link ParamsRequestCondition}
* <li>{@link HeadersRequestCondition}
* <li>{@link ConsumesRequestCondition}
* <li>{@link ProducesRequestCondition}
* <li>{@code RequestCondition} (optional, custom request condition)
* </ol>
*
* @author Arjen Poutsma
@@ -266,21 +266,21 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (obj != null && obj instanceof RequestMappingInfo) {
RequestMappingInfo other = (RequestMappingInfo) obj;
return (this.patternsCondition.equals(other.patternsCondition) &&
this.methodsCondition.equals(other.methodsCondition) &&
this.paramsCondition.equals(other.paramsCondition) &&
this.headersCondition.equals(other.headersCondition) &&
this.consumesCondition.equals(other.consumesCondition) &&
this.producesCondition.equals(other.producesCondition) &&
this.customConditionHolder.equals(other.customConditionHolder));
if (!(other instanceof RequestMappingInfo)) {
return false;
}
return false;
RequestMappingInfo otherInfo = (RequestMappingInfo) other;
return (this.patternsCondition.equals(otherInfo.patternsCondition) &&
this.methodsCondition.equals(otherInfo.methodsCondition) &&
this.paramsCondition.equals(otherInfo.paramsCondition) &&
this.headersCondition.equals(otherInfo.headersCondition) &&
this.consumesCondition.equals(otherInfo.consumesCondition) &&
this.producesCondition.equals(otherInfo.producesCondition) &&
this.customConditionHolder.equals(otherInfo.customConditionHolder));
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -26,13 +26,13 @@ import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
/**
* A {@code ResponseBodyAdvice} implementation that adds support for
* Jackson's {@code @JsonView} annotation declared on a Spring MVC
* {@code @RequestMapping} or {@code @ExceptionHandler} method.
* A {@link ResponseBodyAdvice} implementation that adds support for Jackson's
* {@code @JsonView} annotation declared on a Spring MVC {@code @RequestMapping}
* or {@code @ExceptionHandler} method.
*
* <p>The serialization view specified in the annotation will be passed in to
* the {@code MappingJackson2HttpMessageConverter} which will then use it to
* serialize the response body with.
* <p>The serialization view specified in the annotation will be passed in to the
* {@link org.springframework.http.converter.json.MappingJackson2HttpMessageConverter}
* which will then use it to serialize the response body with.
*
* <p>Note that despite {@code @JsonView} allowing for more than one class to
* be specified, the use for a response body advice is only supported with
@@ -40,6 +40,7 @@ import org.springframework.http.server.ServerHttpResponse;
*
* @author Rossen Stoyanchev
* @since 4.1
* @see com.fasterxml.jackson.annotation.JsonView
* @see com.fasterxml.jackson.databind.ObjectMapper#writerWithView(Class)
*/
public class JsonViewResponseBodyAdvice extends AbstractMappingJacksonResponseBodyAdvice {

View File

@@ -99,13 +99,13 @@ import org.springframework.web.util.WebUtils;
/**
* An {@link AbstractHandlerMethodAdapter} that supports {@link HandlerMethod}s
* with the signature -- method argument and return types, defined in
* with their method argument and return type signature, as defined via
* {@code @RequestMapping}.
*
* <p>Support for custom argument and return value types can be added via
* {@link #setCustomArgumentResolvers} and {@link #setCustomReturnValueHandlers}.
* Or alternatively to re-configure all argument and return value types use
* {@link #setArgumentResolvers} and {@link #setReturnValueHandlers(List)}.
* Or alternatively, to re-configure all argument and return value types,
* use {@link #setArgumentResolvers} and {@link #setReturnValueHandlers}.
*
* @author Rossen Stoyanchev
* @since 3.1
@@ -697,12 +697,12 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
return invokeHandleMethod(request, response, handlerMethod);
return invokeHandlerMethod(request, response, handlerMethod);
}
}
}
return invokeHandleMethod(request, response, handlerMethod);
return invokeHandlerMethod(request, response, handlerMethod);
}
/**
@@ -739,8 +739,8 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
* Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView}
* if view resolution is required.
*/
private ModelAndView invokeHandleMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
private ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response,
HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
@@ -756,7 +756,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
final WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
@@ -766,7 +766,6 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
if (logger.isDebugEnabled()) {
logger.debug("Found concurrent result value [" + result + "]");
}
@@ -774,7 +773,6 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
}
requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -127,7 +127,6 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
}
/**
* Whether to use suffix pattern matching.
*/
@@ -229,7 +228,8 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
}
/**
* Created a RequestMappingInfo from a RequestMapping annotation.
* Create a {@link RequestMappingInfo} from the supplied
* {@link RequestMapping @RequestMapping} annotation.
*/
protected RequestMappingInfo createRequestMappingInfo(RequestMapping annotation, RequestCondition<?> customCondition) {
String[] patterns = resolveEmbeddedValuesInPatterns(annotation.value());

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -19,9 +19,9 @@ package org.springframework.web.servlet.view.groovy;
import groovy.text.markup.MarkupTemplateEngine;
/**
* Interface to be implemented by objects that configure and manage a
* Groovy MarkupTemplateEngine for automatic lookup in a web environment.
* Detected and used by GroovyMarkupView.
* Interface to be implemented by objects that configure and manage a Groovy
* {@link MarkupTemplateEngine} for automatic lookup in a web environment.
* Detected and used by {@link GroovyMarkupView}.
*
* @author Brian Clozel
* @since 4.1

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -46,7 +46,6 @@ import org.springframework.util.StringUtils;
*
* &#64;Bean
* public GroovyMarkupConfig groovyMarkupConfigurer() {
*
* GroovyMarkupConfigurer configurer = new GroovyMarkupConfigurer();
* configurer.setResourceLoaderPath("classpath:/WEB-INF/groovymarkup/");
* return configurer;
@@ -79,7 +78,7 @@ import org.springframework.util.StringUtils;
* @author Rossen Stoyanchev
* @since 4.1
* @see GroovyMarkupView
* @see <a href="http://beta.groovy-lang.org/docs/groovy-2.3.2/html/documentation/markup-template-engine.html">
* @see <a href="http://groovy-lang.org/templating.html#_the_markuptemplateengine">
* Groovy Markup Template engine documentation</a>
*/
public class GroovyMarkupConfigurer extends TemplateConfiguration

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -35,8 +35,7 @@ import org.springframework.web.servlet.view.AbstractTemplateView;
import org.springframework.web.util.NestedServletException;
/**
* An {@link org.springframework.web.servlet.view.AbstractTemplateView AbstractTemplateView}
* based on Groovy XML/XHTML markup templates.
* An {@link AbstractTemplateView} subclass based on Groovy XML/XHTML markup templates.
*
* <p>Spring's Groovy Markup Template support requires Groovy 2.3.1 and higher.
*
@@ -45,7 +44,7 @@ import org.springframework.web.util.NestedServletException;
* @since 4.1
* @see GroovyMarkupViewResolver
* @see GroovyMarkupConfigurer
* @see <a href="http://beta.groovy-lang.org/docs/groovy-2.3.2/html/documentation/markup-template-engine.html">
* @see <a href="http://groovy-lang.org/templating.html#_the_markuptemplateengine">
* Groovy Markup Template engine documentation</a>
*/
public class GroovyMarkupView extends AbstractTemplateView {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -21,10 +21,9 @@ import java.util.Locale;
import org.springframework.web.servlet.view.AbstractTemplateViewResolver;
/**
* Convenience subclass of
* {@link org.springframework.web.servlet.view.AbstractTemplateViewResolver}
* that supports {@link GroovyMarkupView} (i.e. Groovy XML/XHTML markup templates)
* and custom subclasses of it.
* Convenience subclass of @link AbstractTemplateViewResolver} that supports
* {@link GroovyMarkupView} (i.e. Groovy XML/XHTML markup templates) and
* custom subclasses of it.
*
* <p>The view class for all views created by this resolver can be specified
* via the {@link #setViewClass(Class)} property.

View File

@@ -1,6 +1,6 @@
/**
* Support classes for the integration of
* <a href="http://beta.groovy-lang.org/docs/groovy-2.3.0/html/documentation/markup-template-engine.html">
* <a href="http://docs.groovy-lang.org/docs/next/html/documentation/template-engines.html#_the_markuptemplateengine">
* Groovy Templates</a> as Spring web view technology.
* Contains a View implementation for Groovy templates.
*/

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2002-2015 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.web.socket.sockjs.client;
import java.net.URI;
@@ -15,10 +31,9 @@ public interface InfoReceiver {
/**
* Perform an HTTP request to the SockJS "Info" URL.
* and return the resulting JSON response content, or raise an exception.
*
* @param infoUrl the URL to obtain SockJS server information from
* @return the body of the response
*/
String executeInfoRequest(URI infoUrl);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.socket.sockjs.client;
package org.springframework.web.socket.sockjs.client;
import java.util.List;
@@ -40,7 +40,6 @@ public interface Transport {
/**
* Connect the transport.
*
* @param request the transport request.
* @param webSocketHandler the application handler to delegate lifecycle events to.
* @return a future to indicate success or failure to connect.

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2002-2015 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.web.socket.sockjs.client;
import java.net.URI;
@@ -8,8 +24,7 @@ import org.springframework.web.socket.TextMessage;
* A SockJS {@link Transport} that uses HTTP requests to simulate a WebSocket
* interaction. The {@code connect} method of the base {@code Transport} interface
* is used to receive messages from the server while the
* {@link #executeSendRequest(java.net.URI, org.springframework.web.socket.TextMessage)
* executeSendRequest(URI, TextMessage)} method here is used to send messages.
* {@link #executeSendRequest} method here is used to send messages.
*
* @author Rossen Stoyanchev
* @since 4.1
@@ -20,7 +35,6 @@ public interface XhrTransport extends Transport, InfoReceiver {
* An {@code XhrTransport} supports both the "xhr_streaming" and "xhr" SockJS
* server transports. From a client perspective there is no implementation
* difference.
*
* <p>By default an {@code XhrTransport} will be used with "xhr_streaming"
* first and then with "xhr", if the streaming fails to connect. In some
* cases it may be useful to suppress streaming so that only "xhr" is used.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -83,13 +83,12 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
@Override
protected Class<?>[] getAnnotatedConfigClasses() {
return new Class<?>[] { TestMessageBrokerConfiguration.class, TestMessageBrokerConfigurer.class };
return new Class<?>[] {TestMessageBrokerConfiguration.class, TestMessageBrokerConfigurer.class};
}
@Test
public void sendMessageToController() throws Exception {
TextMessage message = create(StompCommand.SEND).headers("destination:/app/simple").build();
WebSocketSession session = doHandshake(new TestClientWebSocketHandler(0, message), "/ws").get();
@@ -104,10 +103,8 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
@Test
public void sendMessageToControllerAndReceiveReplyViaTopic() throws Exception {
TextMessage message1 = create(StompCommand.SUBSCRIBE)
.headers("id:subs1", "destination:/topic/increment").build();
TextMessage message2 = create(StompCommand.SEND)
.headers("destination:/app/increment").body("5").build();
@@ -126,7 +123,6 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
@Test
public void sendMessageToBrokerAndReceiveReplyViaTopic() throws Exception {
TextMessage m1 = create(StompCommand.SUBSCRIBE).headers("id:subs1", "destination:/topic/foo").build();
TextMessage m2 = create(StompCommand.SEND).headers("destination:/topic/foo").body("5").build();
@@ -148,7 +144,6 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
@Test
public void sendSubscribeToControllerAndReceiveReply() throws Exception {
String destHeader = "destination:/app/number";
TextMessage message = create(StompCommand.SUBSCRIBE).headers("id:subs1", destHeader).build();
@@ -168,7 +163,6 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
@Test
public void handleExceptionAndSendToUser() throws Exception {
String destHeader = "destination:/user/queue/error";
TextMessage m1 = create(StompCommand.SUBSCRIBE).headers("id:subs1", destHeader).build();
TextMessage m2 = create(StompCommand.SEND).headers("destination:/app/exception").build();
@@ -178,7 +172,6 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
try {
assertTrue(clientHandler.latch.await(2, TimeUnit.SECONDS));
String payload = clientHandler.actual.get(0).getPayload();
assertTrue(payload.startsWith("MESSAGE\n"));
assertTrue(payload.contains("destination:/user/queue/error\n"));
@@ -191,10 +184,8 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
@Test
public void webSocketScope() throws Exception {
TextMessage message1 = create(StompCommand.SUBSCRIBE)
.headers("id:subs1", "destination:/topic/scopedBeanValue").build();
TextMessage message2 = create(StompCommand.SEND)
.headers("destination:/app/scopedBeanValue").build();
@@ -203,7 +194,6 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
try {
assertTrue(clientHandler.latch.await(2, TimeUnit.SECONDS));
String payload = clientHandler.actual.get(0).getPayload();
assertTrue(payload.startsWith("MESSAGE\n"));
assertTrue(payload.contains("destination:/topic/scopedBeanValue\n"));
@@ -221,6 +211,7 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
private @interface IntegrationTestController {
}
@IntegrationTestController
static class SimpleController {
@@ -243,6 +234,7 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
}
}
@IntegrationTestController
static class IncrementController {
@@ -257,6 +249,7 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
}
}
@IntegrationTestController
static class ScopedBeanController {
@@ -279,6 +272,7 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
String getValue();
}
static class ScopedBeanImpl implements ScopedBean {
private final String value;
@@ -304,7 +298,6 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
private final CountDownLatch latch;
public TestClientWebSocketHandler(int expectedNumberOfMessages, TextMessage... messagesToSend) {
this.messagesToSend = messagesToSend;
this.expected = expectedNumberOfMessages;
@@ -325,6 +318,7 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
}
}
@Configuration
@ComponentScan(
basePackageClasses=StompWebSocketIntegrationTests.class,
@@ -333,7 +327,7 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
static class TestMessageBrokerConfigurer extends AbstractWebSocketMessageBrokerConfigurer {
@Autowired
private HandshakeHandler handshakeHandler; // can't rely on classpath for server detection
private HandshakeHandler handshakeHandler; // can't rely on classpath for server detection
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
@@ -353,19 +347,20 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
}
}
@Configuration
static class TestMessageBrokerConfiguration extends DelegatingWebSocketMessageBrokerConfiguration {
@Override
@Bean
public AbstractSubscribableChannel clientInboundChannel() {
return new ExecutorSubscribableChannel(); // synchronous
return new ExecutorSubscribableChannel(); // synchronous
}
@Override
@Bean
public AbstractSubscribableChannel clientOutboundChannel() {
return new ExecutorSubscribableChannel(); // synchronous
return new ExecutorSubscribableChannel(); // synchronous
}
}