Browse Source

Polish ProtectedAccess options

This commit improves how protected access analysis operates. Rather than
providing a static boolean, a function callback for the member to
analyse is used. This permits to change the decision whether reflection
can be used, or if the return type is assigned.

Both of those are already applicable, with InjectionGenerator relying
on reflection for private fields, and DefaultBeanInstanceGenerator
assigning the bean instance if additional contributors are present.

This commit also moves the logic of computing the options where the code
is actually generated.

See gh-28030
pull/28056/head
Stephane Nicoll 4 years ago
parent
commit
5bbc7dbce2
  1. 8
      spring-beans/src/main/java/org/springframework/beans/factory/generator/DefaultBeanInstanceGenerator.java
  2. 28
      spring-beans/src/main/java/org/springframework/beans/factory/generator/InjectionGenerator.java
  3. 62
      spring-beans/src/test/java/org/springframework/beans/factory/generator/InjectionGeneratorTests.java
  4. 103
      spring-core/src/main/java/org/springframework/aot/generator/ProtectedAccess.java
  5. 136
      spring-core/src/test/java/org/springframework/aot/generator/ProtectedAccessTests.java

8
spring-beans/src/main/java/org/springframework/beans/factory/generator/DefaultBeanInstanceGenerator.java

@ -39,19 +39,21 @@ import org.springframework.util.ClassUtils; @@ -39,19 +39,21 @@ import org.springframework.util.ClassUtils;
*/
class DefaultBeanInstanceGenerator {
private static final Options BEAN_INSTANCE_OPTIONS = new Options(false, true);
private final Executable instanceCreator;
private final List<BeanInstanceContributor> contributors;
private final InjectionGenerator injectionGenerator;
private final Options beanInstanceOptions;
DefaultBeanInstanceGenerator(Executable instanceCreator, List<BeanInstanceContributor> contributors) {
this.instanceCreator = instanceCreator;
this.contributors = List.copyOf(contributors);
this.injectionGenerator = new InjectionGenerator();
this.beanInstanceOptions = Options.defaults().useReflection(member -> false)
.assignReturnType(member -> !this.contributors.isEmpty()).build();
}
/**
@ -62,7 +64,7 @@ class DefaultBeanInstanceGenerator { @@ -62,7 +64,7 @@ class DefaultBeanInstanceGenerator {
*/
public CodeContribution generateBeanInstance(RuntimeHints runtimeHints) {
DefaultCodeContribution contribution = new DefaultCodeContribution(runtimeHints);
contribution.protectedAccess().analyze(this.instanceCreator, BEAN_INSTANCE_OPTIONS);
contribution.protectedAccess().analyze(this.instanceCreator, this.beanInstanceOptions);
if (this.instanceCreator instanceof Constructor<?> constructor) {
writeBeanInstantiation(contribution, constructor);
}

28
spring-beans/src/main/java/org/springframework/beans/factory/generator/InjectionGenerator.java

@ -28,6 +28,8 @@ import java.util.Arrays; @@ -28,6 +28,8 @@ import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import org.springframework.aot.generator.ProtectedAccess;
import org.springframework.aot.generator.ProtectedAccess.Options;
import org.springframework.beans.factory.generator.config.BeanDefinitionRegistrar.BeanInstanceContext;
import org.springframework.javapoet.CodeBlock;
import org.springframework.javapoet.CodeBlock.Builder;
@ -51,6 +53,12 @@ import org.springframework.util.ReflectionUtils; @@ -51,6 +53,12 @@ import org.springframework.util.ReflectionUtils;
*/
public class InjectionGenerator {
private static final Options FIELD_INJECTION_OPTIONS = Options.defaults()
.useReflection(member -> Modifier.isPrivate(member.getModifiers())).build();
private static final Options METHOD_INJECTION_OPTIONS = Options.defaults()
.useReflection(member -> false).build();
private final BeanParameterGenerator parameterGenerator = new BeanParameterGenerator();
@ -77,7 +85,8 @@ public class InjectionGenerator { @@ -77,7 +85,8 @@ public class InjectionGenerator {
* in the specified {@link Member}.
* @param member the field or method to inject
* @param required whether the value is required
* @return a statement that injects a value to the specified membmer
* @return a statement that injects a value to the specified member
* @see #getProtectedAccessInjectionOptions(Member)
*/
public CodeBlock writeInjection(Member member, boolean required) {
if (member instanceof Method method) {
@ -89,6 +98,23 @@ public class InjectionGenerator { @@ -89,6 +98,23 @@ public class InjectionGenerator {
throw new IllegalArgumentException("Could not handle member " + member);
}
/**
* Return the {@link Options} to use if protected access analysis is
* required for the specified {@link Member}.
* @param member the field or method to handle
* @return the options to use to analyse protected access
* @see ProtectedAccess
*/
public Options getProtectedAccessInjectionOptions(Member member) {
if (member instanceof Method) {
return METHOD_INJECTION_OPTIONS;
}
if (member instanceof Field) {
return FIELD_INJECTION_OPTIONS;
}
throw new IllegalArgumentException("Could not handle member " + member);
}
private CodeBlock write(Constructor<?> creator) {
Builder code = CodeBlock.builder();
Class<?> declaringType = ClassUtils.getUserClass(creator.getDeclaringClass());

62
spring-beans/src/test/java/org/springframework/beans/factory/generator/InjectionGeneratorTests.java

@ -24,6 +24,8 @@ import java.lang.reflect.Method; @@ -24,6 +24,8 @@ import java.lang.reflect.Method;
import org.junit.jupiter.api.Test;
import org.springframework.aot.generator.ProtectedAccess;
import org.springframework.aot.generator.ProtectedAccess.Options;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.generator.InjectionGeneratorTests.SimpleConstructorBean.InnerClass;
import org.springframework.javapoet.support.CodeSnippet;
@ -40,6 +42,8 @@ import static org.mockito.Mockito.mock; @@ -40,6 +42,8 @@ import static org.mockito.Mockito.mock;
*/
class InjectionGeneratorTests {
private final ProtectedAccess protectedAccess = new ProtectedAccess();
@Test
void writeInstantiationForConstructorWithNoArgUseShortcut() {
Constructor<?> constructor = SimpleBean.class.getDeclaredConstructors()[0];
@ -162,6 +166,42 @@ class InjectionGeneratorTests { @@ -162,6 +166,42 @@ class InjectionGeneratorTests {
})""");
}
@Test
void getProtectedAccessInjectionOptionsForUnsupportedMember() {
assertThatIllegalArgumentException().isThrownBy(() ->
getProtectedAccessInjectionOptions(mock(Member.class)));
}
@Test
void getProtectedAccessInjectionOptionsForPackagePublicField() {
analyzeProtectedAccess(field(SampleBean.class, "enabled"));
assertThat(this.protectedAccess.isAccessible("com.example")).isTrue();
}
@Test
void getProtectedAccessInjectionOptionsForPackageProtectedField() {
analyzeProtectedAccess(field(SampleBean.class, "counter"));
assertPrivilegedAccess(SampleBean.class);
}
@Test
void getProtectedAccessInjectionOptionsForPrivateField() {
analyzeProtectedAccess(field(SampleBean.class, "source"));
assertThat(this.protectedAccess.isAccessible("com.example")).isTrue();
}
@Test
void getProtectedAccessInjectionOptionsForPublicMethod() {
analyzeProtectedAccess(method(SampleBean.class, "setEnabled", Boolean.class));
assertThat(this.protectedAccess.isAccessible("com.example")).isTrue();
}
@Test
void getProtectedAccessInjectionOptionsForPackageProtectedMethod() {
analyzeProtectedAccess(method(SampleBean.class, "sourceAndCounter", String.class, Integer.class));
assertPrivilegedAccess(SampleBean.class);
}
private Method method(Class<?> type, String name, Class<?>... parameterTypes) {
Method method = ReflectionUtils.findMethod(type, name, parameterTypes);
@ -183,14 +223,34 @@ class InjectionGeneratorTests { @@ -183,14 +223,34 @@ class InjectionGeneratorTests {
return CodeSnippet.process(code -> code.add(new InjectionGenerator().writeInjection(member, required)));
}
private void analyzeProtectedAccess(Member member) {
this.protectedAccess.analyze(member, getProtectedAccessInjectionOptions(member));
}
private Options getProtectedAccessInjectionOptions(Member member) {
return new InjectionGenerator().getProtectedAccessInjectionOptions(member);
}
private void assertPrivilegedAccess(Class<?> target) {
assertThat(this.protectedAccess.isAccessible("com.example")).isFalse();
assertThat(this.protectedAccess.getPrivilegedPackageName("com.example")).isEqualTo(target.getPackageName());
assertThat(this.protectedAccess.isAccessible(target.getPackageName())).isTrue();
}
@SuppressWarnings("unused")
static class SampleBean {
public static class SampleBean {
public Boolean enabled;
private String source;
Integer counter;
public void setEnabled(Boolean enabled) {
}
void sourceAndCounter(String source, Integer counter) {
}

103
spring-core/src/main/java/org/springframework/aot/generator/ProtectedAccess.java

@ -33,7 +33,7 @@ import org.springframework.lang.Nullable; @@ -33,7 +33,7 @@ import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**
* Gather the need of non-public access and determine the priviledged package
* Gather the need of non-public access and determine the privileged package
* to use, if necessary.
*
* @author Stephane Nicoll
@ -104,15 +104,6 @@ public class ProtectedAccess { @@ -104,15 +104,6 @@ public class ProtectedAccess {
}
}
/**
* Analyze accessing the specified {@link Member} using the default
* {@linkplain Options#DEFAULTS options}.
* @param member the member to analyze
*/
public void analyze(Member member) {
analyze(member, Options.DEFAULTS);
}
/**
* Analyze accessing the specified {@link Member} using the specified
* {@link Options options}.
@ -123,12 +114,12 @@ public class ProtectedAccess { @@ -123,12 +114,12 @@ public class ProtectedAccess {
if (isProtected(member.getDeclaringClass())) {
registerProtectedType(member.getDeclaringClass(), member);
}
if (!options.useReflection && isProtected(member.getModifiers())) {
if (isProtected(member.getModifiers()) && !options.useReflection.apply(member)) {
registerProtectedType(member.getDeclaringClass(), member);
}
if (member instanceof Field field) {
ResolvableType fieldType = ResolvableType.forField(field);
if (options.assignReturnType && isProtected(fieldType)) {
if (isProtected(fieldType) && options.assignReturnType.apply(field)) {
registerProtectedType(fieldType, field);
}
}
@ -138,7 +129,7 @@ public class ProtectedAccess { @@ -138,7 +129,7 @@ public class ProtectedAccess {
}
else if (member instanceof Method method) {
ResolvableType returnType = ResolvableType.forMethodReturnType(method);
if (!options.assignReturnType && isProtected(returnType)) {
if (isProtected(returnType) && options.assignReturnType.apply(method)) {
registerProtectedType(returnType, method);
}
analyzeParameterTypes(method, i -> ResolvableType.forMethodParameter(method, i));
@ -204,32 +195,82 @@ public class ProtectedAccess { @@ -204,32 +195,82 @@ public class ProtectedAccess {
* Options to use to analyze if invoking a {@link Member} requires
* privileged access.
*/
public static class Options {
public static final class Options {
/**
* Default options that does fallback to reflection and does not
* assign the default type.
*/
public static final Options DEFAULTS = new Options();
private final Function<Member, Boolean> assignReturnType;
private final Function<Member, Boolean> useReflection;
private final boolean useReflection;
private final boolean assignReturnType;
private Options(Builder builder) {
this.assignReturnType = builder.assignReturnType;
this.useReflection = builder.useReflection;
}
/**
* Create a new instance with the specified options.
* @param useReflection whether the writer can automatically use
* reflection to invoke a protected member if it is not public
* @param assignReturnType whether the writer needs to assign the
* return type, or if it is irrelevant
* Initialize a {@link Builder} with default options, that is use
* reflection if the member is private and does not assign the
* return type.
* @return an options builder
*/
public Options(boolean useReflection, boolean assignReturnType) {
this.useReflection = useReflection;
this.assignReturnType = assignReturnType;
public static Builder defaults() {
return new Builder(member -> false,
member -> Modifier.isPrivate(member.getModifiers()));
}
private Options() {
this(true, false);
public static final class Builder {
private Function<Member, Boolean> assignReturnType;
private Function<Member, Boolean> useReflection;
private Builder(Function<Member, Boolean> assignReturnType,
Function<Member, Boolean> useReflection) {
this.assignReturnType = assignReturnType;
this.useReflection = useReflection;
}
/**
* Specify if the return type is assigned so that its type can be
* analyzed if necessary.
* @param assignReturnType whether the return type is assigned
* @return {@code this}, to facilitate method chaining
*/
public Builder assignReturnType(boolean assignReturnType) {
return assignReturnType(member -> assignReturnType);
}
/**
* Specify a function that determines whether the return type is
* assigned so that its type can be analyzed.
* @param assignReturnType whether the return type is assigned
* @return {@code this}, to facilitate method chaining
*/
public Builder assignReturnType(Function<Member, Boolean> assignReturnType) {
this.assignReturnType = assignReturnType;
return this;
}
/**
* Specify a function that determines whether reflection can be
* used for a given {@link Member}.
* @param useReflection whether reflection can be used
* @return {@code this}, to facilitate method chaining
*/
public Builder useReflection(Function<Member, Boolean> useReflection) {
this.useReflection = useReflection;
return this;
}
/**
* Build an {@link Options} instance based on the state of this
* builder.
* @return a new options instance
*/
public Options build() {
return new Options(this);
}
}
}

136
spring-core/src/test/java/org/springframework/aot/generator/ProtectedAccessTests.java

@ -16,8 +16,10 @@ @@ -16,8 +16,10 @@
package org.springframework.aot.generator;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.junit.jupiter.api.Test;
@ -37,128 +39,126 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -37,128 +39,126 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
*/
class ProtectedAccessTests {
public static final Options DEFAULT_OPTIONS = Options.defaults().build();
private final ProtectedAccess protectedAccess = new ProtectedAccess();
@Test
void analyzeWithPublicConstructor() throws NoSuchMethodException {
this.protectedAccess.analyze(PublicClass.class.getConstructor());
this.protectedAccess.analyze(PublicClass.class.getConstructor(), DEFAULT_OPTIONS);
assertThat(this.protectedAccess.isAccessible("com.example")).isTrue();
}
@Test
void analyzeWithPackagePrivateConstructorAndDefaultOptions() {
this.protectedAccess.analyze(ProtectedAccessor.class.getDeclaredConstructors()[0]);
assertThat(this.protectedAccess.isAccessible("com.example")).isTrue();
assertThat(this.protectedAccess.getPrivilegedPackageName("com.example")).isNull();
void analyzeWithPackagePrivateConstructor() {
this.protectedAccess.analyze(ProtectedAccessor.class.getDeclaredConstructors()[0],
DEFAULT_OPTIONS);
assertPrivilegedAccess(ProtectedAccessor.class);
}
@Test
void analyzeWithPackagePrivateConstructorAndReflectionDisabled() {
this.protectedAccess.analyze(ProtectedAccessor.class.getDeclaredConstructors()[0],
new Options(false, true));
assertThat(this.protectedAccess.isAccessible("com.example")).isFalse();
assertThat(this.protectedAccess.getPrivilegedPackageName("com.example"))
.isEqualTo(ProtectedAccessor.class.getPackageName());
assertThat(this.protectedAccess.isAccessible(ProtectedAccessor.class.getPackageName())).isTrue();
void analyzeWithPackagePrivateConstructorAndReflectionEnabled() {
Constructor<?> constructor = ProtectedAccessor.class.getDeclaredConstructors()[0];
this.protectedAccess.analyze(constructor,
Options.defaults().useReflection(member -> member.equals(constructor)).build());
assertThat(this.protectedAccess.isAccessible("com.example")).isTrue();
}
@Test
void analyzeWithPackagePrivateClass() {
this.protectedAccess.analyze(ProtectedClass.class.getDeclaredConstructors()[0]);
assertThat(this.protectedAccess.isAccessible("com.example")).isFalse();
assertThat(this.protectedAccess.getPrivilegedPackageName("com.example"))
.isEqualTo(ProtectedClass.class.getPackageName());
assertThat(this.protectedAccess.isAccessible(ProtectedClass.class.getPackageName())).isTrue();
this.protectedAccess.analyze(ProtectedClass.class.getDeclaredConstructors()[0], DEFAULT_OPTIONS);
assertPrivilegedAccess(ProtectedClass.class);
}
@Test
void analyzeWithPackagePrivateDeclaringType() {
this.protectedAccess.analyze(method(ProtectedClass.class, "stringBean"));
assertThat(this.protectedAccess.isAccessible("com.example")).isFalse();
assertThat(this.protectedAccess.getPrivilegedPackageName("com.example"))
.isEqualTo(ProtectedClass.class.getPackageName());
assertThat(this.protectedAccess.isAccessible(ProtectedClass.class.getPackageName())).isTrue();
this.protectedAccess.analyze(method(ProtectedClass.class, "stringBean"), DEFAULT_OPTIONS);
assertPrivilegedAccess(ProtectedClass.class);
}
@Test
void analyzeWithPackagePrivateConstructorParameter() {
this.protectedAccess.analyze(ProtectedParameter.class.getConstructors()[0]);
assertThat(this.protectedAccess.isAccessible("com.example")).isFalse();
assertThat(this.protectedAccess.getPrivilegedPackageName("com.example"))
.isEqualTo(ProtectedParameter.class.getPackageName());
assertThat(this.protectedAccess.isAccessible(ProtectedParameter.class.getPackageName())).isTrue();
this.protectedAccess.analyze(ProtectedParameter.class.getConstructors()[0], DEFAULT_OPTIONS);
assertPrivilegedAccess(ProtectedParameter.class);
}
@Test
void analyzeWithPackagePrivateMethod() {
this.protectedAccess.analyze(method(PublicClass.class, "getProtectedMethod"));
assertThat(this.protectedAccess.isAccessible("com.example")).isTrue();
this.protectedAccess.analyze(method(PublicClass.class, "getProtectedMethod"), DEFAULT_OPTIONS);
assertPrivilegedAccess(PublicClass.class);
}
@Test
void analyzeWithPackagePrivateMethodAndReflectionDisabled() {
void analyzeWithPackagePrivateMethodAndReflectionEnabled() {
this.protectedAccess.analyze(method(PublicClass.class, "getProtectedMethod"),
new Options(false, false));
assertThat(this.protectedAccess.isAccessible("com.example")).isFalse();
Options.defaults().useReflection(member -> !Modifier.isPublic(member.getModifiers())).build());
assertThat(this.protectedAccess.isAccessible("com.example")).isTrue();
}
@Test
void analyzeWithPackagePrivateMethodReturnType() {
this.protectedAccess.analyze(method(ProtectedAccessor.class, "methodWithProtectedReturnType"));
assertThat(this.protectedAccess.isAccessible("com.example")).isFalse();
assertThat(this.protectedAccess.getPrivilegedPackageName("com.example"))
.isEqualTo(ProtectedAccessor.class.getPackageName());
assertThat(this.protectedAccess.isAccessible(ProtectedAccessor.class.getPackageName())).isTrue();
this.protectedAccess.analyze(method(ProtectedAccessor.class, "methodWithProtectedReturnType"), DEFAULT_OPTIONS);
assertThat(this.protectedAccess.isAccessible("com.example")).isTrue();
}
@Test
void analyzeWithPackagePrivateMethodReturnTypeAndAssignReturnTypeFunction() {
this.protectedAccess.analyze(method(ProtectedAccessor.class, "methodWithProtectedReturnType"),
Options.defaults().assignReturnType(member -> false).build());
assertThat(this.protectedAccess.isAccessible("com.example")).isTrue();
}
@Test
void analyzeWithPackagePrivateMethodReturnTypeAndAssignReturnType() {
this.protectedAccess.analyze(method(ProtectedAccessor.class, "methodWithProtectedReturnType"),
Options.defaults().assignReturnType(true).build());
assertPrivilegedAccess(ProtectedAccessor.class);
}
@Test
void analyzeWithPackagePrivateMethodParameter() {
this.protectedAccess.analyze(method(ProtectedAccessor.class, "methodWithProtectedParameter",
ProtectedClass.class));
assertThat(this.protectedAccess.isAccessible("com.example")).isFalse();
assertThat(this.protectedAccess.getPrivilegedPackageName("com.example"))
.isEqualTo(ProtectedClass.class.getPackageName());
assertThat(this.protectedAccess.isAccessible(ProtectedClass.class.getPackageName())).isTrue();
ProtectedClass.class), DEFAULT_OPTIONS);
assertPrivilegedAccess(ProtectedAccessor.class);
}
@Test
void analyzeWithPackagePrivateField() {
this.protectedAccess.analyze(field(PublicClass.class, "protectedField"));
assertThat(this.protectedAccess.isAccessible("com.example")).isTrue();
this.protectedAccess.analyze(field(PublicClass.class, "protectedField"), DEFAULT_OPTIONS);
assertPrivilegedAccess(PublicClass.class);
}
@Test
void analyzeWithPackagePrivateFieldAndReflectionDisabled() {
void analyzeWithPackagePrivateFieldAndReflectionEnabled() {
this.protectedAccess.analyze(field(PublicClass.class, "protectedField"),
new Options(false, true));
assertThat(this.protectedAccess.isAccessible("com.example")).isFalse();
assertThat(this.protectedAccess.getPrivilegedPackageName("com.example"))
.isEqualTo(PublicClass.class.getPackageName());
assertThat(this.protectedAccess.isAccessible(PublicClass.class.getPackageName())).isTrue();
Options.defaults().useReflection(member -> true).build());
assertThat(this.protectedAccess.isAccessible("com.example")).isTrue();
}
@Test
void analyzeWithPublicFieldAndProtectedType() {
this.protectedAccess.analyze(field(PublicClass.class, "protectedClassField"), DEFAULT_OPTIONS);
assertThat(this.protectedAccess.isAccessible("com.example")).isTrue();
}
@Test
void analyzeWithPublicFieldAndProtectedTypeAssigned() {
this.protectedAccess.analyze(field(PublicClass.class, "protectedClassField"),
new Options(false, true));
assertThat(this.protectedAccess.isAccessible("com.example")).isFalse();
assertThat(this.protectedAccess.getPrivilegedPackageName("com.example"))
.isEqualTo(ProtectedClass.class.getPackageName());
assertThat(this.protectedAccess.isAccessible(ProtectedClass.class.getPackageName())).isTrue();
Options.defaults().assignReturnType(true).build());
assertPrivilegedAccess(ProtectedClass.class);
}
@Test
void analyzeWithPackagePrivateGenericArgument() {
this.protectedAccess.analyze(method(PublicFactoryBean.class, "protectedTypeFactoryBean"));
assertThat(this.protectedAccess.isAccessible("com.example")).isFalse();
assertThat(this.protectedAccess.isAccessible(PublicFactoryBean.class.getPackageName())).isTrue();
this.protectedAccess.analyze(method(PublicFactoryBean.class, "protectedTypeFactoryBean"),
Options.defaults().assignReturnType(true).build());
assertPrivilegedAccess(PublicFactoryBean.class);
}
@Test
void analyzeTypeWithProtectedGenericArgument() {
this.protectedAccess.analyze(PublicFactoryBean.resolveToProtectedGenericParameter());
assertThat(this.protectedAccess.isAccessible("com.example")).isFalse();
assertThat(this.protectedAccess.isAccessible(PublicFactoryBean.class.getPackageName())).isTrue();
assertPrivilegedAccess(PublicFactoryBean.class);
}
@Test
@ -169,13 +169,14 @@ class ProtectedAccessTests { @@ -169,13 +169,14 @@ class ProtectedAccessTests {
@Test
void getProtectedPackageWithPublicAccess() throws NoSuchMethodException {
this.protectedAccess.analyze(PublicClass.class.getConstructor());
this.protectedAccess.analyze(PublicClass.class.getConstructor(), DEFAULT_OPTIONS);
assertThat(this.protectedAccess.getPrivilegedPackageName("com.example")).isNull();
}
@Test
void getProtectedPackageWithProtectedAccessInOnePackage() {
this.protectedAccess.analyze(method(PublicFactoryBean.class, "protectedTypeFactoryBean"));
this.protectedAccess.analyze(method(PublicFactoryBean.class, "protectedTypeFactoryBean"),
Options.defaults().assignReturnType(true).build());
assertThat(this.protectedAccess.getPrivilegedPackageName("com.example"))
.isEqualTo(PublicFactoryBean.class.getPackageName());
}
@ -185,14 +186,21 @@ class ProtectedAccessTests { @@ -185,14 +186,21 @@ class ProtectedAccessTests {
Method protectedMethodFirstPackage = method(PublicFactoryBean.class, "protectedTypeFactoryBean");
Method protectedMethodSecondPackage = method(ProtectedAccessor.class, "methodWithProtectedParameter",
ProtectedClass.class);
this.protectedAccess.analyze(protectedMethodFirstPackage);
this.protectedAccess.analyze(protectedMethodSecondPackage);
this.protectedAccess.analyze(protectedMethodFirstPackage,
Options.defaults().assignReturnType(true).build());
this.protectedAccess.analyze(protectedMethodSecondPackage, DEFAULT_OPTIONS);
assertThatThrownBy(() -> this.protectedAccess.getPrivilegedPackageName("com.example"))
.isInstanceOfSatisfying(ProtectedAccessException.class, ex ->
assertThat(ex.getProtectedElements().stream().map(ProtectedElement::getMember))
.containsOnly(protectedMethodFirstPackage, protectedMethodSecondPackage));
}
private void assertPrivilegedAccess(Class<?> target) {
assertThat(this.protectedAccess.isAccessible("com.example")).isFalse();
assertThat(this.protectedAccess.getPrivilegedPackageName("com.example")).isEqualTo(target.getPackageName());
assertThat(this.protectedAccess.isAccessible(target.getPackageName())).isTrue();
}
private static Method method(Class<?> type, String name, Class<?>... parameterTypes) {
Method method = ReflectionUtils.findMethod(type, name, parameterTypes);
assertThat(method).isNotNull();

Loading…
Cancel
Save