From e210f08dced17f01bf3308f399c8e089b8f8319a Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 8 Jun 2023 17:25:46 +0200 Subject: [PATCH 1/4] Declare Advisor#isPerInstance() as default method Includes INSTANCE constants on default factory classes. Closes gh-30614 --- .../java/org/springframework/aop/Advisor.java | 7 +++++-- .../aop/aspectj/AspectJPointcutAdvisor.java | 7 +------ .../aop/aspectj/DeclareParentsAdvisor.java | 7 +------ .../framework/DefaultAdvisorChainFactory.java | 7 +++++++ .../aop/framework/DefaultAopProxyFactory.java | 8 +++++++- .../aop/framework/ProxyCreatorSupport.java | 4 ++-- .../aop/framework/ProxyFactoryBean.java | 7 +------ .../aop/support/AbstractPointcutAdvisor.java | 18 ++++-------------- .../support/DefaultIntroductionAdvisor.java | 17 ++++------------- .../StaticMethodMatcherPointcutAdvisor.java | 7 +------ 10 files changed, 33 insertions(+), 56 deletions(-) diff --git a/spring-aop/src/main/java/org/springframework/aop/Advisor.java b/spring-aop/src/main/java/org/springframework/aop/Advisor.java index b10911aebf..100fbd0779 100644 --- a/spring-aop/src/main/java/org/springframework/aop/Advisor.java +++ b/spring-aop/src/main/java/org/springframework/aop/Advisor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2023 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,8 +62,11 @@ public interface Advisor { * Typical Advisor implementations always return {@code true}. * Use singleton/prototype bean definitions or appropriate programmatic * proxy creation to ensure that Advisors have the correct lifecycle model. + *

