From 18bfa6b0035b23f20e2eda02ee16e8fc14166165 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 17 Jul 2019 23:24:52 +0200 Subject: [PATCH 1/4] Consider Hibernate Query.list() as query-terminating method Closes gh-23248 --- .../springframework/orm/jpa/SharedEntityManagerCreator.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java b/spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java index fea6b37993..70b6b06da9 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -84,8 +84,9 @@ public abstract class SharedEntityManagerCreator { queryTerminatingMethods.add("execute"); // JPA 2.1 StoredProcedureQuery queryTerminatingMethods.add("executeUpdate"); queryTerminatingMethods.add("getSingleResult"); - queryTerminatingMethods.add("getResultList"); queryTerminatingMethods.add("getResultStream"); + queryTerminatingMethods.add("getResultList"); + queryTerminatingMethods.add("list"); // Hibernate Query.list() method } From 9ffdf05d77d37e0ef3ba3fefd80b36b516d42d75 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 17 Jul 2019 23:25:21 +0200 Subject: [PATCH 2/4] Explicit javadoc note on publishEvent hand-off semantics See gh-21025 --- .../context/ApplicationEventPublisher.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/context/ApplicationEventPublisher.java b/spring-context/src/main/java/org/springframework/context/ApplicationEventPublisher.java index 2bafa5dc4e..779b73c1c4 100644 --- a/spring-context/src/main/java/org/springframework/context/ApplicationEventPublisher.java +++ b/spring-context/src/main/java/org/springframework/context/ApplicationEventPublisher.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2019 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,7 +18,8 @@ package org.springframework.context; /** * Interface that encapsulates event publication functionality. - * Serves as super-interface for {@link ApplicationContext}. + * + *

Serves as a super-interface for {@link ApplicationContext}. * * @author Juergen Hoeller * @author Stephane Nicoll @@ -26,6 +27,7 @@ package org.springframework.context; * @see ApplicationContext * @see ApplicationEventPublisherAware * @see org.springframework.context.ApplicationEvent + * @see org.springframework.context.event.ApplicationEventMulticaster * @see org.springframework.context.event.EventPublicationInterceptor */ @FunctionalInterface @@ -34,9 +36,16 @@ public interface ApplicationEventPublisher { /** * Notify all matching listeners registered with this * application of an application event. Events may be framework events - * (such as RequestHandledEvent) or application-specific events. + * (such as ContextRefreshedEvent) or application-specific events. + *

Such an event publication step is effectively a hand-off to the + * multicaster and does not imply synchronous/asynchronous execution + * or even immediate execution at all. Event listeners are encouraged + * to be as efficient as possible, individually using asynchronous + * execution for longer-running and potentially blocking operations. * @param event the event to publish - * @see org.springframework.web.context.support.RequestHandledEvent + * @see #publishEvent(Object) + * @see org.springframework.context.event.ContextRefreshedEvent + * @see org.springframework.context.event.ContextClosedEvent */ default void publishEvent(ApplicationEvent event) { publishEvent((Object) event); @@ -47,8 +56,14 @@ public interface ApplicationEventPublisher { * application of an event. *

If the specified {@code event} is not an {@link ApplicationEvent}, * it is wrapped in a {@link PayloadApplicationEvent}. + *

Such an event publication step is effectively a hand-off to the + * multicaster and does not imply synchronous/asynchronous execution + * or even immediate execution at all. Event listeners are encouraged + * to be as efficient as possible, individually using asynchronous + * execution for longer-running and potentially blocking operations. * @param event the event to publish * @since 4.2 + * @see #publishEvent(ApplicationEvent) * @see PayloadApplicationEvent */ void publishEvent(Object event); From f5daa657f41192e7b81b5205ac4fd246dee6d8b3 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 17 Jul 2019 23:25:50 +0200 Subject: [PATCH 3/4] Polishing --- .../interceptor/AbstractCacheInterceptor.java | 6 +++--- .../interceptor/CacheRemoveAllInterceptor.java | 7 +++---- .../CacheRemoveEntryInterceptor.java | 7 +++---- .../interceptor/CacheRemoveOperation.java | 6 +++--- .../TransactionAwareCacheDecorator.java | 17 ++++++++++------- .../java/org/springframework/cache/Cache.java | 13 +++++++------ .../cache/annotation/CacheEvict.java | 2 +- .../cache/concurrent/ConcurrentMapCache.java | 4 ++-- 8 files changed, 32 insertions(+), 30 deletions(-) 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 8f0d4d56e6..06025fc26a 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-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -59,7 +59,7 @@ abstract class AbstractCacheInterceptor, A /** * Resolve the cache to use. * @param context the invocation context - * @return the cache to use (never null) + * @return the cache to use (never {@code null}) */ protected Cache resolveCache(CacheOperationInvocationContext context) { Collection caches = context.getOperation().getCacheResolver().resolveCaches(context); @@ -73,7 +73,7 @@ abstract class AbstractCacheInterceptor, A /** * Convert the collection of caches in a single expected element. *

Throw an {@link IllegalStateException} if the collection holds more than one element - * @return the single element or {@code null} if the collection is empty + * @return the single element, or {@code null} if the collection is empty */ @Nullable static Cache extractFrom(Collection caches) { 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 34446bf4ba..6205dda3a7 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-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -42,7 +42,6 @@ class CacheRemoveAllInterceptor extends AbstractCacheInterceptor context, CacheOperationInvoker invoker) { CacheRemoveAllOperation operation = context.getOperation(); - boolean earlyRemove = operation.isEarlyRemove(); if (earlyRemove) { removeAll(context); @@ -67,8 +66,8 @@ class CacheRemoveAllInterceptor extends AbstractCacheInterceptor context) { Cache cache = resolveCache(context); if (logger.isTraceEnabled()) { - logger.trace("Invalidating entire cache '" + cache.getName() + "' for operation " - + context.getOperation()); + logger.trace("Invalidating entire cache '" + cache.getName() + "' for operation " + + context.getOperation()); } doClear(cache); } 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 2283657807..41c3331d50 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-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -42,7 +42,6 @@ class CacheRemoveEntryInterceptor extends AbstractKeyCacheInterceptor context, CacheOperationInvoker invoker) { CacheRemoveOperation operation = context.getOperation(); - boolean earlyRemove = operation.isEarlyRemove(); if (earlyRemove) { removeValue(context); @@ -68,8 +67,8 @@ class CacheRemoveEntryInterceptor extends AbstractKeyCacheInterceptor { } /** - * Specify if the cache entry should be remove before invoking the method. By default, the - * cache entry is removed after the method invocation. + * Specify if the cache entry should be removed before invoking the method. + *

By default, the cache entry is removed after the method invocation. * @see javax.cache.annotation.CacheRemove#afterInvocation() */ public boolean isEarlyRemove() { diff --git a/spring-context-support/src/main/java/org/springframework/cache/transaction/TransactionAwareCacheDecorator.java b/spring-context-support/src/main/java/org/springframework/cache/transaction/TransactionAwareCacheDecorator.java index 9038156aac..223812c8dc 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/transaction/TransactionAwareCacheDecorator.java +++ b/spring-context-support/src/main/java/org/springframework/cache/transaction/TransactionAwareCacheDecorator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2019 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,14 +25,16 @@ import org.springframework.transaction.support.TransactionSynchronizationManager import org.springframework.util.Assert; /** - * Cache decorator which synchronizes its {@link #put}, {@link #evict} and {@link #clear} - * operations with Spring-managed transactions (through Spring's {@link TransactionSynchronizationManager}, - * performing the actual cache put/evict/clear operation only in the after-commit phase of a - * successful transaction. If no transaction is active, {@link #put}, {@link #evict} and + * Cache decorator which synchronizes its {@link #put}, {@link #evict} and + * {@link #clear} operations with Spring-managed transactions (through Spring's + * {@link TransactionSynchronizationManager}, performing the actual cache + * put/evict/clear operation only in the after-commit phase of a successful + * transaction. If no transaction is active, {@link #put}, {@link #evict} and * {@link #clear} operations will be performed immediately, as usual. * - *

Use of more aggressive operations such as {@link #putIfAbsent} cannot be deferred - * to the after-commit phase of a running transaction. Use these with care. + *

Note: Use of immediate operations such as {@link #putIfAbsent} + * cannot be deferred to the after-commit phase of a running transaction. + * Use these with care in a transactional environment. * * @author Juergen Hoeller * @author Stephane Nicoll @@ -54,6 +56,7 @@ public class TransactionAwareCacheDecorator implements Cache { this.targetCache = targetCache; } + /** * Return the target Cache that this Cache should delegate to. */ diff --git a/spring-context/src/main/java/org/springframework/cache/Cache.java b/spring-context/src/main/java/org/springframework/cache/Cache.java index 988eed9806..e46b4cac94 100644 --- a/spring-context/src/main/java/org/springframework/cache/Cache.java +++ b/spring-context/src/main/java/org/springframework/cache/Cache.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2019 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. @@ -55,6 +55,7 @@ public interface Cache { * a cached {@code null} value. A straight {@code null} being * returned means that the cache contains no mapping for this key. * @see #get(Object, Class) + * @see #get(Object, Callable) */ @Nullable ValueWrapper get(Object key); @@ -94,6 +95,7 @@ public interface Cache { * @return the value to which this cache maps the specified key * @throws ValueRetrievalException if the {@code valueLoader} throws an exception * @since 4.3 + * @see #get(Object) */ @Nullable T get(Object key, Callable valueLoader); @@ -112,13 +114,11 @@ public interface Cache { * if it is not set already. *

This is equivalent to: *


-	 * Object existingValue = cache.get(key);
+	 * ValueWrapper existingValue = cache.get(key);
 	 * if (existingValue == null) {
 	 *     cache.put(key, value);
-	 *     return null;
-	 * } else {
-	 *     return existingValue;
 	 * }
+	 * return existingValue;
 	 * 
* except that the action is performed atomically. While all out-of-the-box * {@link CacheManager} implementations are able to perform the put atomically, @@ -132,6 +132,7 @@ public interface Cache { * mapping for that key prior to this call. Returning {@code null} is therefore * an indicator that the given {@code value} has been associated with the key. * @since 4.1 + * @see #put(Object, Object) */ @Nullable ValueWrapper putIfAbsent(Object key, @Nullable Object value); @@ -143,7 +144,7 @@ public interface Cache { void evict(Object key); /** - * Remove all mappings from the cache. + * Clear the cache through removing all mappings. */ void clear(); diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/CacheEvict.java b/spring-context/src/main/java/org/springframework/cache/annotation/CacheEvict.java index bbfc6526d5..5aa3978852 100644 --- a/spring-context/src/main/java/org/springframework/cache/annotation/CacheEvict.java +++ b/spring-context/src/main/java/org/springframework/cache/annotation/CacheEvict.java @@ -142,7 +142,7 @@ public @interface CacheEvict { * occur irrespective of the method outcome (i.e., whether it threw an * exception or not). *

Defaults to {@code false}, meaning that the cache eviction operation - * will occur after the advised method is invoked successfully (i.e., + * will occur after the advised method is invoked successfully (i.e. * only if the invocation did not throw an exception). */ boolean beforeInvocation() default false; diff --git a/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java b/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java index b92d6e7eef..9b9c076a79 100644 --- a/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java +++ b/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -141,7 +141,7 @@ public class ConcurrentMapCache extends AbstractValueAdaptingCache { @Override @Nullable public T get(Object key, Callable valueLoader) { - return (T) fromStoreValue(this.store.computeIfAbsent(key, r -> { + return (T) fromStoreValue(this.store.computeIfAbsent(key, k -> { try { return toStoreValue(valueLoader.call()); } From 46e5b6f7af6982e5969b2e5a308ea4fc66a14609 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 17 Jul 2019 23:26:07 +0200 Subject: [PATCH 4/4] Upgrade to Tomcat 9.0.22, Checkstyle 8.22, Mockito 2.28.2 --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index acbe4cf3c4..0da6cfdc14 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ ext { rxjava2Version = "2.2.10" slf4jVersion = "1.7.26" // spring-jcl + consistent 3rd party deps tiles3Version = "3.0.8" - tomcatVersion = "9.0.21" + tomcatVersion = "9.0.22" undertowVersion = "2.0.22.Final" gradleScriptDir = "${rootProject.projectDir}/gradle" @@ -143,7 +143,7 @@ configure(allprojects) { project -> } checkstyle { - toolVersion = "8.21" + toolVersion = "8.22" configDir = rootProject.file("src/checkstyle") } @@ -156,7 +156,7 @@ configure(allprojects) { project -> testCompile("junit:junit:4.12") { exclude group: "org.hamcrest", module: "hamcrest-core" } - testCompile("org.mockito:mockito-core:2.27.0") { + testCompile("org.mockito:mockito-core:2.28.2") { exclude group: "org.hamcrest", module: "hamcrest-core" } testCompile("com.nhaarman:mockito-kotlin:1.6.0") {