Allow AccessControl to determine visibility from a given type

This commit adapts AccessVisibility so that it can determine if the
member or type signature is accessible from a given package. This lets
implementers figure out if reflection is necessary without assuming that
package private visibility is OK.

Closes gh-29245
This commit is contained in:
Stephane Nicoll
2022-10-03 10:49:25 +02:00
parent df58c00bf5
commit 3b2b36d0b8
19 changed files with 816 additions and 440 deletions

View File

@@ -40,7 +40,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aot.generate.AccessVisibility;
import org.springframework.aot.generate.AccessControl;
import org.springframework.aot.generate.GeneratedClass;
import org.springframework.aot.generate.GeneratedMethod;
import org.springframework.aot.generate.GenerationContext;
@@ -81,6 +81,7 @@ import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.javapoet.ClassName;
import org.springframework.javapoet.CodeBlock;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -941,7 +942,8 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
method.addParameter(RegisteredBean.class, REGISTERED_BEAN_PARAMETER);
method.addParameter(this.target, INSTANCE_PARAMETER);
method.returns(this.target);
method.addCode(generateMethodCode(generationContext.getRuntimeHints()));
method.addCode(generateMethodCode(generatedClass.getName(),
generationContext.getRuntimeHints()));
});
beanRegistrationCode.addInstancePostProcessor(generateMethod.toMethodReference());
@@ -950,41 +952,42 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
}
}
private CodeBlock generateMethodCode(RuntimeHints hints) {
private CodeBlock generateMethodCode(ClassName targetClassName, RuntimeHints hints) {
CodeBlock.Builder code = CodeBlock.builder();
for (AutowiredElement autowiredElement : this.autowiredElements) {
code.addStatement(
generateMethodStatementForElement(autowiredElement, hints));
code.addStatement(generateMethodStatementForElement(
targetClassName, autowiredElement, hints));
}
code.addStatement("return $L", INSTANCE_PARAMETER);
return code.build();
}
private CodeBlock generateMethodStatementForElement(
private CodeBlock generateMethodStatementForElement(ClassName targetClassName,
AutowiredElement autowiredElement, RuntimeHints hints) {
Member member = autowiredElement.getMember();
boolean required = autowiredElement.required;
if (member instanceof Field field) {
return generateMethodStatementForField(field, required, hints);
return generateMethodStatementForField(
targetClassName, field, required, hints);
}
if (member instanceof Method method) {
return generateMethodStatementForMethod(method, required, hints);
return generateMethodStatementForMethod(
targetClassName, method, required, hints);
}
throw new IllegalStateException(
"Unsupported member type " + member.getClass().getName());
}
private CodeBlock generateMethodStatementForField(Field field, boolean required,
RuntimeHints hints) {
private CodeBlock generateMethodStatementForField(ClassName targetClassName,
Field field, boolean required, RuntimeHints hints) {
hints.reflection().registerField(field);
CodeBlock resolver = CodeBlock.of("$T.$L($S)",
AutowiredFieldValueResolver.class,
(!required) ? "forField" : "forRequiredField", field.getName());
AccessVisibility visibility = AccessVisibility.forMember(field);
if (visibility == AccessVisibility.PRIVATE
|| visibility == AccessVisibility.PROTECTED) {
AccessControl accessControl = AccessControl.forMember(field);
if (!accessControl.isAccessibleFrom(targetClassName)) {
return CodeBlock.of("$L.resolveAndSet($L, $L)", resolver,
REGISTERED_BEAN_PARAMETER, INSTANCE_PARAMETER);
}
@@ -992,8 +995,8 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
field.getName(), resolver, REGISTERED_BEAN_PARAMETER);
}
private CodeBlock generateMethodStatementForMethod(Method method,
boolean required, RuntimeHints hints) {
private CodeBlock generateMethodStatementForMethod(ClassName targetClassName,
Method method, boolean required, RuntimeHints hints) {
CodeBlock.Builder code = CodeBlock.builder();
code.add("$T.$L", AutowiredMethodArgumentsResolver.class,
@@ -1004,9 +1007,8 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
generateParameterTypesCode(method.getParameterTypes()));
}
code.add(")");
AccessVisibility visibility = AccessVisibility.forMember(method);
if (visibility == AccessVisibility.PRIVATE
|| visibility == AccessVisibility.PROTECTED) {
AccessControl accessControl = AccessControl.forMember(method);
if (!accessControl.isAccessibleFrom(targetClassName)) {
hints.reflection().registerMethod(method, ExecutableMode.INVOKE);
code.add(".resolveAndInvoke($L, $L)", REGISTERED_BEAN_PARAMETER,
INSTANCE_PARAMETER);

View File

@@ -21,7 +21,7 @@ import java.lang.reflect.Executable;
import java.util.List;
import java.util.function.Predicate;
import org.springframework.aot.generate.AccessVisibility;
import org.springframework.aot.generate.AccessControl;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.generate.MethodReference;
import org.springframework.aot.generate.MethodReference.ArgumentCodeGenerator;
@@ -85,9 +85,9 @@ class DefaultBeanRegistrationCodeFragments implements BeanRegistrationCodeFragme
private Class<?> extractDeclaringClass(ResolvableType beanType, Executable executable) {
Class<?> declaringClass = ClassUtils.getUserClass(executable.getDeclaringClass());
if (executable instanceof Constructor<?> &&
AccessVisibility.forMember(executable) == AccessVisibility.PUBLIC &&
FactoryBean.class.isAssignableFrom(declaringClass)) {
if (executable instanceof Constructor<?>
&& AccessControl.forMember(executable).isPublic()
&& FactoryBean.class.isAssignableFrom(declaringClass)) {
return extractTargetClassFromFactoryBean(declaringClass, beanType);
}
return executable.getDeclaringClass();

View File

@@ -24,7 +24,8 @@ import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.function.Consumer;
import org.springframework.aot.generate.AccessVisibility;
import org.springframework.aot.generate.AccessControl;
import org.springframework.aot.generate.AccessControl.Visibility;
import org.springframework.aot.generate.GeneratedMethod;
import org.springframework.aot.generate.GeneratedMethods;
import org.springframework.aot.generate.GenerationContext;
@@ -111,10 +112,9 @@ class InstanceSupplierCodeGenerator {
Class<?> declaringClass = ClassUtils
.getUserClass(constructor.getDeclaringClass());
boolean dependsOnBean = ClassUtils.isInnerClass(declaringClass);
AccessVisibility accessVisibility = getAccessVisibility(registeredBean,
constructor);
if (accessVisibility == AccessVisibility.PUBLIC
|| accessVisibility == AccessVisibility.PACKAGE_PRIVATE) {
Visibility accessVisibility = getAccessVisibility(registeredBean, constructor);
if (accessVisibility == Visibility.PUBLIC
|| accessVisibility == Visibility.PACKAGE_PRIVATE) {
return generateCodeForAccessibleConstructor(beanName, beanClass, constructor,
dependsOnBean, declaringClass);
}
@@ -207,10 +207,9 @@ class InstanceSupplierCodeGenerator {
Class<?> declaringClass = ClassUtils
.getUserClass(factoryMethod.getDeclaringClass());
boolean dependsOnBean = !Modifier.isStatic(factoryMethod.getModifiers());
AccessVisibility accessVisibility = getAccessVisibility(registeredBean,
factoryMethod);
if (accessVisibility == AccessVisibility.PUBLIC
|| accessVisibility == AccessVisibility.PACKAGE_PRIVATE) {
Visibility accessVisibility = getAccessVisibility(registeredBean, factoryMethod);
if (accessVisibility == Visibility.PUBLIC
|| accessVisibility == Visibility.PACKAGE_PRIVATE) {
return generateCodeForAccessibleFactoryMethod(beanName, beanClass, factoryMethod,
declaringClass, dependsOnBean);
}
@@ -314,13 +313,13 @@ class InstanceSupplierCodeGenerator {
return code.build();
}
protected AccessVisibility getAccessVisibility(RegisteredBean registeredBean,
private Visibility getAccessVisibility(RegisteredBean registeredBean,
Member member) {
AccessVisibility beanTypeAccessVisibility = AccessVisibility
AccessControl beanTypeAccessControl = AccessControl
.forResolvableType(registeredBean.getBeanType());
AccessVisibility memberAccessVisibility = AccessVisibility.forMember(member);
return AccessVisibility.lowest(beanTypeAccessVisibility, memberAccessVisibility);
AccessControl memberAccessControl = AccessControl.forMember(member);
return AccessControl.lowest(beanTypeAccessControl, memberAccessControl).getVisibility();
}
private CodeBlock generateParameterTypesCode(Class<?>[] parameterTypes, int offset) {