As of 6.0.10, the default implementation returns {@code true}. * @return whether this advice is associated with a particular target instance */ - boolean isPerInstance(); + default boolean isPerInstance() { + return true; + } } diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJPointcutAdvisor.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJPointcutAdvisor.java index 442df0808f..fb1974faee 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJPointcutAdvisor.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJPointcutAdvisor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -67,11 +67,6 @@ public class AspectJPointcutAdvisor implements PointcutAdvisor, Ordered { } } - @Override - public boolean isPerInstance() { - return true; - } - @Override public Advice getAdvice() { return this.advice; diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/DeclareParentsAdvisor.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/DeclareParentsAdvisor.java index 3a4f8992cb..43233666ad 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/DeclareParentsAdvisor.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/DeclareParentsAdvisor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2023 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. @@ -91,11 +91,6 @@ public class DeclareParentsAdvisor implements IntroductionAdvisor { // Do nothing } - @Override - public boolean isPerInstance() { - return true; - } - @Override public Advice getAdvice() { return this.advice; 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 5bef4c501c..73c2fb4308 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 @@ -47,6 +47,13 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable { + /** + * Singleton instance of this class. + * @since 6.0.10 + */ + public static final DefaultAdvisorChainFactory INSTANCE = new DefaultAdvisorChainFactory(); + + @Override public List getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, @Nullable Class targetClass) { diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java b/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java index 5710f8e03b..f97455dfc4 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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,6 +48,12 @@ import org.springframework.util.ClassUtils; */ public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { + /** + * Singleton instance of this class. + * @since 6.0.10 + */ + public static final DefaultAopProxyFactory INSTANCE = new DefaultAopProxyFactory(); + private static final long serialVersionUID = 7930414337282325166L; diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/ProxyCreatorSupport.java b/spring-aop/src/main/java/org/springframework/aop/framework/ProxyCreatorSupport.java index 096294321f..a9b43befbc 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/ProxyCreatorSupport.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/ProxyCreatorSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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. @@ -44,7 +44,7 @@ public class ProxyCreatorSupport extends AdvisedSupport { * Create a new ProxyCreatorSupport instance. */ public ProxyCreatorSupport() { - this.aopProxyFactory = new DefaultAopProxyFactory(); + this.aopProxyFactory = DefaultAopProxyFactory.INSTANCE; } /** diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/ProxyFactoryBean.java b/spring-aop/src/main/java/org/springframework/aop/framework/ProxyFactoryBean.java index 77b8858171..f963721c58 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/ProxyFactoryBean.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/ProxyFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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. @@ -606,11 +606,6 @@ public class ProxyFactoryBean extends ProxyCreatorSupport throw new UnsupportedOperationException("Cannot invoke methods: " + this.message); } - @Override - public boolean isPerInstance() { - throw new UnsupportedOperationException("Cannot invoke methods: " + this.message); - } - @Override public String toString() { return this.message; diff --git a/spring-aop/src/main/java/org/springframework/aop/support/AbstractPointcutAdvisor.java b/spring-aop/src/main/java/org/springframework/aop/support/AbstractPointcutAdvisor.java index 6937e31ce2..fc5527270e 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/AbstractPointcutAdvisor.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/AbstractPointcutAdvisor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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. @@ -58,22 +58,12 @@ public abstract class AbstractPointcutAdvisor implements PointcutAdvisor, Ordere return Ordered.LOWEST_PRECEDENCE; } - @Override - public boolean isPerInstance() { - return true; - } - @Override public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof PointcutAdvisor otherAdvisor)) { - return false; - } - return (ObjectUtils.nullSafeEquals(getAdvice(), otherAdvisor.getAdvice()) && - ObjectUtils.nullSafeEquals(getPointcut(), otherAdvisor.getPointcut())); + return (this == other || (other instanceof PointcutAdvisor otherAdvisor && + ObjectUtils.nullSafeEquals(getAdvice(), otherAdvisor.getAdvice()) && + ObjectUtils.nullSafeEquals(getPointcut(), otherAdvisor.getPointcut()))); } @Override diff --git a/spring-aop/src/main/java/org/springframework/aop/support/DefaultIntroductionAdvisor.java b/spring-aop/src/main/java/org/springframework/aop/support/DefaultIntroductionAdvisor.java index 8b70d019fe..930255c62c 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/DefaultIntroductionAdvisor.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/DefaultIntroductionAdvisor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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. @@ -134,11 +134,6 @@ public class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFil return this.advice; } - @Override - public boolean isPerInstance() { - return true; - } - @Override public ClassFilter getClassFilter() { return this; @@ -152,13 +147,9 @@ public class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFil @Override public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof DefaultIntroductionAdvisor otherAdvisor)) { - return false; - } - return (this.advice.equals(otherAdvisor.advice) && this.interfaces.equals(otherAdvisor.interfaces)); + return (this == other || (other instanceof DefaultIntroductionAdvisor otherAdvisor && + this.advice.equals(otherAdvisor.advice) && + this.interfaces.equals(otherAdvisor.interfaces))); } @Override diff --git a/spring-aop/src/main/java/org/springframework/aop/support/StaticMethodMatcherPointcutAdvisor.java b/spring-aop/src/main/java/org/springframework/aop/support/StaticMethodMatcherPointcutAdvisor.java index 38dceb3008..f5b3ccdeaa 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/StaticMethodMatcherPointcutAdvisor.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/StaticMethodMatcherPointcutAdvisor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -77,11 +77,6 @@ public abstract class StaticMethodMatcherPointcutAdvisor extends StaticMethodMat return this.advice; } - @Override - public boolean isPerInstance() { - return true; - } - @Override public Pointcut getPointcut() { return this; From 045df81f14685969f6d9994594092f2aae698456 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 8 Jun 2023 17:27:09 +0200 Subject: [PATCH 2/4] Reduce ProxyCallbackFilter to key-only role after class generation Avoids memory leaks from ProxyCallbackFilter-contained Advisors. Includes consistent ProxyCallbackFilter#equals/hashCode methods. Closes gh-26266 Closes gh-30615 --- .../aop/framework/AdvisedSupport.java | 87 +++++++++++++++++-- .../aop/framework/CglibAopProxy.java | 87 +++++-------------- .../aop/framework/CglibProxyTests.java | 37 ++++++++ 3 files changed, 140 insertions(+), 71 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 90d5afef82..d88c58aa3b 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -32,6 +33,8 @@ import org.springframework.aop.Advisor; import org.springframework.aop.DynamicIntroductionAdvice; import org.springframework.aop.IntroductionAdvisor; import org.springframework.aop.IntroductionInfo; +import org.springframework.aop.Pointcut; +import org.springframework.aop.PointcutAdvisor; import org.springframework.aop.TargetSource; import org.springframework.aop.support.DefaultIntroductionAdvisor; import org.springframework.aop.support.DefaultPointcutAdvisor; @@ -41,6 +44,7 @@ import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; /** * Base class for AOP proxy configuration managers. @@ -72,15 +76,13 @@ public class AdvisedSupport extends ProxyConfig implements Advised { /** Package-protected to allow direct access for efficiency. */ - @SuppressWarnings("serial") TargetSource targetSource = EMPTY_TARGET_SOURCE; /** Whether the Advisors are already filtered for the specific target class. */ private boolean preFiltered = false; /** The AdvisorChainFactory to use. */ - @SuppressWarnings("serial") - AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory(); + private AdvisorChainFactory advisorChainFactory; /** Cache with Method as key and advisor chain List as value. */ private transient Map> methodCache; @@ -89,21 +91,22 @@ public class AdvisedSupport extends ProxyConfig implements Advised { * Interfaces to be implemented by the proxy. Held in List to keep the order * of registration, to create JDK proxy with specified order of interfaces. */ - @SuppressWarnings("serial") private List> interfaces = new ArrayList<>(); /** * List of Advisors. If an Advice is added, it will be wrapped * in an Advisor before being added to this List. */ - @SuppressWarnings("serial") private List advisors = new ArrayList<>(); + private List advisorKey = this.advisors; + /** * No-arg constructor for use as a JavaBean. */ public AdvisedSupport() { + this.advisorChainFactory = DefaultAdvisorChainFactory.INSTANCE; this.methodCache = new ConcurrentHashMap<>(32); } @@ -116,6 +119,15 @@ public class AdvisedSupport extends ProxyConfig implements Advised { setInterfaces(interfaces); } + /** + * Internal constructor for {@link #getConfigurationOnlyCopy()}. + * @since 6.0.10 + */ + private AdvisedSupport(AdvisorChainFactory advisorChainFactory, Map> methodCache) { + this.advisorChainFactory = advisorChainFactory; + this.methodCache = methodCache; + } + /** * Set the given object as target. @@ -520,15 +532,27 @@ public class AdvisedSupport extends ProxyConfig implements Advised { * replacing the TargetSource. */ AdvisedSupport getConfigurationOnlyCopy() { - AdvisedSupport copy = new AdvisedSupport(); + AdvisedSupport copy = new AdvisedSupport(this.advisorChainFactory, this.methodCache); copy.copyFrom(this); copy.targetSource = EmptyTargetSource.forClass(getTargetClass(), getTargetSource().isStatic()); - copy.advisorChainFactory = this.advisorChainFactory; copy.interfaces = new ArrayList<>(this.interfaces); copy.advisors = new ArrayList<>(this.advisors); + copy.advisorKey = new ArrayList<>(this.advisors.size()); + for (Advisor advisor : this.advisors) { + copy.advisorKey.add(new AdvisorKeyEntry(advisor)); + } return copy; } + void reduceToAdvisorKey() { + this.advisors = this.advisorKey; + this.methodCache = Collections.emptyMap(); + } + + Object getAdvisorKey() { + return this.advisorKey; + } + //--------------------------------------------------------------------- // Serialization support @@ -604,4 +628,51 @@ public class AdvisedSupport extends ProxyConfig implements Advised { } } + + /** + * Stub for an Advisor instance that is just needed for key purposes, + * allowing for efficient equals and hashCode comparisons against the + * advice class and the pointcut. + * @since 6.0.10 + * @see #getConfigurationOnlyCopy() + * @see #getAdvisorKey() + */ + private static class AdvisorKeyEntry implements Advisor { + + private final Class adviceType; + + @Nullable + private String classFilterKey; + + @Nullable + private String methodMatcherKey; + + public AdvisorKeyEntry(Advisor advisor) { + this.adviceType = advisor.getAdvice().getClass(); + if (advisor instanceof PointcutAdvisor pointcutAdvisor) { + Pointcut pointcut = pointcutAdvisor.getPointcut(); + this.classFilterKey = ObjectUtils.identityToString(pointcut.getClassFilter()); + this.methodMatcherKey = ObjectUtils.identityToString(pointcut.getMethodMatcher()); + } + } + + @Override + public Advice getAdvice() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean equals(Object other) { + return (this == other || (other instanceof AdvisorKeyEntry otherEntry && + this.adviceType == otherEntry.adviceType && + ObjectUtils.nullSafeEquals(this.classFilterKey, otherEntry.classFilterKey) && + ObjectUtils.nullSafeEquals(this.methodMatcherKey, otherEntry.methodMatcherKey))); + } + + @Override + public int hashCode() { + return this.adviceType.hashCode(); + } + } + } diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java b/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java index a95c6c7ff2..cb7d8e7a0f 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java @@ -26,14 +26,11 @@ import java.util.Map; import java.util.Set; import java.util.WeakHashMap; -import org.aopalliance.aop.Advice; import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.aop.Advisor; import org.springframework.aop.AopInvocationException; -import org.springframework.aop.PointcutAdvisor; import org.springframework.aop.RawTargetAccess; import org.springframework.aop.TargetSource; import org.springframework.aop.support.AopUtils; @@ -205,12 +202,21 @@ class CglibAopProxy implements AopProxy, Serializable { types[x] = callbacks[x].getClass(); } // fixedInterceptorMap only populated at this point, after getCallbacks call above - enhancer.setCallbackFilter(new ProxyCallbackFilter( - this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); + ProxyCallbackFilter filter = new ProxyCallbackFilter( + this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset); + enhancer.setCallbackFilter(filter); enhancer.setCallbackTypes(types); // Generate the proxy class and create a proxy instance. - return (classOnly ? createProxyClass(enhancer) : createProxyClassAndInstance(enhancer, callbacks)); + // ProxyCallbackFilter has method introspection capability with Advisor access. + try { + return (classOnly ? createProxyClass(enhancer) : createProxyClassAndInstance(enhancer, callbacks)); + } + finally { + // Reduce ProxyCallbackFilter to key-only state for its class cache role + // in the CGLIB$CALLBACK_FILTER field, not leaking any Advisor state... + filter.advised.reduceToAdvisorKey(); + } } catch (CodeGenerationException | IllegalArgumentException ex) { throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() + @@ -294,9 +300,9 @@ class CglibAopProxy implements AopProxy, Serializable { private Callback[] getCallbacks(Class rootClass) throws Exception { // Parameters used for optimization choices... - boolean exposeProxy = this.advised.isExposeProxy(); - boolean isFrozen = this.advised.isFrozen(); boolean isStatic = this.advised.getTargetSource().isStatic(); + boolean isFrozen = this.advised.isFrozen(); + boolean exposeProxy = this.advised.isExposeProxy(); // Choose an "aop" interceptor (used for AOP calls). Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised); @@ -776,7 +782,7 @@ class CglibAopProxy implements AopProxy, Serializable { */ private static class ProxyCallbackFilter implements CallbackFilter { - private final AdvisedSupport advised; + final AdvisedSupport advised; private final Map fixedInterceptorMap; @@ -857,9 +863,9 @@ class CglibAopProxy implements AopProxy, Serializable { // Proxy is not yet available, but that shouldn't matter. List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); boolean haveAdvice = !chain.isEmpty(); - boolean exposeProxy = this.advised.isExposeProxy(); boolean isStatic = this.advised.getTargetSource().isStatic(); boolean isFrozen = this.advised.isFrozen(); + boolean exposeProxy = this.advised.isExposeProxy(); if (haveAdvice || !isFrozen) { // If exposing the proxy, then AOP_PROXY must be used. if (exposeProxy) { @@ -921,63 +927,18 @@ class CglibAopProxy implements AopProxy, Serializable { return false; } AdvisedSupport otherAdvised = otherCallbackFilter.advised; - if (this.advised.isFrozen() != otherAdvised.isFrozen()) { - return false; - } - if (this.advised.isExposeProxy() != otherAdvised.isExposeProxy()) { - return false; - } - if (this.advised.getTargetSource().isStatic() != otherAdvised.getTargetSource().isStatic()) { - return false; - } - if (!AopProxyUtils.equalsProxiedInterfaces(this.advised, otherAdvised)) { - return false; - } - // Advice instance identity is unimportant to the proxy class: - // All that matters is type and ordering. - if (this.advised.getAdvisorCount() != otherAdvised.getAdvisorCount()) { - return false; - } - Advisor[] thisAdvisors = this.advised.getAdvisors(); - Advisor[] thatAdvisors = otherAdvised.getAdvisors(); - for (int i = 0; i < thisAdvisors.length; i++) { - Advisor thisAdvisor = thisAdvisors[i]; - Advisor thatAdvisor = thatAdvisors[i]; - if (!equalsAdviceClasses(thisAdvisor, thatAdvisor)) { - return false; - } - if (!equalsPointcuts(thisAdvisor, thatAdvisor)) { - return false; - } - } - return true; - } - - private static boolean equalsAdviceClasses(Advisor a, Advisor b) { - return (a.getAdvice().getClass() == b.getAdvice().getClass()); - } - - private static boolean equalsPointcuts(Advisor a, Advisor b) { - // If only one of the advisor (but not both) is PointcutAdvisor, then it is a mismatch. - // Takes care of the situations where an IntroductionAdvisor is used (see SPR-3959). - return (!(a instanceof PointcutAdvisor pointcutAdvisor1) || - (b instanceof PointcutAdvisor pointcutAdvisor2 && - ObjectUtils.nullSafeEquals(pointcutAdvisor1.getPointcut(), pointcutAdvisor2.getPointcut()))); + return (this.advised.getAdvisorKey().equals(otherAdvised.getAdvisorKey()) && + AopProxyUtils.equalsProxiedInterfaces(this.advised, otherAdvised) && + ObjectUtils.nullSafeEquals(this.advised.getTargetClass(), otherAdvised.getTargetClass()) && + this.advised.getTargetSource().isStatic() == otherAdvised.getTargetSource().isStatic() && + this.advised.isFrozen() == otherAdvised.isFrozen() && + this.advised.isExposeProxy() == otherAdvised.isExposeProxy() && + this.advised.isOpaque() == otherAdvised.isOpaque()); } @Override public int hashCode() { - int hashCode = 0; - Advisor[] advisors = this.advised.getAdvisors(); - for (Advisor advisor : advisors) { - Advice advice = advisor.getAdvice(); - hashCode = 13 * hashCode + advice.getClass().hashCode(); - } - hashCode = 13 * hashCode + (this.advised.isFrozen() ? 1 : 0); - hashCode = 13 * hashCode + (this.advised.isExposeProxy() ? 1 : 0); - hashCode = 13 * hashCode + (this.advised.isOptimize() ? 1 : 0); - hashCode = 13 * hashCode + (this.advised.isOpaque() ? 1 : 0); - return hashCode; + return this.advised.getAdvisorKey().hashCode(); } } diff --git a/spring-context/src/test/java/org/springframework/aop/framework/CglibProxyTests.java b/spring-context/src/test/java/org/springframework/aop/framework/CglibProxyTests.java index 047974b454..3fddbf2af9 100644 --- a/spring-context/src/test/java/org/springframework/aop/framework/CglibProxyTests.java +++ b/spring-context/src/test/java/org/springframework/aop/framework/CglibProxyTests.java @@ -28,6 +28,7 @@ import org.springframework.aop.MethodMatcher; import org.springframework.aop.Pointcut; import org.springframework.aop.support.AopUtils; import org.springframework.aop.support.DefaultPointcutAdvisor; +import org.springframework.aop.support.annotation.AnnotationMatchingPointcut; import org.springframework.aop.testfixture.advice.CountingBeforeAdvice; import org.springframework.aop.testfixture.interceptor.NopInterceptor; import org.springframework.beans.testfixture.beans.ITestBean; @@ -35,6 +36,7 @@ import org.springframework.beans.testfixture.beans.TestBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextException; import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import static org.assertj.core.api.Assertions.assertThat; @@ -304,6 +306,8 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab CglibAopProxy cglib = new CglibAopProxy(as); ITestBean proxy1 = (ITestBean) cglib.getProxy(); + ITestBean proxy1a = (ITestBean) cglib.getProxy(); + assertThat(proxy1a.getClass()).isSameAs(proxy1.getClass()); mockTargetSource.setTarget(proxy1); as = new AdvisedSupport(new Class[]{}); @@ -313,6 +317,39 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab ITestBean proxy2 = (ITestBean) cglib.getProxy(); assertThat(proxy2).isInstanceOf(Serializable.class); + assertThat(proxy2.getClass()).isNotSameAs(proxy1.getClass()); + + ITestBean proxy2a = (ITestBean) cglib.getProxy(); + assertThat(proxy2a).isInstanceOf(Serializable.class); + assertThat(proxy2a.getClass()).isSameAs(proxy2.getClass()); + + mockTargetSource.setTarget(proxy1); + as = new AdvisedSupport(new Class[]{}); + as.setTargetSource(mockTargetSource); + as.addAdvisor(new DefaultPointcutAdvisor(new AnnotationMatchingPointcut(Nullable.class), new NopInterceptor())); + cglib = new CglibAopProxy(as); + + ITestBean proxy3 = (ITestBean) cglib.getProxy(); + assertThat(proxy3).isInstanceOf(Serializable.class); + assertThat(proxy3.getClass()).isNotSameAs(proxy2.getClass()); + + ITestBean proxy3a = (ITestBean) cglib.getProxy(); + assertThat(proxy3a).isInstanceOf(Serializable.class); + assertThat(proxy3a.getClass()).isSameAs(proxy3.getClass()); + + mockTargetSource.setTarget(proxy1); + as = new AdvisedSupport(new Class[]{}); + as.setTargetSource(mockTargetSource); + as.addAdvisor(new DefaultPointcutAdvisor(new AnnotationMatchingPointcut(NonNull.class), new NopInterceptor())); + cglib = new CglibAopProxy(as); + + ITestBean proxy4 = (ITestBean) cglib.getProxy(); + assertThat(proxy4).isInstanceOf(Serializable.class); + assertThat(proxy4.getClass()).isNotSameAs(proxy3.getClass()); + + ITestBean proxy4a = (ITestBean) cglib.getProxy(); + assertThat(proxy4a).isInstanceOf(Serializable.class); + assertThat(proxy4a.getClass()).isSameAs(proxy4.getClass()); } @Test From 6931106c5eb1160091be17ef205258079f63dd0d Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 8 Jun 2023 17:28:52 +0200 Subject: [PATCH 3/4] Redesign inner Pointcut implementations as standalone classes Avoids exposure of implicit Advisor instance state in Pointcut instance. See gh-30621 --- ...anFactoryJCacheOperationSourceAdvisor.java | 55 +++++++++++++++---- .../JCacheOperationSourcePointcut.java | 4 +- ...eanFactoryCacheOperationSourceAdvisor.java | 20 +++---- .../CacheOperationSourcePointcut.java | 38 ++++++------- ...toryTransactionAttributeSourceAdvisor.java | 16 +----- .../TransactionAttributeSourceAdvisor.java | 12 ++-- .../TransactionAttributeSourcePointcut.java | 38 ++++++------- 7 files changed, 93 insertions(+), 90 deletions(-) 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 62ae44f03a..baf635e4d2 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-2018 the original author or authors. + * Copyright 2002-2023 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,30 +16,30 @@ package org.springframework.cache.jcache.interceptor; +import java.io.Serializable; +import java.lang.reflect.Method; + import org.springframework.aop.ClassFilter; import org.springframework.aop.Pointcut; import org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor; +import org.springframework.aop.support.StaticMethodMatcherPointcut; import org.springframework.lang.Nullable; +import org.springframework.util.ObjectUtils; /** * Advisor driven by a {@link JCacheOperationSource}, used to include a * cache advice bean for methods that are cacheable. * * @author Stephane Nicoll + * @author Juergen Hoeller * @since 4.1 + * @see #setAdviceBeanName + * @see JCacheInterceptor */ @SuppressWarnings("serial") public class BeanFactoryJCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor { - @Nullable - private JCacheOperationSource cacheOperationSource; - - private final JCacheOperationSourcePointcut pointcut = new JCacheOperationSourcePointcut() { - @Override - protected JCacheOperationSource getCacheOperationSource() { - return cacheOperationSource; - } - }; + private final JCacheOperationSourcePointcut pointcut = new JCacheOperationSourcePointcut(); /** @@ -48,7 +48,7 @@ public class BeanFactoryJCacheOperationSourceAdvisor extends AbstractBeanFactory * set on the cache interceptor itself. */ public void setCacheOperationSource(JCacheOperationSource cacheOperationSource) { - this.cacheOperationSource = cacheOperationSource; + this.pointcut.setCacheOperationSource(cacheOperationSource); } /** @@ -64,4 +64,37 @@ public class BeanFactoryJCacheOperationSourceAdvisor extends AbstractBeanFactory return this.pointcut; } + + private static class JCacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { + + @Nullable + private JCacheOperationSource cacheOperationSource; + + public void setCacheOperationSource(@Nullable JCacheOperationSource cacheOperationSource) { + this.cacheOperationSource = cacheOperationSource; + } + + @Override + public boolean matches(Method method, Class targetClass) { + return (this.cacheOperationSource == null || + this.cacheOperationSource.getCacheOperation(method, targetClass) != null); + } + + @Override + public boolean equals(@Nullable Object other) { + return (this == other || (other instanceof JCacheOperationSourcePointcut otherPc && + ObjectUtils.nullSafeEquals(this.cacheOperationSource, otherPc.cacheOperationSource))); + } + + @Override + public int hashCode() { + return JCacheOperationSourcePointcut.class.hashCode(); + } + + @Override + public String toString() { + return getClass().getName() + ": " + this.cacheOperationSource; + } + } + } 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 1dbb421089..b81512728b 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-2021 the original author or authors. + * Copyright 2002-2023 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,7 +29,9 @@ import org.springframework.util.ObjectUtils; * * @author Stephane Nicoll * @since 4.1 + * @deprecated since 6.0.10, as it is not used by the framework anymore */ +@Deprecated(since = "6.0.10", forRemoval = true) @SuppressWarnings("serial") public abstract class JCacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/BeanFactoryCacheOperationSourceAdvisor.java b/spring-context/src/main/java/org/springframework/cache/interceptor/BeanFactoryCacheOperationSourceAdvisor.java index efd0cf7aae..70844ad1b0 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/BeanFactoryCacheOperationSourceAdvisor.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/BeanFactoryCacheOperationSourceAdvisor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2023 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,37 +19,31 @@ package org.springframework.cache.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 CacheOperationSource}, used to include a * cache advice bean for methods that are cacheable. * * @author Costin Leau + * @author Juergen Hoeller * @since 3.1 + * @see #setAdviceBeanName + * @see CacheInterceptor */ @SuppressWarnings("serial") public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor { - @Nullable - private CacheOperationSource cacheOperationSource; - - private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() { - @Override - @Nullable - protected CacheOperationSource getCacheOperationSource() { - return cacheOperationSource; - } - }; + private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut(); /** * Set the cache operation attribute source which is used to find cache * attributes. This should usually be identical to the source reference * set on the cache interceptor itself. + * @see CacheInterceptor#setCacheOperationSource */ public void setCacheOperationSource(CacheOperationSource cacheOperationSource) { - this.cacheOperationSource = cacheOperationSource; + this.pointcut.setCacheOperationSource(cacheOperationSource); } /** diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheOperationSourcePointcut.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheOperationSourcePointcut.java index d555d802a2..3911dffe50 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheOperationSourcePointcut.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheOperationSourcePointcut.java @@ -35,28 +35,31 @@ import org.springframework.util.ObjectUtils; * @since 3.1 */ @SuppressWarnings("serial") -abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { +class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { - protected CacheOperationSourcePointcut() { + @Nullable + private CacheOperationSource cacheOperationSource; + + + public CacheOperationSourcePointcut() { setClassFilter(new CacheOperationSourceClassFilter()); } + public void setCacheOperationSource(@Nullable CacheOperationSource cacheOperationSource) { + this.cacheOperationSource = cacheOperationSource; + } + @Override public boolean matches(Method method, Class targetClass) { - CacheOperationSource cas = getCacheOperationSource(); - return (cas != null && !CollectionUtils.isEmpty(cas.getCacheOperations(method, targetClass))); + return (this.cacheOperationSource == null || + !CollectionUtils.isEmpty(this.cacheOperationSource.getCacheOperations(method, targetClass))); } @Override public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof CacheOperationSourcePointcut otherPc)) { - return false; - } - return ObjectUtils.nullSafeEquals(getCacheOperationSource(), otherPc.getCacheOperationSource()); + return (this == other || (other instanceof CacheOperationSourcePointcut otherPc && + ObjectUtils.nullSafeEquals(this.cacheOperationSource, otherPc.cacheOperationSource))); } @Override @@ -66,18 +69,10 @@ abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut @Override public String toString() { - return getClass().getName() + ": " + getCacheOperationSource(); + return getClass().getName() + ": " + this.cacheOperationSource; } - /** - * Obtain the underlying {@link CacheOperationSource} (may be {@code null}). - * To be implemented by subclasses. - */ - @Nullable - protected abstract CacheOperationSource getCacheOperationSource(); - - /** * {@link ClassFilter} that delegates to {@link CacheOperationSource#isCandidateClass} * for filtering classes whose methods are not worth searching to begin with. @@ -89,8 +84,7 @@ abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut if (CacheManager.class.isAssignableFrom(clazz)) { return false; } - CacheOperationSource cas = getCacheOperationSource(); - return (cas == null || cas.isCandidateClass(clazz)); + return (cacheOperationSource == null || cacheOperationSource.isCandidateClass(clazz)); } } diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/BeanFactoryTransactionAttributeSourceAdvisor.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/BeanFactoryTransactionAttributeSourceAdvisor.java index f52410ed9e..75f6b391d5 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/BeanFactoryTransactionAttributeSourceAdvisor.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/BeanFactoryTransactionAttributeSourceAdvisor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2023 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,7 +19,6 @@ package org.springframework.transaction.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 TransactionAttributeSource}, used to include @@ -34,16 +33,7 @@ import org.springframework.lang.Nullable; @SuppressWarnings("serial") public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor { - @Nullable - private TransactionAttributeSource transactionAttributeSource; - - private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() { - @Override - @Nullable - protected TransactionAttributeSource getTransactionAttributeSource() { - return transactionAttributeSource; - } - }; + private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut(); /** @@ -53,7 +43,7 @@ public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFa * @see TransactionInterceptor#setTransactionAttributeSource */ public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) { - this.transactionAttributeSource = transactionAttributeSource; + this.pointcut.setTransactionAttributeSource(transactionAttributeSource); } /** diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSourceAdvisor.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSourceAdvisor.java index 5e65816fdb..bbaca68870 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSourceAdvisor.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSourceAdvisor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2023 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,13 +43,7 @@ public class TransactionAttributeSourceAdvisor extends AbstractPointcutAdvisor { @Nullable private TransactionInterceptor transactionInterceptor; - private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() { - @Override - @Nullable - protected TransactionAttributeSource getTransactionAttributeSource() { - return (transactionInterceptor != null ? transactionInterceptor.getTransactionAttributeSource() : null); - } - }; + private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut(); /** @@ -71,7 +65,9 @@ public class TransactionAttributeSourceAdvisor extends AbstractPointcutAdvisor { * Set the transaction interceptor to use for this advisor. */ public void setTransactionInterceptor(TransactionInterceptor interceptor) { + Assert.notNull(interceptor, "TransactionInterceptor must not be null"); this.transactionInterceptor = interceptor; + this.pointcut.setTransactionAttributeSource(interceptor.getTransactionAttributeSource()); } /** diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSourcePointcut.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSourcePointcut.java index a7cdc8867d..0877acaf8a 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSourcePointcut.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSourcePointcut.java @@ -34,28 +34,31 @@ import org.springframework.util.ObjectUtils; * @since 2.5.5 */ @SuppressWarnings("serial") -abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { +class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { - protected TransactionAttributeSourcePointcut() { + @Nullable + private TransactionAttributeSource transactionAttributeSource; + + + public TransactionAttributeSourcePointcut() { setClassFilter(new TransactionAttributeSourceClassFilter()); } + public void setTransactionAttributeSource(@Nullable TransactionAttributeSource transactionAttributeSource) { + this.transactionAttributeSource = transactionAttributeSource; + } + @Override public boolean matches(Method method, Class targetClass) { - TransactionAttributeSource tas = getTransactionAttributeSource(); - return (tas == null || tas.getTransactionAttribute(method, targetClass) != null); + return (this.transactionAttributeSource == null || + this.transactionAttributeSource.getTransactionAttribute(method, targetClass) != null); } @Override public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof TransactionAttributeSourcePointcut otherPc)) { - return false; - } - return ObjectUtils.nullSafeEquals(getTransactionAttributeSource(), otherPc.getTransactionAttributeSource()); + return (this == other || (other instanceof TransactionAttributeSourcePointcut otherPc && + ObjectUtils.nullSafeEquals(this.transactionAttributeSource, otherPc.transactionAttributeSource))); } @Override @@ -65,18 +68,10 @@ abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPoi @Override public String toString() { - return getClass().getName() + ": " + getTransactionAttributeSource(); + return getClass().getName() + ": " + this.transactionAttributeSource; } - /** - * Obtain the underlying TransactionAttributeSource (may be {@code null}). - * To be implemented by subclasses. - */ - @Nullable - protected abstract TransactionAttributeSource getTransactionAttributeSource(); - - /** * {@link ClassFilter} that delegates to {@link TransactionAttributeSource#isCandidateClass} * for filtering classes whose methods are not worth searching to begin with. @@ -90,8 +85,7 @@ abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPoi PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) { return false; } - TransactionAttributeSource tas = getTransactionAttributeSource(); - return (tas == null || tas.isCandidateClass(clazz)); + return (transactionAttributeSource == null || transactionAttributeSource.isCandidateClass(clazz)); } } From c16f582ed829eb6cee8c1019f2fafc6083ddffec Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 8 Jun 2023 17:36:39 +0200 Subject: [PATCH 4/4] Consistent equals implementations in AOP support classes --- .../support/AbstractRegexpMethodPointcut.java | 13 ++++------- .../aop/support/ComposablePointcut.java | 13 ++++------- .../aop/support/ControlFlowPointcut.java | 12 ++++------ .../aop/support/MethodMatchers.java | 20 +++++------------ .../annotation/AnnotationClassFilter.java | 12 ++++------ .../AnnotationMatchingPointcut.java | 22 +++++-------------- .../annotation/AnnotationMethodMatcher.java | 19 ++++++---------- .../AnnotationCacheOperationSource.java | 13 ++++------- .../NameMatchCacheOperationSource.java | 12 ++++------ .../AnnotationTransactionAttributeSource.java | 13 ++++------- .../MethodMapTransactionAttributeSource.java | 11 +++------- .../NameMatchTransactionAttributeSource.java | 11 +++------- 12 files changed, 52 insertions(+), 119 deletions(-) diff --git a/spring-aop/src/main/java/org/springframework/aop/support/AbstractRegexpMethodPointcut.java b/spring-aop/src/main/java/org/springframework/aop/support/AbstractRegexpMethodPointcut.java index 44f5766901..30fead6732 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/AbstractRegexpMethodPointcut.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/AbstractRegexpMethodPointcut.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2023 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. @@ -196,14 +196,9 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo @Override public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof AbstractRegexpMethodPointcut otherPointcut)) { - return false; - } - return (Arrays.equals(this.patterns, otherPointcut.patterns) && - Arrays.equals(this.excludedPatterns, otherPointcut.excludedPatterns)); + return (this == other || (other instanceof AbstractRegexpMethodPointcut otherPointcut && + Arrays.equals(this.patterns, otherPointcut.patterns) && + Arrays.equals(this.excludedPatterns, otherPointcut.excludedPatterns))); } @Override diff --git a/spring-aop/src/main/java/org/springframework/aop/support/ComposablePointcut.java b/spring-aop/src/main/java/org/springframework/aop/support/ComposablePointcut.java index 1ac7fd2117..432635510c 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/ComposablePointcut.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/ComposablePointcut.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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. @@ -187,14 +187,9 @@ public class ComposablePointcut implements Pointcut, Serializable { @Override public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof ComposablePointcut otherPointcut)) { - return false; - } - return (this.classFilter.equals(otherPointcut.classFilter) && - this.methodMatcher.equals(otherPointcut.methodMatcher)); + return (this == other || (other instanceof ComposablePointcut otherPointcut && + this.classFilter.equals(otherPointcut.classFilter) && + this.methodMatcher.equals(otherPointcut.methodMatcher))); } @Override diff --git a/spring-aop/src/main/java/org/springframework/aop/support/ControlFlowPointcut.java b/spring-aop/src/main/java/org/springframework/aop/support/ControlFlowPointcut.java index 788eae69a5..67eeecea0e 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/ControlFlowPointcut.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/ControlFlowPointcut.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2023 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. @@ -125,13 +125,9 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher @Override public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof ControlFlowPointcut that)) { - return false; - } - return (this.clazz.equals(that.clazz)) && ObjectUtils.nullSafeEquals(this.methodName, that.methodName); + return (this == other || (other instanceof ControlFlowPointcut that && + this.clazz.equals(that.clazz)) && + ObjectUtils.nullSafeEquals(this.methodName, that.methodName)); } @Override diff --git a/spring-aop/src/main/java/org/springframework/aop/support/MethodMatchers.java b/spring-aop/src/main/java/org/springframework/aop/support/MethodMatchers.java index 19bf5adbb0..22e8b44d2d 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/MethodMatchers.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/MethodMatchers.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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. @@ -143,13 +143,8 @@ public abstract class MethodMatchers { @Override public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof UnionMethodMatcher that)) { - return false; - } - return (this.mm1.equals(that.mm1) && this.mm2.equals(that.mm2)); + return (this == other || (other instanceof UnionMethodMatcher that && + this.mm1.equals(that.mm1) && this.mm2.equals(that.mm2))); } @Override @@ -307,13 +302,8 @@ public abstract class MethodMatchers { @Override public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof IntersectionMethodMatcher that)) { - return false; - } - return (this.mm1.equals(that.mm1) && this.mm2.equals(that.mm2)); + return (this == other || (other instanceof IntersectionMethodMatcher that && + this.mm1.equals(that.mm1) && this.mm2.equals(that.mm2))); } @Override diff --git a/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationClassFilter.java b/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationClassFilter.java index 997bcb9509..9b234633ad 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationClassFilter.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationClassFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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. @@ -68,13 +68,9 @@ public class AnnotationClassFilter implements ClassFilter { @Override public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof AnnotationClassFilter otherCf)) { - return false; - } - return (this.annotationType.equals(otherCf.annotationType) && this.checkInherited == otherCf.checkInherited); + return (this == other || (other instanceof AnnotationClassFilter otherCf && + this.annotationType.equals(otherCf.annotationType) && + this.checkInherited == otherCf.checkInherited)); } @Override diff --git a/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMatchingPointcut.java b/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMatchingPointcut.java index 4dacd14936..421063c67f 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMatchingPointcut.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMatchingPointcut.java @@ -121,14 +121,9 @@ public class AnnotationMatchingPointcut implements Pointcut { @Override public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof AnnotationMatchingPointcut otherPointcut)) { - return false; - } - return (this.classFilter.equals(otherPointcut.classFilter) && - this.methodMatcher.equals(otherPointcut.methodMatcher)); + return (this == other || (other instanceof AnnotationMatchingPointcut otherPointcut && + this.classFilter.equals(otherPointcut.classFilter) && + this.methodMatcher.equals(otherPointcut.methodMatcher))); } @Override @@ -183,14 +178,9 @@ public class AnnotationMatchingPointcut implements Pointcut { } @Override - public boolean equals(@Nullable Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof AnnotationCandidateClassFilter that)) { - return false; - } - return this.annotationType.equals(that.annotationType); + public boolean equals(@Nullable Object other) { + return (this == other || (other instanceof AnnotationCandidateClassFilter that && + this.annotationType.equals(that.annotationType))); } @Override diff --git a/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMethodMatcher.java b/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMethodMatcher.java index af5dfa4cdc..520519ff72 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMethodMatcher.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMethodMatcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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,10 +27,9 @@ import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** - * Simple {@link org.springframework.aop.MethodMatcher MethodMatcher} that looks - * for a specific annotation being present on a method (checking both the method - * on the invoked interface, if any, and the corresponding method on the target - * class). + * Simple {@link org.springframework.aop.MethodMatcher MethodMatcher} that looks for + * a specific annotation being present on a method (checking both the method on the + * invoked interface, if any, and the corresponding method on the target class). * * @author Juergen Hoeller * @author Sam Brannen @@ -90,13 +89,9 @@ public class AnnotationMethodMatcher extends StaticMethodMatcher { @Override public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof AnnotationMethodMatcher otherMm)) { - return false; - } - return (this.annotationType.equals(otherMm.annotationType) && this.checkInherited == otherMm.checkInherited); + return (this == other || (other instanceof AnnotationMethodMatcher otherMm && + this.annotationType.equals(otherMm.annotationType) && + this.checkInherited == otherMm.checkInherited)); } @Override diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java b/spring-context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java index 230a36d187..acc7242121 100644 --- a/spring-context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java +++ b/spring-context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2023 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. @@ -165,14 +165,9 @@ public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperati @Override public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof AnnotationCacheOperationSource otherCos)) { - return false; - } - return (this.annotationParsers.equals(otherCos.annotationParsers) && - this.publicMethodsOnly == otherCos.publicMethodsOnly); + return (this == other || (other instanceof AnnotationCacheOperationSource otherCos && + this.annotationParsers.equals(otherCos.annotationParsers) && + this.publicMethodsOnly == otherCos.publicMethodsOnly)); } @Override diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/NameMatchCacheOperationSource.java b/spring-context/src/main/java/org/springframework/cache/interceptor/NameMatchCacheOperationSource.java index d916e3f89c..a06cb8cf4b 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/NameMatchCacheOperationSource.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/NameMatchCacheOperationSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2023 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. @@ -111,13 +111,8 @@ public class NameMatchCacheOperationSource implements CacheOperationSource, Seri @Override public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof NameMatchCacheOperationSource otherTas)) { - return false; - } - return ObjectUtils.nullSafeEquals(this.nameMap, otherTas.nameMap); + return (this == other || (other instanceof NameMatchCacheOperationSource otherCos && + ObjectUtils.nullSafeEquals(this.nameMap, otherCos.nameMap))); } @Override @@ -129,4 +124,5 @@ public class NameMatchCacheOperationSource implements CacheOperationSource, Seri public String toString() { return getClass().getName() + ": " + this.nameMap; } + } diff --git a/spring-tx/src/main/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSource.java b/spring-tx/src/main/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSource.java index 5d4e2e9395..4b6b81b708 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSource.java +++ b/spring-tx/src/main/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2023 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. @@ -191,14 +191,9 @@ public class AnnotationTransactionAttributeSource extends AbstractFallbackTransa @Override public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof AnnotationTransactionAttributeSource otherTas)) { - return false; - } - return (this.annotationParsers.equals(otherTas.annotationParsers) && - this.publicMethodsOnly == otherTas.publicMethodsOnly); + return (this == other || (other instanceof AnnotationTransactionAttributeSource otherTas && + this.annotationParsers.equals(otherTas.annotationParsers) && + this.publicMethodsOnly == otherTas.publicMethodsOnly)); } @Override diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/MethodMapTransactionAttributeSource.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/MethodMapTransactionAttributeSource.java index e328a88a2e..5b90510878 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/MethodMapTransactionAttributeSource.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/MethodMapTransactionAttributeSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2023 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. @@ -239,13 +239,8 @@ public class MethodMapTransactionAttributeSource @Override public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof MethodMapTransactionAttributeSource otherTas)) { - return false; - } - return ObjectUtils.nullSafeEquals(this.methodMap, otherTas.methodMap); + return (this == other || (other instanceof MethodMapTransactionAttributeSource otherTas && + ObjectUtils.nullSafeEquals(this.methodMap, otherTas.methodMap))); } @Override diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/NameMatchTransactionAttributeSource.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/NameMatchTransactionAttributeSource.java index a0f4e15bf4..0b2cc33f11 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/NameMatchTransactionAttributeSource.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/NameMatchTransactionAttributeSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2023 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. @@ -164,13 +164,8 @@ public class NameMatchTransactionAttributeSource @Override public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof NameMatchTransactionAttributeSource otherTas)) { - return false; - } - return ObjectUtils.nullSafeEquals(this.nameMap, otherTas.nameMap); + return (this == other || (other instanceof NameMatchTransactionAttributeSource otherTas && + ObjectUtils.nullSafeEquals(this.nameMap, otherTas.nameMap))); } @Override