Merge branch '5.3.x'
# Conflicts: # spring-core/src/main/java/org/springframework/cglib/core/ReflectUtils.java
This commit is contained in:
commit
dc5807ea51
|
|
@ -679,13 +679,19 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||||
Object retVal;
|
Object retVal;
|
||||||
// Check whether we only have one InvokerInterceptor: that is,
|
// Check whether we only have one InvokerInterceptor: that is,
|
||||||
// no real advice, but just reflective invocation of the target.
|
// no real advice, but just reflective invocation of the target.
|
||||||
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
|
if (chain.isEmpty() && CglibMethodInvocation.isMethodProxyCompatible(method)) {
|
||||||
// We can skip creating a MethodInvocation: just invoke the target directly.
|
// We can skip creating a MethodInvocation: just invoke the target directly.
|
||||||
// Note that the final invoker must be an InvokerInterceptor, so we know
|
// Note that the final invoker must be an InvokerInterceptor, so we know
|
||||||
// it does nothing but a reflective operation on the target, and no hot
|
// it does nothing but a reflective operation on the target, and no hot
|
||||||
// swapping or fancy proxying.
|
// swapping or fancy proxying.
|
||||||
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
|
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
|
||||||
retVal = methodProxy.invoke(target, argsToUse);
|
try {
|
||||||
|
retVal = methodProxy.invoke(target, argsToUse);
|
||||||
|
}
|
||||||
|
catch (CodeGenerationException ex) {
|
||||||
|
CglibMethodInvocation.logFastClassGenerationFailure(method);
|
||||||
|
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// We need to create a method invocation...
|
// We need to create a method invocation...
|
||||||
|
|
@ -737,10 +743,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||||
super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
|
super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
|
||||||
|
|
||||||
// Only use method proxy for public methods not derived from java.lang.Object
|
// Only use method proxy for public methods not derived from java.lang.Object
|
||||||
this.methodProxy = (Modifier.isPublic(method.getModifiers()) &&
|
this.methodProxy = (isMethodProxyCompatible(method) ? methodProxy : null);
|
||||||
method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) &&
|
|
||||||
!AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ?
|
|
||||||
methodProxy : null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -776,10 +779,25 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||||
@Override
|
@Override
|
||||||
protected Object invokeJoinpoint() throws Throwable {
|
protected Object invokeJoinpoint() throws Throwable {
|
||||||
if (this.methodProxy != null) {
|
if (this.methodProxy != null) {
|
||||||
return this.methodProxy.invoke(this.target, this.arguments);
|
try {
|
||||||
|
return this.methodProxy.invoke(this.target, this.arguments);
|
||||||
|
}
|
||||||
|
catch (CodeGenerationException ex) {
|
||||||
|
logFastClassGenerationFailure(this.method);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
return super.invokeJoinpoint();
|
||||||
return super.invokeJoinpoint();
|
}
|
||||||
|
|
||||||
|
static boolean isMethodProxyCompatible(Method method) {
|
||||||
|
return (Modifier.isPublic(method.getModifiers()) &&
|
||||||
|
method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) &&
|
||||||
|
!AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logFastClassGenerationFailure(Method method) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Failed to generate CGLIB fast class for method: " + method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,43 +55,40 @@ public class ReflectUtils {
|
||||||
|
|
||||||
private static final Method classLoaderDefineClassMethod;
|
private static final Method classLoaderDefineClassMethod;
|
||||||
|
|
||||||
private static final ProtectionDomain PROTECTION_DOMAIN;
|
|
||||||
|
|
||||||
private static final Throwable THROWABLE;
|
private static final Throwable THROWABLE;
|
||||||
|
|
||||||
|
private static final ProtectionDomain PROTECTION_DOMAIN;
|
||||||
|
|
||||||
private static final List<Method> OBJECT_METHODS = new ArrayList<Method>();
|
private static final List<Method> OBJECT_METHODS = new ArrayList<Method>();
|
||||||
|
|
||||||
// SPRING PATCH BEGIN
|
// SPRING PATCH BEGIN
|
||||||
static {
|
static {
|
||||||
Method classLoaderDefineClass;
|
Method classLoaderDefineClass;
|
||||||
ProtectionDomain protectionDomain;
|
|
||||||
Throwable throwable = null;
|
Throwable throwable = null;
|
||||||
try {
|
try {
|
||||||
classLoaderDefineClass = ClassLoader.class.getDeclaredMethod("defineClass",
|
classLoaderDefineClass = ClassLoader.class.getDeclaredMethod("defineClass",
|
||||||
String.class, byte[].class, Integer.TYPE, Integer.TYPE, ProtectionDomain.class);
|
String.class, byte[].class, Integer.TYPE, Integer.TYPE, ProtectionDomain.class);
|
||||||
protectionDomain = getProtectionDomain(ReflectUtils.class);
|
|
||||||
for (Method method : Object.class.getDeclaredMethods()) {
|
|
||||||
if ("finalize".equals(method.getName())
|
|
||||||
|| (method.getModifiers() & (Modifier.FINAL | Modifier.STATIC)) > 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
OBJECT_METHODS.add(method);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Throwable t) {
|
catch (Throwable t) {
|
||||||
classLoaderDefineClass = null;
|
classLoaderDefineClass = null;
|
||||||
protectionDomain = null;
|
|
||||||
throwable = t;
|
throwable = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
classLoaderDefineClassMethod = classLoaderDefineClass;
|
classLoaderDefineClassMethod = classLoaderDefineClass;
|
||||||
PROTECTION_DOMAIN = protectionDomain;
|
|
||||||
THROWABLE = throwable;
|
THROWABLE = throwable;
|
||||||
|
PROTECTION_DOMAIN = getProtectionDomain(ReflectUtils.class);
|
||||||
|
|
||||||
|
for (Method method : Object.class.getDeclaredMethods()) {
|
||||||
|
if ("finalize".equals(method.getName())
|
||||||
|
|| (method.getModifiers() & (Modifier.FINAL | Modifier.STATIC)) > 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
OBJECT_METHODS.add(method);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// SPRING PATCH END
|
// SPRING PATCH END
|
||||||
|
|
||||||
private static final String[] CGLIB_PACKAGES = {
|
private static final String[] CGLIB_PACKAGES = {"java.lang"};
|
||||||
"java.lang",
|
|
||||||
};
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
primitives.put("byte", Byte.TYPE);
|
primitives.put("byte", Byte.TYPE);
|
||||||
|
|
@ -444,6 +441,7 @@ public class ReflectUtils {
|
||||||
ProtectionDomain protectionDomain, Class<?> contextClass) throws Exception {
|
ProtectionDomain protectionDomain, Class<?> contextClass) throws Exception {
|
||||||
|
|
||||||
Class c = null;
|
Class c = null;
|
||||||
|
Throwable t = THROWABLE;
|
||||||
|
|
||||||
// Preferred option: JDK 9+ Lookup.defineClass API if ClassLoader matches
|
// Preferred option: JDK 9+ Lookup.defineClass API if ClassLoader matches
|
||||||
if (contextClass != null && contextClass.getClassLoader() == loader) {
|
if (contextClass != null && contextClass.getClassLoader() == loader) {
|
||||||
|
|
@ -455,6 +453,7 @@ public class ReflectUtils {
|
||||||
// in case of plain LinkageError (class already defined)
|
// in case of plain LinkageError (class already defined)
|
||||||
// or IllegalArgumentException (class in different package):
|
// or IllegalArgumentException (class in different package):
|
||||||
// fall through to traditional ClassLoader.defineClass below
|
// fall through to traditional ClassLoader.defineClass below
|
||||||
|
t = ex;
|
||||||
}
|
}
|
||||||
catch (Throwable ex) {
|
catch (Throwable ex) {
|
||||||
throw new CodeGenerationException(ex);
|
throw new CodeGenerationException(ex);
|
||||||
|
|
@ -478,9 +477,11 @@ public class ReflectUtils {
|
||||||
throw new CodeGenerationException(ex.getTargetException());
|
throw new CodeGenerationException(ex.getTargetException());
|
||||||
}
|
}
|
||||||
// in case of UnsupportedOperationException, fall through
|
// in case of UnsupportedOperationException, fall through
|
||||||
|
t = ex.getTargetException();
|
||||||
}
|
}
|
||||||
catch (Throwable ex) {
|
catch (Throwable ex) {
|
||||||
// publicDefineClass method not available -> fall through
|
// publicDefineClass method not available -> fall through
|
||||||
|
t = ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Classic option: protected ClassLoader.defineClass method
|
// Classic option: protected ClassLoader.defineClass method
|
||||||
|
|
@ -501,6 +502,7 @@ public class ReflectUtils {
|
||||||
if (!ex.getClass().getName().endsWith("InaccessibleObjectException")) {
|
if (!ex.getClass().getName().endsWith("InaccessibleObjectException")) {
|
||||||
throw new CodeGenerationException(ex);
|
throw new CodeGenerationException(ex);
|
||||||
}
|
}
|
||||||
|
t = ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -518,7 +520,7 @@ public class ReflectUtils {
|
||||||
|
|
||||||
// No defineClass variant available at all?
|
// No defineClass variant available at all?
|
||||||
if (c == null) {
|
if (c == null) {
|
||||||
throw new CodeGenerationException(THROWABLE);
|
throw new CodeGenerationException(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force static initializers to run.
|
// Force static initializers to run.
|
||||||
|
|
|
||||||
|
|
@ -89,8 +89,8 @@ public class SpringExtension implements BeforeAllCallback, AfterAllCallback, Tes
|
||||||
* {@link Namespace} in which {@code @Autowired} validation error messages
|
* {@link Namespace} in which {@code @Autowired} validation error messages
|
||||||
* are stored, keyed by test class.
|
* are stored, keyed by test class.
|
||||||
*/
|
*/
|
||||||
private static final Namespace AUTOWIRED_VALIDATION_NAMESPACE = Namespace.create(SpringExtension.class.getName() +
|
private static final Namespace AUTOWIRED_VALIDATION_NAMESPACE =
|
||||||
"#autowired.validation");
|
Namespace.create(SpringExtension.class.getName() + "#autowired.validation");
|
||||||
|
|
||||||
private static final String NO_AUTOWIRED_VIOLATIONS_DETECTED = "NO AUTOWIRED VIOLATIONS DETECTED";
|
private static final String NO_AUTOWIRED_VIOLATIONS_DETECTED = "NO AUTOWIRED VIOLATIONS DETECTED";
|
||||||
|
|
||||||
|
|
@ -101,8 +101,8 @@ public class SpringExtension implements BeforeAllCallback, AfterAllCallback, Tes
|
||||||
|
|
||||||
private static final MethodFilter autowiredTestOrLifecycleMethodFilter =
|
private static final MethodFilter autowiredTestOrLifecycleMethodFilter =
|
||||||
ReflectionUtils.USER_DECLARED_METHODS
|
ReflectionUtils.USER_DECLARED_METHODS
|
||||||
.and(method -> !Modifier.isPrivate(method.getModifiers()))
|
.and(method -> !Modifier.isPrivate(method.getModifiers()))
|
||||||
.and(SpringExtension::isAutowiredTestOrLifecycleMethod);
|
.and(SpringExtension::isAutowiredTestOrLifecycleMethod);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -147,16 +147,16 @@ public class SpringExtension implements BeforeAllCallback, AfterAllCallback, Tes
|
||||||
// We save the result in the ExtensionContext.Store so that we don't
|
// We save the result in the ExtensionContext.Store so that we don't
|
||||||
// re-validate all methods for the same test class multiple times.
|
// re-validate all methods for the same test class multiple times.
|
||||||
Store store = context.getStore(AUTOWIRED_VALIDATION_NAMESPACE);
|
Store store = context.getStore(AUTOWIRED_VALIDATION_NAMESPACE);
|
||||||
String errorMessage = store.getOrComputeIfAbsent(context.getRequiredTestClass(),
|
|
||||||
testClass -> {
|
String errorMessage = store.getOrComputeIfAbsent(context.getRequiredTestClass(), testClass -> {
|
||||||
Method[] methodsWithErrors =
|
Method[] methodsWithErrors =
|
||||||
ReflectionUtils.getUniqueDeclaredMethods(testClass, autowiredTestOrLifecycleMethodFilter);
|
ReflectionUtils.getUniqueDeclaredMethods(testClass, autowiredTestOrLifecycleMethodFilter);
|
||||||
return (methodsWithErrors.length == 0 ? NO_AUTOWIRED_VIOLATIONS_DETECTED :
|
return (methodsWithErrors.length == 0 ? NO_AUTOWIRED_VIOLATIONS_DETECTED :
|
||||||
String.format(
|
String.format(
|
||||||
"Test methods and test lifecycle methods must not be annotated with @Autowired. " +
|
"Test methods and test lifecycle methods must not be annotated with @Autowired. " +
|
||||||
"You should instead annotate individual method parameters with @Autowired, " +
|
"You should instead annotate individual method parameters with @Autowired, " +
|
||||||
"@Qualifier, or @Value. Offending methods in test class %s: %s",
|
"@Qualifier, or @Value. Offending methods in test class %s: %s",
|
||||||
testClass.getName(), Arrays.toString(methodsWithErrors)));
|
testClass.getName(), Arrays.toString(methodsWithErrors)));
|
||||||
}, String.class);
|
}, String.class);
|
||||||
|
|
||||||
if (errorMessage != NO_AUTOWIRED_VIOLATIONS_DETECTED) {
|
if (errorMessage != NO_AUTOWIRED_VIOLATIONS_DETECTED) {
|
||||||
|
|
@ -247,7 +247,7 @@ public class SpringExtension implements BeforeAllCallback, AfterAllCallback, Tes
|
||||||
private boolean supportsApplicationEvents(ParameterContext parameterContext) {
|
private boolean supportsApplicationEvents(ParameterContext parameterContext) {
|
||||||
if (ApplicationEvents.class.isAssignableFrom(parameterContext.getParameter().getType())) {
|
if (ApplicationEvents.class.isAssignableFrom(parameterContext.getParameter().getType())) {
|
||||||
Assert.isTrue(parameterContext.getDeclaringExecutable() instanceof Method,
|
Assert.isTrue(parameterContext.getDeclaringExecutable() instanceof Method,
|
||||||
"ApplicationEvents can only be injected into test and lifecycle methods");
|
"ApplicationEvents can only be injected into test and lifecycle methods");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue