From c0040a5508a7b4b0c8d4f2e371802a0490aa5d11 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 18 Jul 2018 14:03:54 +0200 Subject: [PATCH] Polishing --- .../aop/framework/AdvisedSupport.java | 7 ++-- .../framework/DefaultAdvisorChainFactory.java | 32 ++++++++++----- .../adapter/AdvisorAdapterRegistry.java | 21 +++++----- .../SimpleAsyncUncaughtExceptionHandler.java | 8 ++-- .../config/AbstractJCacheConfiguration.java | 5 ++- .../cache/jcache/config/JCacheConfigurer.java | 4 +- .../config/JCacheConfigurerSupport.java | 4 +- .../cache/jcache/config/package-info.java | 5 +++ .../interceptor/AbstractCacheInterceptor.java | 3 +- ...AbstractFallbackJCacheOperationSource.java | 6 +-- .../interceptor/AbstractJCacheOperation.java | 2 +- .../AbstractKeyCacheInterceptor.java | 6 +-- .../AnnotationJCacheOperationSource.java | 41 +++++++++++-------- ...anFactoryJCacheOperationSourceAdvisor.java | 7 +++- .../interceptor/CachePutInterceptor.java | 12 +++--- .../jcache/interceptor/CachePutOperation.java | 14 +++++-- .../CacheRemoveAllInterceptor.java | 11 +++-- .../CacheRemoveEntryInterceptor.java | 17 ++++---- .../interceptor/CacheResultInterceptor.java | 17 +++++--- .../interceptor/CacheResultOperation.java | 8 +++- .../DefaultCacheKeyInvocationContext.java | 20 +++++---- .../DefaultJCacheOperationSource.java | 36 ++++++++++------ .../interceptor/JCacheAspectSupport.java | 38 ++++++++++++----- .../jcache/interceptor/JCacheInterceptor.java | 4 +- .../interceptor/JCacheOperationSource.java | 3 +- .../JCacheOperationSourcePointcut.java | 8 ++-- .../interceptor/KeyGeneratorAdapter.java | 11 ++++- .../jcache/interceptor/package-info.java | 5 +++ .../AnnotationCacheOperationSourceTests.java | 6 +-- .../annotation/CachingConfigurerSupport.java | 6 +-- ...tationDrivenCacheBeanDefinitionParser.java | 20 ++++----- .../cache/interceptor/CacheAspectSupport.java | 6 ++- .../annotation/AsyncAnnotationAdvisor.java | 4 +- .../validation/AbstractBindingResult.java | 5 +-- .../validation/BindException.java | 2 +- .../validation/BindingResult.java | 2 +- .../validation/DataBinder.java | 2 +- .../cache/config/EnableCachingTests.java | 30 ++++++-------- .../support/StringToLocaleConverter.java | 2 + .../util/ConcurrentReferenceHashMap.java | 4 +- .../support/WebExchangeBindException.java | 2 +- .../ModelAttributeMethodProcessor.java | 23 ++++++----- .../session/InMemoryWebSessionStore.java | 10 ++--- .../web/util/HierarchicalUriComponents.java | 1 - .../web/util/UriComponentsBuilder.java | 9 ++-- ...b2CollectionHttpMessageConverterTests.java | 8 ++-- ...2RootElementHttpMessageConverterTests.java | 19 ++++----- .../MarshallingHttpMessageConverterTests.java | 10 ++--- .../xml/SourceHttpMessageConverterTests.java | 15 +++---- ...stractMessageConverterMethodProcessor.java | 22 +++++----- ...MappingHandlerAdapterIntegrationTests.java | 15 ++----- .../RequestMappingHandlerAdapterTests.java | 6 +-- 52 files changed, 331 insertions(+), 253 deletions(-) diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java b/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java index 93e22e368b5..bd6df6bd86f 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java @@ -22,7 +22,6 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -94,7 +93,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised { * List of Advisors. If an Advice is added, it will be wrapped * in an Advisor before being added to this List. */ - private List advisors = new LinkedList<>(); + private List advisors = new ArrayList<>(); /** * Array updated on changes to the advisors list, which is easier @@ -474,7 +473,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised { * for the given method, based on this configuration. * @param method the proxied method * @param targetClass the target class - * @return List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers) + * @return a List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers) */ public List getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class targetClass) { MethodCacheKey cacheKey = new MethodCacheKey(method); @@ -528,7 +527,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised { /** * Build a configuration-only copy of this AdvisedSupport, - * replacing the TargetSource + * replacing the TargetSource. */ AdvisedSupport getConfigurationOnlyCopy() { AdvisedSupport copy = new AdvisedSupport(); diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAdvisorChainFactory.java b/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAdvisorChainFactory.java index decf2e55a3e..586051bc78a 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAdvisorChainFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAdvisorChainFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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. @@ -27,11 +27,11 @@ import org.aopalliance.intercept.MethodInterceptor; import org.springframework.aop.Advisor; import org.springframework.aop.IntroductionAdvisor; +import org.springframework.aop.IntroductionAwareMethodMatcher; import org.springframework.aop.MethodMatcher; import org.springframework.aop.PointcutAdvisor; import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry; import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry; -import org.springframework.aop.support.MethodMatchers; import org.springframework.lang.Nullable; /** @@ -53,19 +53,30 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ // This is somewhat tricky... We have to process introductions first, // but we need to preserve order in the ultimate list. - List interceptorList = new ArrayList<>(config.getAdvisors().length); - Class actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); - boolean hasIntroductions = hasMatchingIntroductions(config, actualClass); AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); + Advisor[] advisors = config.getAdvisors(); + List interceptorList = new ArrayList<>(advisors.length); + Class actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); + Boolean hasIntroductions = null; - for (Advisor advisor : config.getAdvisors()) { + for (Advisor advisor : advisors) { if (advisor instanceof PointcutAdvisor) { // Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { - MethodInterceptor[] interceptors = registry.getInterceptors(advisor); MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); - if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) { + boolean match; + if (mm instanceof IntroductionAwareMethodMatcher) { + if (hasIntroductions == null) { + hasIntroductions = hasMatchingIntroductions(advisors, actualClass); + } + match = ((IntroductionAwareMethodMatcher) mm).matches(method, targetClass, hasIntroductions); + } + else { + match = mm.matches(method, targetClass); + } + if (match) { + MethodInterceptor[] interceptors = registry.getInterceptors(advisor); if (mm.isRuntime()) { // Creating a new object instance in the getInterceptors() method // isn't a problem as we normally cache created chains. @@ -98,9 +109,8 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ /** * Determine whether the Advisors contain matching introductions. */ - private static boolean hasMatchingIntroductions(Advised config, Class actualClass) { - for (int i = 0; i < config.getAdvisors().length; i++) { - Advisor advisor = config.getAdvisors()[i]; + private static boolean hasMatchingIntroductions(Advisor[] advisors, Class actualClass) { + for (Advisor advisor : advisors) { if (advisor instanceof IntroductionAdvisor) { IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (ia.getClassFilter().matches(actualClass)) { diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/adapter/AdvisorAdapterRegistry.java b/spring-aop/src/main/java/org/springframework/aop/framework/adapter/AdvisorAdapterRegistry.java index 9eacf479bad..97ff108d831 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/adapter/AdvisorAdapterRegistry.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/adapter/AdvisorAdapterRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2018 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,15 +31,15 @@ import org.springframework.aop.Advisor; public interface AdvisorAdapterRegistry { /** - * Return an Advisor wrapping the given advice. + * Return an {@link Advisor} wrapping the given advice. *

Should by default at least support * {@link org.aopalliance.intercept.MethodInterceptor}, * {@link org.springframework.aop.MethodBeforeAdvice}, * {@link org.springframework.aop.AfterReturningAdvice}, * {@link org.springframework.aop.ThrowsAdvice}. * @param advice object that should be an advice - * @return an Advisor wrapping the given advice. Never returns {@code null}. - * If the advice parameter is an Advisor, return it. + * @return an Advisor wrapping the given advice (never {@code null}; + * if the advice parameter is an Advisor, it is to be returned as-is) * @throws UnknownAdviceTypeException if no registered advisor adapter * can wrap the supposed advice */ @@ -48,21 +48,20 @@ public interface AdvisorAdapterRegistry { /** * Return an array of AOP Alliance MethodInterceptors to allow use of the * given Advisor in an interception-based framework. - *

Don't worry about the pointcut associated with the Advisor, - * if it's a PointcutAdvisor: just return an interceptor. + *

Don't worry about the pointcut associated with the {@link Advisor}, if it is + * a {@link org.springframework.aop.PointcutAdvisor}: just return an interceptor. * @param advisor Advisor to find an interceptor for * @return an array of MethodInterceptors to expose this Advisor's behavior * @throws UnknownAdviceTypeException if the Advisor type is - * not understood by any registered AdvisorAdapter. + * not understood by any registered AdvisorAdapter */ MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException; /** - * Register the given AdvisorAdapter. Note that it is not necessary to register + * Register the given {@link AdvisorAdapter}. Note that it is not necessary to register * adapters for an AOP Alliance Interceptors or Spring Advices: these must be - * automatically recognized by an AdvisorAdapterRegistry implementation. - * @param adapter AdvisorAdapter that understands a particular Advisor - * or Advice types + * automatically recognized by an {@code AdvisorAdapterRegistry} implementation. + * @param adapter AdvisorAdapter that understands particular Advisor or Advice types */ void registerAdvisorAdapter(AdvisorAdapter adapter); diff --git a/spring-aop/src/main/java/org/springframework/aop/interceptor/SimpleAsyncUncaughtExceptionHandler.java b/spring-aop/src/main/java/org/springframework/aop/interceptor/SimpleAsyncUncaughtExceptionHandler.java index dffba79e80e..e77f84b4357 100644 --- a/spring-aop/src/main/java/org/springframework/aop/interceptor/SimpleAsyncUncaughtExceptionHandler.java +++ b/spring-aop/src/main/java/org/springframework/aop/interceptor/SimpleAsyncUncaughtExceptionHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2018 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,13 +29,13 @@ import org.apache.commons.logging.LogFactory; */ public class SimpleAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler { - private final Log logger = LogFactory.getLog(SimpleAsyncUncaughtExceptionHandler.class); + private static final Log logger = LogFactory.getLog(SimpleAsyncUncaughtExceptionHandler.class); + @Override public void handleUncaughtException(Throwable ex, Method method, Object... params) { if (logger.isErrorEnabled()) { - logger.error(String.format("Unexpected error occurred invoking async " + - "method '%s'.", method), ex); + logger.error("Unexpected error occurred invoking async method: " + method, ex); } } diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/config/AbstractJCacheConfiguration.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/config/AbstractJCacheConfiguration.java index e033b6436f6..fd94f98cd20 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/config/AbstractJCacheConfiguration.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/config/AbstractJCacheConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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,6 +25,7 @@ import org.springframework.cache.jcache.interceptor.JCacheOperationSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Role; +import org.springframework.lang.Nullable; /** * Abstract JSR-107 specific {@code @Configuration} class providing common @@ -37,8 +38,10 @@ import org.springframework.context.annotation.Role; @Configuration public class AbstractJCacheConfiguration extends AbstractCachingConfiguration { + @Nullable protected CacheResolver exceptionCacheResolver; + @Override protected void useCachingConfigurer(CachingConfigurer config) { super.useCachingConfigurer(config); diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/config/JCacheConfigurer.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/config/JCacheConfigurer.java index 784a42ae15d..1c3e333d193 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/config/JCacheConfigurer.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/config/JCacheConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2018 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. @@ -18,6 +18,7 @@ package org.springframework.cache.jcache.config; import org.springframework.cache.annotation.CachingConfigurer; import org.springframework.cache.interceptor.CacheResolver; +import org.springframework.lang.Nullable; /** * Extension of {@link CachingConfigurer} for the JSR-107 implementation. @@ -58,6 +59,7 @@ public interface JCacheConfigurer extends CachingConfigurer { * * See {@link org.springframework.cache.annotation.EnableCaching} for more complete examples. */ + @Nullable CacheResolver exceptionCacheResolver(); } diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/config/JCacheConfigurerSupport.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/config/JCacheConfigurerSupport.java index cd6adc7ef8f..9e55f2596b2 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/config/JCacheConfigurerSupport.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/config/JCacheConfigurerSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2018 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. @@ -18,6 +18,7 @@ package org.springframework.cache.jcache.config; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.interceptor.CacheResolver; +import org.springframework.lang.Nullable; /** * An extension of {@link CachingConfigurerSupport} that also implements @@ -34,6 +35,7 @@ import org.springframework.cache.interceptor.CacheResolver; public class JCacheConfigurerSupport extends CachingConfigurerSupport implements JCacheConfigurer { @Override + @Nullable public CacheResolver exceptionCacheResolver() { return null; } diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/config/package-info.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/config/package-info.java index 280ecee2fbe..9bc89f8e0a2 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/config/package-info.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/config/package-info.java @@ -6,4 +6,9 @@ *

Provide an extension of the {@code CachingConfigurer} that exposes * the exception cache resolver to use, see {@code JCacheConfigurer}. */ +@NonNullApi +@NonNullFields package org.springframework.cache.jcache.config; + +import org.springframework.lang.NonNullApi; +import org.springframework.lang.NonNullFields; diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractCacheInterceptor.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractCacheInterceptor.java index 3fc4e4f56af..04aa8c1bbed 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractCacheInterceptor.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractCacheInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2018 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. @@ -49,6 +49,7 @@ abstract class AbstractCacheInterceptor, A } + @Nullable protected abstract Object invoke(CacheOperationInvocationContext context, CacheOperationInvoker invoker) throws Throwable; diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractFallbackJCacheOperationSource.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractFallbackJCacheOperationSource.java index 3ca53b2aebe..5e31deae5ca 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractFallbackJCacheOperationSource.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractFallbackJCacheOperationSource.java @@ -55,7 +55,7 @@ public abstract class AbstractFallbackJCacheOperationSource implements JCacheOpe @Override - public JCacheOperation getCacheOperation(Method method, Class targetClass) { + public JCacheOperation getCacheOperation(Method method, @Nullable Class targetClass) { MethodClassKey cacheKey = new MethodClassKey(method, targetClass); Object cached = this.cache.get(cacheKey); @@ -78,7 +78,7 @@ public abstract class AbstractFallbackJCacheOperationSource implements JCacheOpe } @Nullable - private JCacheOperation computeCacheOperation(Method method, Class targetClass) { + private JCacheOperation computeCacheOperation(Method method, @Nullable Class targetClass) { // Don't allow no-public methods as required. if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null; @@ -113,7 +113,7 @@ public abstract class AbstractFallbackJCacheOperationSource implements JCacheOpe * (or {@code null} if none) */ @Nullable - protected abstract JCacheOperation findCacheOperation(Method method, Class targetType); + protected abstract JCacheOperation findCacheOperation(Method method, @Nullable Class targetType); /** * Should only public methods be allowed to have caching semantics? diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractJCacheOperation.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractJCacheOperation.java index a9b186a0705..e879259df0d 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractJCacheOperation.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractJCacheOperation.java @@ -50,7 +50,7 @@ abstract class AbstractJCacheOperation implements JCacheOp /** - * Create a new instance. + * Construct a new {@code AbstractJCacheOperation}. * @param methodDetails the {@link CacheMethodDetails} related to the cached method * @param cacheResolver the cache resolver to resolve regular caches */ diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractKeyCacheInterceptor.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractKeyCacheInterceptor.java index b6d1d704505..8ce24119a6a 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractKeyCacheInterceptor.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractKeyCacheInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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,6 +37,7 @@ abstract class AbstractKeyCacheInterceptor createCacheKeyInvocationContext( - CacheOperationInvocationContext context) { + protected CacheKeyInvocationContext createCacheKeyInvocationContext(CacheOperationInvocationContext context) { return new DefaultCacheKeyInvocationContext<>(context.getOperation(), context.getTarget(), context.getArgs()); } diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AnnotationJCacheOperationSource.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AnnotationJCacheOperationSource.java index 0ebf93a71ff..d574881141e 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AnnotationJCacheOperationSource.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AnnotationJCacheOperationSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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. @@ -45,7 +45,7 @@ import org.springframework.util.StringUtils; public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJCacheOperationSource { @Override - protected JCacheOperation findCacheOperation(Method method, Class targetType) { + protected JCacheOperation findCacheOperation(Method method, @Nullable Class targetType) { CacheResult cacheResult = method.getAnnotation(CacheResult.class); CachePut cachePut = method.getAnnotation(CachePut.class); CacheRemove cacheRemove = method.getAnnotation(CacheRemove.class); @@ -74,15 +74,16 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC } } - protected CacheDefaults getCacheDefaults(Method method, Class targetType) { + @Nullable + protected CacheDefaults getCacheDefaults(Method method, @Nullable Class targetType) { CacheDefaults annotation = method.getDeclaringClass().getAnnotation(CacheDefaults.class); if (annotation != null) { return annotation; } - return targetType.getAnnotation(CacheDefaults.class); + return (targetType != null ? targetType.getAnnotation(CacheDefaults.class) : null); } - protected CacheResultOperation createCacheResultOperation(Method method, CacheDefaults defaults, CacheResult ann) { + protected CacheResultOperation createCacheResultOperation(Method method, @Nullable CacheDefaults defaults, CacheResult ann) { String cacheName = determineCacheName(method, defaults, ann.cacheName()); CacheResolverFactory cacheResolverFactory = determineCacheResolverFactory(defaults, ann.cacheResolverFactory()); @@ -100,7 +101,7 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC return new CacheResultOperation(methodDetails, cacheResolver, keyGenerator, exceptionCacheResolver); } - protected CachePutOperation createCachePutOperation(Method method, CacheDefaults defaults, CachePut ann) { + protected CachePutOperation createCachePutOperation(Method method, @Nullable CacheDefaults defaults, CachePut ann) { String cacheName = determineCacheName(method, defaults, ann.cacheName()); CacheResolverFactory cacheResolverFactory = determineCacheResolverFactory(defaults, ann.cacheResolverFactory()); @@ -111,7 +112,7 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC return new CachePutOperation(methodDetails, cacheResolver, keyGenerator); } - protected CacheRemoveOperation createCacheRemoveOperation(Method method, CacheDefaults defaults, CacheRemove ann) { + protected CacheRemoveOperation createCacheRemoveOperation(Method method, @Nullable CacheDefaults defaults, CacheRemove ann) { String cacheName = determineCacheName(method, defaults, ann.cacheName()); CacheResolverFactory cacheResolverFactory = determineCacheResolverFactory(defaults, ann.cacheResolverFactory()); @@ -122,7 +123,7 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC return new CacheRemoveOperation(methodDetails, cacheResolver, keyGenerator); } - protected CacheRemoveAllOperation createCacheRemoveAllOperation(Method method, CacheDefaults defaults, CacheRemoveAll ann) { + protected CacheRemoveAllOperation createCacheRemoveAllOperation(Method method, @Nullable CacheDefaults defaults, CacheRemoveAll ann) { String cacheName = determineCacheName(method, defaults, ann.cacheName()); CacheResolverFactory cacheResolverFactory = determineCacheResolverFactory(defaults, ann.cacheResolverFactory()); @@ -136,7 +137,9 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC return new DefaultCacheMethodDetails<>(method, annotation, cacheName); } - protected CacheResolver getCacheResolver(CacheResolverFactory factory, CacheMethodDetails details) { + protected CacheResolver getCacheResolver( + @Nullable CacheResolverFactory factory, CacheMethodDetails details) { + if (factory != null) { javax.cache.annotation.CacheResolver cacheResolver = factory.getCacheResolver(details); return new CacheResolverAdapter(cacheResolver); @@ -146,8 +149,8 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC } } - protected CacheResolver getExceptionCacheResolver(CacheResolverFactory factory, - CacheMethodDetails details) { + protected CacheResolver getExceptionCacheResolver( + @Nullable CacheResolverFactory factory, CacheMethodDetails details) { if (factory != null) { javax.cache.annotation.CacheResolver cacheResolver = factory.getExceptionCacheResolver(details); @@ -159,13 +162,13 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC } @Nullable - protected CacheResolverFactory determineCacheResolverFactory(CacheDefaults defaults, - Class candidate) { + protected CacheResolverFactory determineCacheResolverFactory( + @Nullable CacheDefaults defaults, Class candidate) { - if (CacheResolverFactory.class != candidate) { + if (candidate != CacheResolverFactory.class) { return getBean(candidate); } - else if (defaults != null && CacheResolverFactory.class != defaults.cacheResolverFactory()) { + else if (defaults != null && defaults.cacheResolverFactory() != CacheResolverFactory.class) { return getBean(defaults.cacheResolverFactory()); } else { @@ -173,8 +176,10 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC } } - protected KeyGenerator determineKeyGenerator(CacheDefaults defaults, Class candidate) { - if (CacheKeyGenerator.class != candidate) { + protected KeyGenerator determineKeyGenerator( + @Nullable CacheDefaults defaults, Class candidate) { + + if (candidate != CacheKeyGenerator.class) { return new KeyGeneratorAdapter(this, getBean(candidate)); } else if (defaults != null && CacheKeyGenerator.class != defaults.cacheKeyGenerator()) { @@ -185,7 +190,7 @@ public abstract class AnnotationJCacheOperationSource extends AbstractFallbackJC } } - protected String determineCacheName(Method method, CacheDefaults defaults, String candidate) { + protected String determineCacheName(Method method, @Nullable CacheDefaults defaults, String candidate) { if (StringUtils.hasText(candidate)) { return candidate; } diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/BeanFactoryJCacheOperationSourceAdvisor.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/BeanFactoryJCacheOperationSourceAdvisor.java index d9d4dde7314..df81c605aa3 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/BeanFactoryJCacheOperationSourceAdvisor.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/BeanFactoryJCacheOperationSourceAdvisor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2018 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,6 +19,7 @@ package org.springframework.cache.jcache.interceptor; import org.springframework.aop.ClassFilter; import org.springframework.aop.Pointcut; import org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor; +import org.springframework.lang.Nullable; /** * Advisor driven by a {@link JCacheOperationSource}, used to include a @@ -30,6 +31,7 @@ import org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor; @SuppressWarnings("serial") public class BeanFactoryJCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor { + @Nullable private JCacheOperationSource cacheOperationSource; private final JCacheOperationSourcePointcut pointcut = new JCacheOperationSourcePointcut() { @@ -39,6 +41,7 @@ public class BeanFactoryJCacheOperationSourceAdvisor extends AbstractBeanFactory } }; + /** * Set the cache operation attribute source which is used to find cache * attributes. This should usually be identical to the source reference @@ -61,4 +64,4 @@ public class BeanFactoryJCacheOperationSourceAdvisor extends AbstractBeanFactory return this.pointcut; } -} \ No newline at end of file +} diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CachePutInterceptor.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CachePutInterceptor.java index ee339ce4621..9df61af08ab 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CachePutInterceptor.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CachePutInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2018 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,16 +37,16 @@ class CachePutInterceptor extends AbstractKeyCacheInterceptor context, - CacheOperationInvoker invoker) { - CacheKeyInvocationContext invocationContext = createCacheKeyInvocationContext(context); + @Override + protected Object invoke( + CacheOperationInvocationContext context, CacheOperationInvoker invoker) { + CachePutOperation operation = context.getOperation(); + CacheKeyInvocationContext invocationContext = createCacheKeyInvocationContext(context); boolean earlyPut = operation.isEarlyPut(); Object value = invocationContext.getValueParameter().getValue(); - if (earlyPut) { cacheValue(context, value); } diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CachePutOperation.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CachePutOperation.java index 0df04db81a7..847a6ce8a7b 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CachePutOperation.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CachePutOperation.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2018 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. @@ -24,6 +24,7 @@ import javax.cache.annotation.CachePut; import org.springframework.cache.interceptor.CacheResolver; import org.springframework.cache.interceptor.KeyGenerator; +import org.springframework.lang.Nullable; import org.springframework.util.ExceptionTypeFilter; /** @@ -44,13 +45,17 @@ class CachePutOperation extends AbstractJCacheKeyOperation { CacheMethodDetails methodDetails, CacheResolver cacheResolver, KeyGenerator keyGenerator) { super(methodDetails, cacheResolver, keyGenerator); + CachePut ann = methodDetails.getCacheAnnotation(); this.exceptionTypeFilter = createExceptionTypeFilter(ann.cacheFor(), ann.noCacheFor()); - this.valueParameterDetail = initializeValueParameterDetail(methodDetails.getMethod(), this.allParameterDetails); - if (this.valueParameterDetail == null) { + + CacheParameterDetail valueParameterDetail = + initializeValueParameterDetail(methodDetails.getMethod(), this.allParameterDetails); + if (valueParameterDetail == null) { throw new IllegalArgumentException("No parameter annotated with @CacheValue was found for " + - "" + methodDetails.getMethod()); + methodDetails.getMethod()); } + this.valueParameterDetail = valueParameterDetail; } @@ -85,6 +90,7 @@ class CachePutOperation extends AbstractJCacheKeyOperation { } + @Nullable private static CacheParameterDetail initializeValueParameterDetail( Method method, List allParameters) { diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CacheRemoveAllInterceptor.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CacheRemoveAllInterceptor.java index 78212f9bd80..c6ad61794d2 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CacheRemoveAllInterceptor.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CacheRemoveAllInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2018 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. @@ -30,21 +30,20 @@ import org.springframework.cache.interceptor.CacheOperationInvoker; * @since 4.1 */ @SuppressWarnings("serial") -class CacheRemoveAllInterceptor - extends AbstractCacheInterceptor { +class CacheRemoveAllInterceptor extends AbstractCacheInterceptor { protected CacheRemoveAllInterceptor(CacheErrorHandler errorHandler) { super(errorHandler); } + @Override - protected Object invoke(CacheOperationInvocationContext context, - CacheOperationInvoker invoker) { + protected Object invoke( + CacheOperationInvocationContext context, CacheOperationInvoker invoker) { CacheRemoveAllOperation operation = context.getOperation(); boolean earlyRemove = operation.isEarlyRemove(); - if (earlyRemove) { removeAll(context); } diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CacheRemoveEntryInterceptor.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CacheRemoveEntryInterceptor.java index 19bbc2c27be..681e6f598f8 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CacheRemoveEntryInterceptor.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CacheRemoveEntryInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2018 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. @@ -36,13 +36,14 @@ class CacheRemoveEntryInterceptor extends AbstractKeyCacheInterceptor context, - CacheOperationInvoker invoker) { + protected Object invoke( + CacheOperationInvocationContext context, CacheOperationInvoker invoker) { + CacheRemoveOperation operation = context.getOperation(); - final boolean earlyRemove = operation.isEarlyRemove(); - + boolean earlyRemove = operation.isEarlyRemove(); if (earlyRemove) { removeValue(context); } @@ -54,12 +55,12 @@ class CacheRemoveEntryInterceptor extends AbstractKeyCacheInterceptor context, - CacheOperationInvoker invoker) { + @Nullable + protected Object invoke( + CacheOperationInvocationContext context, CacheOperationInvoker invoker) { CacheResultOperation operation = context.getOperation(); Object cacheKey = generateKey(context); @@ -74,17 +76,19 @@ class CacheResultInterceptor extends AbstractKeyCacheInterceptor T cloneException(T exception) { try { return (T) SerializationUtils.deserialize(SerializationUtils.serialize(exception)); diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CacheResultOperation.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CacheResultOperation.java index f421dfe850d..16cbe65a7a2 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CacheResultOperation.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CacheResultOperation.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2018 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. @@ -36,15 +36,18 @@ class CacheResultOperation extends AbstractJCacheKeyOperation { private final ExceptionTypeFilter exceptionTypeFilter; + @Nullable private final CacheResolver exceptionCacheResolver; + @Nullable private final String exceptionCacheName; public CacheResultOperation(CacheMethodDetails methodDetails, CacheResolver cacheResolver, - KeyGenerator keyGenerator, CacheResolver exceptionCacheResolver) { + KeyGenerator keyGenerator, @Nullable CacheResolver exceptionCacheResolver) { super(methodDetails, cacheResolver, keyGenerator); + CacheResult ann = methodDetails.getCacheAnnotation(); this.exceptionTypeFilter = createExceptionTypeFilter(ann.cachedExceptions(), ann.nonCachedExceptions()); this.exceptionCacheResolver = exceptionCacheResolver; @@ -70,6 +73,7 @@ class CacheResultOperation extends AbstractJCacheKeyOperation { * Return the {@link CacheResolver} instance to use to resolve the cache to * use for matching exceptions thrown by this operation. */ + @Nullable public CacheResolver getExceptionCacheResolver() { return this.exceptionCacheResolver; } diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/DefaultCacheKeyInvocationContext.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/DefaultCacheKeyInvocationContext.java index 28f8ea507d2..20513504a4a 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/DefaultCacheKeyInvocationContext.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/DefaultCacheKeyInvocationContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2018 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. @@ -20,21 +20,25 @@ import java.lang.annotation.Annotation; import javax.cache.annotation.CacheInvocationParameter; import javax.cache.annotation.CacheKeyInvocationContext; +import org.springframework.lang.Nullable; + /** * The default {@link CacheKeyInvocationContext} implementation. * * @author Stephane Nicoll * @since 4.1 + * @param the annotation type */ -class DefaultCacheKeyInvocationContext - extends DefaultCacheInvocationContext implements CacheKeyInvocationContext { +class DefaultCacheKeyInvocationContext extends DefaultCacheInvocationContext + implements CacheKeyInvocationContext { private final CacheInvocationParameter[] keyParameters; + @Nullable private final CacheInvocationParameter valueParameter; - public DefaultCacheKeyInvocationContext(AbstractJCacheKeyOperation operation, - Object target, Object[] args) { + + public DefaultCacheKeyInvocationContext(AbstractJCacheKeyOperation operation, Object target, Object[] args) { super(operation, target, args); this.keyParameters = operation.getKeyParameters(args); if (operation instanceof CachePutOperation) { @@ -45,14 +49,16 @@ class DefaultCacheKeyInvocationContext } } + @Override public CacheInvocationParameter[] getKeyParameters() { - return keyParameters.clone(); + return this.keyParameters.clone(); } @Override + @Nullable public CacheInvocationParameter getValueParameter() { - return valueParameter; + return this.valueParameter; } } diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/DefaultJCacheOperationSource.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/DefaultJCacheOperationSource.java index aebf919e86b..093f8334423 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/DefaultJCacheOperationSource.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/DefaultJCacheOperationSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2018 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,22 +46,27 @@ import org.springframework.util.Assert; public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSource implements BeanFactoryAware, InitializingBean, SmartInitializingSingleton { + @Nullable private CacheManager cacheManager; + @Nullable private CacheResolver cacheResolver; + @Nullable private CacheResolver exceptionCacheResolver; private KeyGenerator keyGenerator = new SimpleKeyGenerator(); + @Nullable private KeyGenerator adaptedKeyGenerator; + @Nullable private BeanFactory beanFactory; /** - * Set the default {@link CacheManager} to use to lookup cache by name. Only mandatory - * if the {@linkplain CacheResolver cache resolvers} have not been set. + * Set the default {@link CacheManager} to use to lookup cache by name. + * Only mandatory if the {@linkplain CacheResolver cache resolver} has not been set. */ public void setCacheManager(@Nullable CacheManager cacheManager) { this.cacheManager = cacheManager; @@ -112,14 +117,13 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc * honoring the JSR-107 {@link javax.cache.annotation.CacheKey} and * {@link javax.cache.annotation.CacheValue} will be used. */ - public void setKeyGenerator(@Nullable KeyGenerator keyGenerator) { + public void setKeyGenerator(KeyGenerator keyGenerator) { this.keyGenerator = keyGenerator; } /** - * Return the specified key generator to use, if any. + * Return the specified key generator to use. */ - @Nullable public KeyGenerator getKeyGenerator() { return this.keyGenerator; } @@ -138,13 +142,14 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc @Override public void afterSingletonsInstantiated() { // Make sure that the cache resolver is initialized. An exception cache resolver is only - // required if the exceptionCacheName attribute is set on an operation + // required if the exceptionCacheName attribute is set on an operation. Assert.notNull(getDefaultCacheResolver(), "Cache resolver should have been initialized"); } @Override protected T getBean(Class type) { + Assert.state(this.beanFactory != null, "BeanFactory required for resolution of [" + type + "]"); try { return this.beanFactory.getBean(type); } @@ -162,6 +167,7 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc protected CacheManager getDefaultCacheManager() { if (this.cacheManager == null) { + Assert.state(this.beanFactory != null, "BeanFactory required for default CacheManager resolution"); try { this.cacheManager = this.beanFactory.getBean(CacheManager.class); } @@ -195,21 +201,25 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc @Override protected KeyGenerator getDefaultKeyGenerator() { + Assert.state(this.adaptedKeyGenerator != null, "KeyGenerator not initialized"); return this.adaptedKeyGenerator; } /** * Only resolve the default exception cache resolver when an exception needs to be handled. - *

A non-JSR-107 setup requires either a {@link CacheManager} or a {@link CacheResolver}. If only - * the latter is specified, it is not possible to extract a default exception {@code CacheResolver} - * from a custom {@code CacheResolver} implementation so we have to fallback on the {@code CacheManager}. - *

This gives this weird situation of a perfectly valid configuration that breaks all the sudden - * because the JCache support is enabled. To avoid this we resolve the default exception {@code CacheResolver} - * as late as possible to avoid such hard requirement in other cases. + *

A non-JSR-107 setup requires either a {@link CacheManager} or a {@link CacheResolver}. + * If only the latter is specified, it is not possible to extract a default exception + * {@code CacheResolver} from a custom {@code CacheResolver} implementation so we have to + * fall back on the {@code CacheManager}. + *

This gives this weird situation of a perfectly valid configuration that breaks all + * the sudden because the JCache support is enabled. To avoid this we resolve the default + * exception {@code CacheResolver} as late as possible to avoid such hard requirement + * in other cases. */ class LazyCacheResolver implements CacheResolver { + @Nullable private CacheResolver cacheResolver; @Override diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/JCacheAspectSupport.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/JCacheAspectSupport.java index 21464e1265b..121de7492fa 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/JCacheAspectSupport.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/JCacheAspectSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -28,6 +28,7 @@ import org.springframework.cache.interceptor.AbstractCacheInvoker; import org.springframework.cache.interceptor.BasicOperation; import org.springframework.cache.interceptor.CacheOperationInvocationContext; import org.springframework.cache.interceptor.CacheOperationInvoker; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -52,19 +53,27 @@ public class JCacheAspectSupport extends AbstractCacheInvoker implements Initial protected final Log logger = LogFactory.getLog(getClass()); + @Nullable private JCacheOperationSource cacheOperationSource; + @Nullable + private CacheResultInterceptor cacheResultInterceptor; + + @Nullable + private CachePutInterceptor cachePutInterceptor; + + @Nullable + private CacheRemoveEntryInterceptor cacheRemoveEntryInterceptor; + + @Nullable + private CacheRemoveAllInterceptor cacheRemoveAllInterceptor; + private boolean initialized = false; - private CacheResultInterceptor cacheResultInterceptor; - - private CachePutInterceptor cachePutInterceptor; - - private CacheRemoveEntryInterceptor cacheRemoveEntryInterceptor; - - private CacheRemoveAllInterceptor cacheRemoveAllInterceptor; - + /** + * Set the CacheOperationSource for this cache aspect. + */ public void setCacheOperationSource(JCacheOperationSource cacheOperationSource) { Assert.notNull(cacheOperationSource, "JCacheOperationSource must not be null"); this.cacheOperationSource = cacheOperationSource; @@ -74,12 +83,13 @@ public class JCacheAspectSupport extends AbstractCacheInvoker implements Initial * Return the CacheOperationSource for this cache aspect. */ public JCacheOperationSource getCacheOperationSource() { + Assert.state(this.cacheOperationSource != null, "The 'cacheOperationSource' property is required: " + + "If there are no cacheable methods, then don't use a cache aspect."); return this.cacheOperationSource; } public void afterPropertiesSet() { - Assert.state(getCacheOperationSource() != null, "The 'cacheOperationSource' property is required: " + - "If there are no cacheable methods, then don't use a cache aspect."); + getCacheOperationSource(); this.cacheResultInterceptor = new CacheResultInterceptor(getErrorHandler()); this.cachePutInterceptor = new CachePutInterceptor(getErrorHandler()); @@ -90,6 +100,7 @@ public class JCacheAspectSupport extends AbstractCacheInvoker implements Initial } + @Nullable protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) { // Check whether aspect is enabled to cope with cases where the AJ is pulled in automatically if (this.initialized) { @@ -114,23 +125,28 @@ public class JCacheAspectSupport extends AbstractCacheInvoker implements Initial } @SuppressWarnings("unchecked") + @Nullable private Object execute(CacheOperationInvocationContext context, CacheOperationInvoker invoker) { CacheOperationInvoker adapter = new CacheOperationInvokerAdapter(invoker); BasicOperation operation = context.getOperation(); if (operation instanceof CacheResultOperation) { + Assert.state(this.cacheResultInterceptor != null, "No CacheResultInterceptor"); return this.cacheResultInterceptor.invoke( (CacheOperationInvocationContext) context, adapter); } else if (operation instanceof CachePutOperation) { + Assert.state(this.cachePutInterceptor != null, "No CachePutInterceptor"); return this.cachePutInterceptor.invoke( (CacheOperationInvocationContext) context, adapter); } else if (operation instanceof CacheRemoveOperation) { + Assert.state(this.cacheRemoveEntryInterceptor != null, "No CacheRemoveEntryInterceptor"); return this.cacheRemoveEntryInterceptor.invoke( (CacheOperationInvocationContext) context, adapter); } else if (operation instanceof CacheRemoveAllOperation) { + Assert.state(this.cacheRemoveAllInterceptor != null, "No CacheRemoveAllInterceptor"); return this.cacheRemoveAllInterceptor.invoke( (CacheOperationInvocationContext) context, adapter); } diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/JCacheInterceptor.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/JCacheInterceptor.java index f478f10e971..23f4bb567c7 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/JCacheInterceptor.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/JCacheInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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,6 +23,7 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.cache.interceptor.CacheOperationInvoker; +import org.springframework.lang.Nullable; /** * AOP Alliance MethodInterceptor for declarative cache @@ -42,6 +43,7 @@ import org.springframework.cache.interceptor.CacheOperationInvoker; public class JCacheInterceptor extends JCacheAspectSupport implements MethodInterceptor, Serializable { @Override + @Nullable public Object invoke(final MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/JCacheOperationSource.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/JCacheOperationSource.java index 5139282c1d5..43068e7fba7 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/JCacheOperationSource.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/JCacheOperationSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2018 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. @@ -33,7 +33,6 @@ public interface JCacheOperationSource { /** * Return the cache operations for this method, or {@code null} * if the method contains no JSR-107 related metadata. - * * @param method the method to introspect * @param targetClass the target class (may be {@code null}, in which case * the declaring class of the method must be used) diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/JCacheOperationSourcePointcut.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/JCacheOperationSourcePointcut.java index 46fbd7439b4..f638c1f987b 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/JCacheOperationSourcePointcut.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/JCacheOperationSourcePointcut.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2018 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,10 @@ import org.springframework.util.ObjectUtils; * @since 4.1 */ @SuppressWarnings("serial") -public abstract class JCacheOperationSourcePointcut - extends StaticMethodMatcherPointcut implements Serializable { +public abstract class JCacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { @Override - public boolean matches(Method method, Class targetClass) { + public boolean matches(Method method, @Nullable Class targetClass) { JCacheOperationSource cas = getCacheOperationSource(); return (cas != null && cas.getCacheOperation(method, targetClass) != null); } @@ -47,6 +46,7 @@ public abstract class JCacheOperationSourcePointcut @Nullable protected abstract JCacheOperationSource getCacheOperationSource(); + @Override public boolean equals(Object other) { if (this == other) { diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/KeyGeneratorAdapter.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/KeyGeneratorAdapter.java index 679b5bec2c0..fb00ab22a20 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/KeyGeneratorAdapter.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/KeyGeneratorAdapter.java @@ -25,6 +25,7 @@ import javax.cache.annotation.CacheKeyGenerator; import javax.cache.annotation.CacheKeyInvocationContext; import org.springframework.cache.interceptor.KeyGenerator; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -34,14 +35,17 @@ import org.springframework.util.CollectionUtils; * so that only relevant parameters are handled. * * @author Stephane Nicoll + * @author Juergen Hoeller * @since 4.1 */ class KeyGeneratorAdapter implements KeyGenerator { private final JCacheOperationSource cacheOperationSource; + @Nullable private KeyGenerator keyGenerator; + @Nullable private CacheKeyGenerator cacheKeyGenerator; @@ -72,7 +76,11 @@ class KeyGeneratorAdapter implements KeyGenerator { * or a {@link CacheKeyGenerator}. */ public Object getTarget() { - return (this.keyGenerator != null ? this.keyGenerator : this.cacheKeyGenerator); + if (this.cacheKeyGenerator != null) { + return this.cacheKeyGenerator; + } + Assert.state(this.keyGenerator != null, "No key generator"); + return this.keyGenerator; } @Override @@ -87,6 +95,7 @@ class KeyGeneratorAdapter implements KeyGenerator { return this.cacheKeyGenerator.generateCacheKey(invocationContext); } else { + Assert.state(this.keyGenerator != null, "No key generator"); return doGenerate(this.keyGenerator, invocationContext); } } diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/package-info.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/package-info.java index 9240434b373..c752c806b9f 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/package-info.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/package-info.java @@ -7,4 +7,9 @@ *

Builds on the AOP infrastructure in org.springframework.aop.framework. * Any POJO can be cache-advised with Spring. */ +@NonNullApi +@NonNullFields package org.springframework.cache.jcache.interceptor; + +import org.springframework.lang.NonNullApi; +import org.springframework.lang.NonNullFields; diff --git a/spring-context-support/src/test/java/org/springframework/cache/jcache/interceptor/AnnotationCacheOperationSourceTests.java b/spring-context-support/src/test/java/org/springframework/cache/jcache/interceptor/AnnotationCacheOperationSourceTests.java index 67c4d827704..6d62634237f 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/jcache/interceptor/AnnotationCacheOperationSourceTests.java +++ b/spring-context-support/src/test/java/org/springframework/cache/jcache/interceptor/AnnotationCacheOperationSourceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2018 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. @@ -47,11 +47,11 @@ public class AnnotationCacheOperationSourceTests extends AbstractJCacheTests { private final DefaultJCacheOperationSource source = new DefaultJCacheOperationSource(); - private final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + private final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); @Before - public void setUp() { + public void setup() { source.setCacheResolver(defaultCacheResolver); source.setExceptionCacheResolver(defaultExceptionCacheResolver); source.setKeyGenerator(defaultKeyGenerator); diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurerSupport.java b/spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurerSupport.java index 6719efa137a..30a929709e4 100644 --- a/spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurerSupport.java +++ b/spring-context/src/main/java/org/springframework/cache/annotation/CachingConfigurerSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2018 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,13 +40,13 @@ public class CachingConfigurerSupport implements CachingConfigurer { @Override @Nullable - public KeyGenerator keyGenerator() { + public CacheResolver cacheResolver() { return null; } @Override @Nullable - public CacheResolver cacheResolver() { + public KeyGenerator keyGenerator() { return null; } diff --git a/spring-context/src/main/java/org/springframework/cache/config/AnnotationDrivenCacheBeanDefinitionParser.java b/spring-context/src/main/java/org/springframework/cache/config/AnnotationDrivenCacheBeanDefinitionParser.java index a0d3c10200c..09ba1642385 100644 --- a/spring-context/src/main/java/org/springframework/cache/config/AnnotationDrivenCacheBeanDefinitionParser.java +++ b/spring-context/src/main/java/org/springframework/cache/config/AnnotationDrivenCacheBeanDefinitionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -112,21 +112,21 @@ class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser */ private static void parseCacheResolution(Element element, BeanDefinition def, boolean setBoth) { String name = element.getAttribute("cache-resolver"); - if (StringUtils.hasText(name)) { + boolean hasText = StringUtils.hasText(name); + if (hasText) { def.getPropertyValues().add("cacheResolver", new RuntimeBeanReference(name.trim())); } - if (!StringUtils.hasText(name) || setBoth) { + if (!hasText || setBoth) { def.getPropertyValues().add("cacheManager", new RuntimeBeanReference(CacheNamespaceHandler.extractCacheManager(element))); } } - private static BeanDefinition parseErrorHandler(Element element, BeanDefinition def) { + private static void parseErrorHandler(Element element, BeanDefinition def) { String name = element.getAttribute("error-handler"); if (StringUtils.hasText(name)) { def.getPropertyValues().add("errorHandler", new RuntimeBeanReference(name.trim())); } - return def; } @@ -175,12 +175,12 @@ class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser } /** - * Registers a + * Registers a cache aspect. *

-		 * 
-		 *   
-		 *   
-		 * 
+		 * <bean id="cacheAspect" class="org.springframework.cache.aspectj.AnnotationCacheAspect" factory-method="aspectOf">
+		 *   <property name="cacheManager" ref="cacheManager"/>
+		 *   <property name="keyGenerator" ref="keyGenerator"/>
+		 * </bean>
 		 * 
*/ private static void registerCacheAspect(Element element, ParserContext parserContext) { diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java index 19ca45bd337..21fc33db5dc 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java @@ -192,8 +192,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker } catch (NoUniqueBeanDefinitionException ex) { throw new IllegalStateException("No CacheResolver specified, and no unique bean of type " + - "CacheManager found. Mark one as primary (or give it the name 'cacheManager') or " + - "declare a specific CacheManager to use, that serves as the default one."); + "CacheManager found. Mark one as primary or declare a specific CacheManager to use."); } catch (NoSuchBeanDefinitionException ex) { throw new IllegalStateException("No CacheResolver specified, and no bean of type CacheManager found. " + @@ -650,6 +649,9 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker } + /** + * A {@link CacheOperationInvocationContext} context for a {@link CacheOperation}. + */ protected class CacheOperationContext implements CacheOperationInvocationContext { private final CacheOperationMetadata metadata; diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationAdvisor.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationAdvisor.java index f04efd853ea..d282cd4899a 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationAdvisor.java +++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationAdvisor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -100,7 +100,9 @@ public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements B /** * Specify the default task executor to use for asynchronous methods. + * @deprecated as of 5.0.8, in favor of {@link #AsyncAnnotationAdvisor(Executor, AsyncUncaughtExceptionHandler)} */ + @Deprecated public void setTaskExecutor(Executor executor) { this.advice = buildAdvice(executor, this.exceptionHandler); } diff --git a/spring-context/src/main/java/org/springframework/validation/AbstractBindingResult.java b/spring-context/src/main/java/org/springframework/validation/AbstractBindingResult.java index 82a92aba869..3d08c96597b 100644 --- a/spring-context/src/main/java/org/springframework/validation/AbstractBindingResult.java +++ b/spring-context/src/main/java/org/springframework/validation/AbstractBindingResult.java @@ -321,9 +321,8 @@ public abstract class AbstractBindingResult extends AbstractErrors implements Bi @Override public String[] resolveMessageCodes(String errorCode, @Nullable String field) { - Class fieldType = (getTarget() != null ? getFieldType(field) : null); return getMessageCodesResolver().resolveMessageCodes( - errorCode, getObjectName(), fixedField(field), fieldType); + errorCode, getObjectName(), fixedField(field), getFieldType(field)); } @Override @@ -332,7 +331,7 @@ public abstract class AbstractBindingResult extends AbstractErrors implements Bi } @Override - public void recordFieldValue(String field, Class type, Object value) { + public void recordFieldValue(String field, Class type, @Nullable Object value) { this.fieldTypes.put(field, type); this.fieldValues.put(field, value); } diff --git a/spring-context/src/main/java/org/springframework/validation/BindException.java b/spring-context/src/main/java/org/springframework/validation/BindException.java index d31ee8e5524..f9111ecd225 100644 --- a/spring-context/src/main/java/org/springframework/validation/BindException.java +++ b/spring-context/src/main/java/org/springframework/validation/BindException.java @@ -275,7 +275,7 @@ public class BindException extends Exception implements BindingResult { } @Override - public void recordFieldValue(String field, Class type, Object value) { + public void recordFieldValue(String field, Class type, @Nullable Object value) { this.bindingResult.recordFieldValue(field, type, value); } diff --git a/spring-context/src/main/java/org/springframework/validation/BindingResult.java b/spring-context/src/main/java/org/springframework/validation/BindingResult.java index ebe5594eeee..62273969944 100644 --- a/spring-context/src/main/java/org/springframework/validation/BindingResult.java +++ b/spring-context/src/main/java/org/springframework/validation/BindingResult.java @@ -143,7 +143,7 @@ public interface BindingResult extends Errors { * @param value the original value * @since 5.0.4 */ - default void recordFieldValue(String field, Class type, Object value) { + default void recordFieldValue(String field, Class type, @Nullable Object value) { } /** diff --git a/spring-context/src/main/java/org/springframework/validation/DataBinder.java b/spring-context/src/main/java/org/springframework/validation/DataBinder.java index 33a51f24a7b..0562712247b 100644 --- a/spring-context/src/main/java/org/springframework/validation/DataBinder.java +++ b/spring-context/src/main/java/org/springframework/validation/DataBinder.java @@ -853,7 +853,7 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { * @see #getBindingResult() */ public void validate() { - for (Validator validator : this.validators) { + for (Validator validator : getValidators()) { validator.validate(getTarget(), getBindingResult()); } } diff --git a/spring-context/src/test/java/org/springframework/cache/config/EnableCachingTests.java b/spring-context/src/test/java/org/springframework/cache/config/EnableCachingTests.java index 75856f41676..a454d40daff 100644 --- a/spring-context/src/test/java/org/springframework/cache/config/EnableCachingTests.java +++ b/spring-context/src/test/java/org/springframework/cache/config/EnableCachingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -66,23 +66,21 @@ public class EnableCachingTests extends AbstractCacheAnnotationTests { } @Test - public void singleCacheManagerBean() throws Throwable { + public void singleCacheManagerBean() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(SingleCacheManagerConfig.class); ctx.refresh(); } - @Test(expected = IllegalStateException.class) - public void multipleCacheManagerBeans() throws Throwable { + @Test + public void multipleCacheManagerBeans() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(MultiCacheManagerConfig.class); try { ctx.refresh(); } - catch (BeanCreationException ex) { - Throwable root = ex.getRootCause(); - assertTrue(root.getMessage().contains("beans of type CacheManager")); - throw root; + catch (IllegalStateException ex) { + assertTrue(ex.getMessage().contains("no unique bean of type CacheManager")); } } @@ -93,8 +91,8 @@ public class EnableCachingTests extends AbstractCacheAnnotationTests { ctx.refresh(); // does not throw an exception } - @Test(expected = IllegalStateException.class) - public void multipleCachingConfigurers() throws Throwable { + @Test + public void multipleCachingConfigurers() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(MultiCacheManagerConfigurer.class, EnableCachingConfig.class); try { @@ -102,22 +100,20 @@ public class EnableCachingTests extends AbstractCacheAnnotationTests { } catch (BeanCreationException ex) { Throwable root = ex.getRootCause(); + assertTrue(root instanceof IllegalStateException); assertTrue(root.getMessage().contains("implementations of CachingConfigurer")); - throw root; } } - @Test(expected = IllegalStateException.class) - public void noCacheManagerBeans() throws Throwable { + @Test + public void noCacheManagerBeans() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(EmptyConfig.class); try { ctx.refresh(); } - catch (BeanCreationException ex) { - Throwable root = ex.getRootCause(); - assertTrue(root.getMessage().contains("No bean of type CacheManager")); - throw root; + catch (IllegalStateException ex) { + assertTrue(ex.getMessage().contains("no bean of type CacheManager")); } } diff --git a/spring-core/src/main/java/org/springframework/core/convert/support/StringToLocaleConverter.java b/spring-core/src/main/java/org/springframework/core/convert/support/StringToLocaleConverter.java index 7212068a83d..2cdbfffde04 100644 --- a/spring-core/src/main/java/org/springframework/core/convert/support/StringToLocaleConverter.java +++ b/spring-core/src/main/java/org/springframework/core/convert/support/StringToLocaleConverter.java @@ -19,6 +19,7 @@ package org.springframework.core.convert.support; import java.util.Locale; import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; /** @@ -35,6 +36,7 @@ import org.springframework.util.StringUtils; final class StringToLocaleConverter implements Converter { @Override + @Nullable public Locale convert(String source) { return StringUtils.parseLocale(source); } diff --git a/spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java b/spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java index ec5a223d4d3..316023c6c4a 100644 --- a/spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java +++ b/spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java @@ -651,9 +651,9 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen return null; } - @SuppressWarnings("unchecked") + @SuppressWarnings({"rawtypes", "unchecked"}) private Reference[] createReferenceArray(int size) { - return (Reference[]) Array.newInstance(Reference.class, size); + return new Reference[size]; } private int getIndex(int hash, Reference[] references) { diff --git a/spring-web/src/main/java/org/springframework/web/bind/support/WebExchangeBindException.java b/spring-web/src/main/java/org/springframework/web/bind/support/WebExchangeBindException.java index 288d0daf3d6..dd6dcb6e8e4 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/support/WebExchangeBindException.java +++ b/spring-web/src/main/java/org/springframework/web/bind/support/WebExchangeBindException.java @@ -261,7 +261,7 @@ public class WebExchangeBindException extends ServerWebInputException implements } @Override - public void recordFieldValue(String field, Class type, Object value) { + public void recordFieldValue(String field, Class type, @Nullable Object value) { this.bindingResult.recordFieldValue(field, type, value); } diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java b/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java index 67c4d42bdcc..7940d4bb224 100644 --- a/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java +++ b/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java @@ -33,7 +33,6 @@ import org.springframework.core.ParameterNameDiscoverer; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import org.springframework.validation.AbstractBindingResult; import org.springframework.validation.BindException; import org.springframework.validation.BindingResult; import org.springframework.validation.Errors; @@ -289,13 +288,11 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol } if (bindingFailure) { - if (binder.getBindingResult() instanceof AbstractBindingResult) { - AbstractBindingResult result = (AbstractBindingResult) binder.getBindingResult(); - for (int i = 0; i < paramNames.length; i++) { - result.recordFieldValue(paramNames[i], paramTypes[i], args[i]); - } + BindingResult result = binder.getBindingResult(); + for (int i = 0; i < paramNames.length; i++) { + result.recordFieldValue(paramNames[i], paramTypes[i], args[i]); } - throw new BindException(binder.getBindingResult()); + throw new BindException(result); } return BeanUtils.instantiateClass(ctor, args); @@ -319,13 +316,17 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol * @param parameter the method parameter declaration */ protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) { - Annotation[] annotations = parameter.getParameterAnnotations(); - for (Annotation ann : annotations) { + for (Annotation ann : parameter.getParameterAnnotations()) { Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class); if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) { Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann)); - Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints}); - binder.validate(validationHints); + if (hints != null) { + Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints}); + binder.validate(validationHints); + } + else { + binder.validate(); + } break; } } diff --git a/spring-web/src/main/java/org/springframework/web/server/session/InMemoryWebSessionStore.java b/spring-web/src/main/java/org/springframework/web/server/session/InMemoryWebSessionStore.java index b372695aa28..130d140fb16 100644 --- a/spring-web/src/main/java/org/springframework/web/server/session/InMemoryWebSessionStore.java +++ b/spring-web/src/main/java/org/springframework/web/server/session/InMemoryWebSessionStore.java @@ -62,7 +62,7 @@ public class InMemoryWebSessionStore implements WebSessionStore { * {@link IllegalStateException}. *

By default set to 10000. * @param maxSessions the maximum number of sessions - * @since 5.1 + * @since 5.0.8 */ public void setMaxSessions(int maxSessions) { this.maxSessions = maxSessions; @@ -70,7 +70,7 @@ public class InMemoryWebSessionStore implements WebSessionStore { /** * Return the maximum number of sessions that can be stored. - * @since 5.1 + * @since 5.0.8 */ public int getMaxSessions() { return this.maxSessions; @@ -102,9 +102,9 @@ public class InMemoryWebSessionStore implements WebSessionStore { * Return the map of sessions with an {@link Collections#unmodifiableMap * unmodifiable} wrapper. This could be used for management purposes, to * list active sessions, invalidate expired ones, etc. - * @since 5.1 + * @since 5.0.8 */ - public Map getSessions() { + public Map getSessions() { return Collections.unmodifiableMap(this.sessions); } @@ -153,7 +153,7 @@ public class InMemoryWebSessionStore implements WebSessionStore { * kicked off lazily during calls to {@link #createWebSession() create} or * {@link #retrieveSession retrieve}, no less than 60 seconds apart. * This method can be called to force a check at a specific time. - * @since 5.1 + * @since 5.0.8 */ public void removeExpiredSessions() { this.expiredSessionChecker.removeExpiredSessions(this.clock.instant()); diff --git a/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java b/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java index 3dac6113bce..ad5b16ae717 100644 --- a/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java +++ b/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java @@ -255,7 +255,6 @@ final class HierarchicalUriComponents extends UriComponents { // Encoding HierarchicalUriComponents encodeTemplate(Charset charset) { - if (this.encodeState.isEncoded()) { return this; } diff --git a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java index 1c0686e4234..2e3ae703106 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java @@ -325,7 +325,7 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { } - // encode methods + // Encode methods /** * Request to have the URI template pre-encoded at build time, and @@ -361,7 +361,7 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { } - // build methods + // Build methods /** * Build a {@code UriComponents} instance from the various components contained in this builder. @@ -386,8 +386,7 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { HierarchicalUriComponents uriComponents = new HierarchicalUriComponents(this.scheme, this.fragment, this.userInfo, this.host, this.port, this.pathBuilder.build(), this.queryParams, encoded); - - return this.encodeTemplate ? uriComponents.encodeTemplate(this.charset) : uriComponents; + return (this.encodeTemplate ? uriComponents.encodeTemplate(this.charset) : uriComponents); } } @@ -406,7 +405,7 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { * Build a {@code UriComponents} instance and replaces URI template variables * with the values from an array. This is a shortcut method which combines * calls to {@link #build()} and then {@link UriComponents#expand(Object...)}. - * @param uriVariableValues URI variable values + * @param uriVariableValues the URI variable values * @return the URI components with expanded values */ public UriComponents buildAndExpand(Object... uriVariableValues) { diff --git a/spring-web/src/test/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverterTests.java b/spring-web/src/test/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverterTests.java index 7f2c6442ae3..a5f42d4211c 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverterTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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. @@ -62,7 +62,7 @@ public class Jaxb2CollectionHttpMessageConverterTests { @Before - public void setUp() { + public void setup() { converter = new Jaxb2CollectionHttpMessageConverter>(); rootElementListType = new ParameterizedTypeReference>() {}.getType(); rootElementSetType = new ParameterizedTypeReference>() {}.getType(); @@ -72,7 +72,7 @@ public class Jaxb2CollectionHttpMessageConverterTests { @Test - public void canRead() throws Exception { + public void canRead() { assertTrue(converter.canRead(rootElementListType, null, null)); assertTrue(converter.canRead(rootElementSetType, null, null)); assertTrue(converter.canRead(typeSetType, null, null)); @@ -271,4 +271,4 @@ public class Jaxb2CollectionHttpMessageConverterTests { } } -} \ No newline at end of file +} diff --git a/spring-web/src/test/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverterTests.java b/spring-web/src/test/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverterTests.java index 85bc624befc..722d9ff4326 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverterTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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. @@ -16,13 +16,7 @@ package org.springframework.http.converter.xml; -import static org.junit.Assert.*; -import static org.xmlunit.diff.ComparisonType.*; -import static org.xmlunit.diff.DifferenceEvaluators.*; -import static org.xmlunit.matchers.CompareMatcher.*; - import java.nio.charset.StandardCharsets; - import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.bind.annotation.XmlAttribute; @@ -48,6 +42,11 @@ import org.springframework.http.MockHttpInputMessage; import org.springframework.http.MockHttpOutputMessage; import org.springframework.http.converter.HttpMessageNotReadableException; +import static org.junit.Assert.*; +import static org.xmlunit.diff.ComparisonType.*; +import static org.xmlunit.diff.DifferenceEvaluators.*; +import static org.xmlunit.matchers.CompareMatcher.*; + /** * Tests for {@link Jaxb2RootElementHttpMessageConverter}. * @@ -68,7 +67,7 @@ public class Jaxb2RootElementHttpMessageConverterTests { @Before - public void setUp() { + public void setup() { converter = new Jaxb2RootElementHttpMessageConverter(); rootElement = new RootElement(); DefaultAopProxyFactory proxyFactory = new DefaultAopProxyFactory(); @@ -81,7 +80,7 @@ public class Jaxb2RootElementHttpMessageConverterTests { @Test - public void canRead() throws Exception { + public void canRead() { assertTrue("Converter does not support reading @XmlRootElement", converter.canRead(RootElement.class, null)); assertTrue("Converter does not support reading @XmlType", @@ -89,7 +88,7 @@ public class Jaxb2RootElementHttpMessageConverterTests { } @Test - public void canWrite() throws Exception { + public void canWrite() { assertTrue("Converter does not support writing @XmlRootElement", converter.canWrite(RootElement.class, null)); assertTrue("Converter does not support writing @XmlRootElement subclass", diff --git a/spring-web/src/test/java/org/springframework/http/converter/xml/MarshallingHttpMessageConverterTests.java b/spring-web/src/test/java/org/springframework/http/converter/xml/MarshallingHttpMessageConverterTests.java index 074f883cb2a..0e9463414a2 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/xml/MarshallingHttpMessageConverterTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/xml/MarshallingHttpMessageConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2018 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. @@ -43,7 +43,7 @@ import static org.mockito.BDDMockito.*; public class MarshallingHttpMessageConverterTests { @Test - public void canRead() throws Exception { + public void canRead() { Unmarshaller unmarshaller = mock(Unmarshaller.class); given(unmarshaller.supports(Integer.class)).willReturn(false); @@ -58,7 +58,7 @@ public class MarshallingHttpMessageConverterTests { } @Test - public void canWrite() throws Exception { + public void canWrite() { Marshaller marshaller = mock(Marshaller.class); given(marshaller.supports(Integer.class)).willReturn(false); @@ -130,8 +130,8 @@ public class MarshallingHttpMessageConverterTests { MarshallingHttpMessageConverter converter = new MarshallingHttpMessageConverter(marshaller); converter.write(body, null, outputMessage); - assertEquals("Invalid content-type", new MediaType("application", "xml"), outputMessage.getHeaders() - .getContentType()); + assertEquals("Invalid content-type", new MediaType("application", "xml"), + outputMessage.getHeaders().getContentType()); } @Test diff --git a/spring-web/src/test/java/org/springframework/http/converter/xml/SourceHttpMessageConverterTests.java b/spring-web/src/test/java/org/springframework/http/converter/xml/SourceHttpMessageConverterTests.java index 51a6f39e926..96b6678c594 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/xml/SourceHttpMessageConverterTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/xml/SourceHttpMessageConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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. @@ -48,13 +48,8 @@ import org.springframework.http.MockHttpOutputMessage; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.util.FileCopyUtils; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.xmlunit.matchers.CompareMatcher.isSimilarTo; - -// Do NOT statically import org.junit.Assert.*, since XMLAssert extends junit.framework.Assert +import static org.junit.Assert.*; +import static org.xmlunit.matchers.CompareMatcher.*; /** * @author Arjen Poutsma @@ -73,7 +68,7 @@ public class SourceHttpMessageConverterTests { @Before - public void setUp() throws IOException { + public void setup() throws IOException { converter = new SourceHttpMessageConverter<>(); Resource external = new ClassPathResource("external.txt", getClass()); @@ -163,7 +158,7 @@ public class SourceHttpMessageConverterTests { XMLReader reader = result.getXMLReader(); reader.setContentHandler(new DefaultHandler() { @Override - public void characters(char[] ch, int start, int length) throws SAXException { + public void characters(char[] ch, int start, int length) { String s = new String(ch, start, length); assertNotEquals("Invalid result", "Foo Bar", s); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodProcessor.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodProcessor.java index a2b43202915..5959aaa3b54 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodProcessor.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodProcessor.java @@ -191,7 +191,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe valueType = getReturnValueType(outputValue, returnType); declaredType = getGenericType(returnType); } - + if (isResourceType(value, returnType)) { outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes"); if (value != null && inputMessage.getHeaders().getFirst(HttpHeaders.RANGE) != null) { @@ -258,12 +258,12 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe if (selectedMediaType != null) { selectedMediaType = selectedMediaType.removeQualityValue(); for (HttpMessageConverter converter : this.messageConverters) { - GenericHttpMessageConverter genericConverter = - (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter) converter : null); + GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ? + (GenericHttpMessageConverter) converter : null); if (genericConverter != null ? ((GenericHttpMessageConverter) converter).canWrite(declaredType, valueType, selectedMediaType) : converter.canWrite(valueType, selectedMediaType)) { - outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType, + outputValue = getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType, (Class>) converter.getClass(), inputMessage, outputMessage); if (outputValue != null) { @@ -300,7 +300,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe } /** - * Return whether the returned value or the declared return type extend {@link Resource} + * Return whether the returned value or the declared return type extends {@link Resource}. */ protected boolean isResourceType(@Nullable Object value, MethodParameter returnType) { Class clazz = getReturnValueType(value, returnType); @@ -321,15 +321,16 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe } /** + * Returns the media types that can be produced. * @see #getProducibleMediaTypes(HttpServletRequest, Class, Type) */ - @SuppressWarnings({"unchecked", "unused"}) + @SuppressWarnings("unused") protected List getProducibleMediaTypes(HttpServletRequest request, Class valueClass) { return getProducibleMediaTypes(request, valueClass, null); } /** - * Returns the media types that can be produced: + * Returns the media types that can be produced. The resulting media types are: *

    *
  • The producible media types specified in the request mappings, or *
  • Media types of configured converters that can write the specific return value, or @@ -338,10 +339,11 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe * @since 4.2 */ @SuppressWarnings("unchecked") - protected List getProducibleMediaTypes(HttpServletRequest request, Class valueClass, - @Nullable Type declaredType) { + protected List getProducibleMediaTypes( + HttpServletRequest request, Class valueClass, @Nullable Type declaredType) { - Set mediaTypes = (Set) request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE); + Set mediaTypes = + (Set) request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE); if (!CollectionUtils.isEmpty(mediaTypes)) { return new ArrayList<>(mediaTypes); } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterIntegrationTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterIntegrationTests.java index adec9a29fb9..05503093d9a 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterIntegrationTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterIntegrationTests.java @@ -29,7 +29,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; - import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -86,13 +85,7 @@ import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.util.UriComponentsBuilder; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; /** * A test fixture with a controller with all supported method signature styles @@ -378,7 +371,7 @@ public class RequestMappingHandlerAdapterIntegrationTests { User user, @ModelAttribute OtherUser otherUser, Model model, - UriComponentsBuilder builder) throws Exception { + UriComponentsBuilder builder) { model.addAttribute("cookie", cookie).addAttribute("pathvar", pathvar).addAttribute("header", header) .addAttribute("systemHeader", systemHeader).addAttribute("headerMap", headerMap) @@ -404,7 +397,7 @@ public class RequestMappingHandlerAdapterIntegrationTests { @ResponseStatus(code = HttpStatus.ACCEPTED) @ResponseBody - public String handleAndValidateRequestBody(@Valid TestBean modelAttr, Errors errors) throws Exception { + public String handleAndValidateRequestBody(@Valid TestBean modelAttr, Errors errors) { return "Error count [" + errors.getErrorCount() + "]"; } @@ -453,7 +446,7 @@ public class RequestMappingHandlerAdapterIntegrationTests { private static class ColorArgumentResolver implements WebArgumentResolver { @Override - public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) throws Exception { + public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) { return new Color(0); } } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterTests.java index 33c5570c37d..f6f8e74dd26 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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. @@ -54,8 +54,7 @@ import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.FlashMap; import org.springframework.web.servlet.ModelAndView; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; /** * Unit tests for {@link RequestMappingHandlerAdapter}. @@ -257,7 +256,6 @@ public class RequestMappingHandlerAdapterTests { @Test public void jsonpResponseBodyAdvice() throws Exception { - List> converters = new ArrayList<>(); converters.add(new MappingJackson2HttpMessageConverter()); this.handlerAdapter.setMessageConverters(converters);