GH-3765 Resolve Lookup ctor lazily via reflection
Fixes https://github.com/spring-projects/spring-integration/issues/3765 The `DefaultMethodInvokingMethodInterceptor` has several strategies for `default` method invocations in the messaging gateway. One of them is based on the `Lookup` constructor which causes a `WARNING: An illegal reflective access operation has occurred`. This can be done lazily when there is no `MethodHandles.privateLookupIn` in Java version used for the project. * Fix `OPEN` enum value for the `Constructor<Lookup>` to be resolved in a lazy manner via `Supplier` and `boolean` flag **Cherry-pick to `5.5.x`**
This commit is contained in:
committed by
Gary Russell
parent
6a435fbd77
commit
cd84f1699a
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2021 the original author or authors.
|
* Copyright 2015-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -23,6 +23,7 @@ import java.lang.invoke.MethodType;
|
|||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.aopalliance.intercept.MethodInterceptor;
|
import org.aopalliance.intercept.MethodInterceptor;
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
@@ -119,29 +120,36 @@ class DefaultMethodInvokingMethodInterceptor implements MethodInterceptor {
|
|||||||
*/
|
*/
|
||||||
OPEN {
|
OPEN {
|
||||||
|
|
||||||
@Nullable
|
private volatile boolean constructorResolved;
|
||||||
private final transient Constructor<Lookup> constructor;
|
|
||||||
|
|
||||||
{
|
private Constructor<Lookup> constructor;
|
||||||
Constructor<Lookup> ctor = null;
|
|
||||||
try {
|
private final Supplier<Constructor<Lookup>> constructorSupplier =
|
||||||
ctor = Lookup.class.getDeclaredConstructor(Class.class);
|
() -> {
|
||||||
ReflectionUtils.makeAccessible(ctor);
|
if (!this.constructorResolved) {
|
||||||
}
|
Constructor<Lookup> ctor = null;
|
||||||
catch (Exception ex) {
|
try {
|
||||||
// this is the signal that we are on Java 9 (encapsulated) and can't use the accessible constructor
|
ctor = Lookup.class.getDeclaredConstructor(Class.class);
|
||||||
// approach.
|
ReflectionUtils.makeAccessible(ctor);
|
||||||
if (!ex.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")) {
|
}
|
||||||
throw new IllegalStateException(ex);
|
catch (Exception ex) {
|
||||||
}
|
// this is the signal that we are on Java 9 (encapsulated) and can't use the accessible
|
||||||
}
|
// constructor approach.
|
||||||
this.constructor = ctor;
|
if (!ex.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")) {
|
||||||
}
|
throw new IllegalStateException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.constructor = ctor;
|
||||||
|
this.constructorResolved = true;
|
||||||
|
}
|
||||||
|
return this.constructor;
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
MethodHandle lookup(Method method) throws ReflectiveOperationException {
|
MethodHandle lookup(Method method) throws ReflectiveOperationException {
|
||||||
if (this.constructor != null) {
|
Constructor<Lookup> lookupConstructor = this.constructorSupplier.get();
|
||||||
return this.constructor.newInstance(method.getDeclaringClass())
|
if (lookupConstructor != null) {
|
||||||
|
return lookupConstructor.newInstance(method.getDeclaringClass())
|
||||||
.unreflectSpecial(method, method.getDeclaringClass());
|
.unreflectSpecial(method, method.getDeclaringClass());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -151,7 +159,7 @@ class DefaultMethodInvokingMethodInterceptor implements MethodInterceptor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean isAvailable() {
|
boolean isAvailable() {
|
||||||
return this.constructor != null;
|
return this.constructorSupplier.get() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -160,7 +168,6 @@ class DefaultMethodInvokingMethodInterceptor implements MethodInterceptor {
|
|||||||
* Fallback {@link MethodHandle} lookup using {@link MethodHandles#lookup() public lookup}.
|
* Fallback {@link MethodHandle} lookup using {@link MethodHandles#lookup() public lookup}.
|
||||||
*/
|
*/
|
||||||
FALLBACK {
|
FALLBACK {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
MethodHandle lookup(Method method) throws ReflectiveOperationException {
|
MethodHandle lookup(Method method) throws ReflectiveOperationException {
|
||||||
return doLookup(method, MethodHandles.lookup());
|
return doLookup(method, MethodHandles.lookup());
|
||||||
@@ -191,7 +198,7 @@ class DefaultMethodInvokingMethodInterceptor implements MethodInterceptor {
|
|||||||
* @return the {@link MethodHandleLookup}
|
* @return the {@link MethodHandleLookup}
|
||||||
* @throws IllegalStateException if no {@link MethodHandleLookup} is available.
|
* @throws IllegalStateException if no {@link MethodHandleLookup} is available.
|
||||||
*/
|
*/
|
||||||
public static MethodHandleLookup getMethodHandleLookup() {
|
static MethodHandleLookup getMethodHandleLookup() {
|
||||||
for (MethodHandleLookup it : MethodHandleLookup.values()) {
|
for (MethodHandleLookup it : MethodHandleLookup.values()) {
|
||||||
if (it.isAvailable()) {
|
if (it.isAvailable()) {
|
||||||
return it;
|
return it;
|
||||||
|
|||||||
Reference in New Issue
Block a user