Polishing.

Reformat code and reorder methods according to visibility. Reduce type and method visibility where applicable.

See #2680
Original pull request: #2682.
This commit is contained in:
Mark Paluch
2022-10-04 15:45:04 +02:00
parent e7cc9a6104
commit 9c993e22f5
8 changed files with 124 additions and 100 deletions

17
pom.xml
View File

@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
@@ -11,8 +13,11 @@
<description>Core Spring concepts underpinning every Spring Data module.</description>
<url>https://spring.io/projects/spring-data</url>
<scm>
<connection>scm:git:https://github.com/spring-projects/spring-data-commons.git</connection>
<developerConnection>scm:git:git@github.com:spring-projects/spring-data-commons.git</developerConnection>
<connection>scm:git:https://github.com/spring-projects/spring-data-commons.git
</connection>
<developerConnection>
scm:git:git@github.com:spring-projects/spring-data-commons.git
</developerConnection>
<url>https://github.com/spring-projects/spring-data-commons</url>
</scm>
<issueManagement>
@@ -77,6 +82,7 @@
<artifactId>spring-webflux</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core-test</artifactId>
@@ -121,11 +127,6 @@
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core-test</artifactId>
<scope>test</scope>
</dependency>
<!-- RxJava -->

View File

@@ -48,6 +48,15 @@ public class ManagedTypesBeanRegistrationAotProcessor implements BeanRegistratio
private final Log logger = LogFactory.getLog(getClass());
private @Nullable String moduleIdentifier;
public void setModuleIdentifier(@Nullable String moduleIdentifier) {
this.moduleIdentifier = moduleIdentifier;
}
@Nullable
public String getModuleIdentifier() {
return this.moduleIdentifier;
}
@Override
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
@@ -59,18 +68,20 @@ public class ManagedTypesBeanRegistrationAotProcessor implements BeanRegistratio
return contribute(AotContext.from(beanFactory), resolveManagedTypes(registeredBean), registeredBean);
}
ManagedTypes resolveManagedTypes(RegisteredBean registeredBean) {
private ManagedTypes resolveManagedTypes(RegisteredBean registeredBean) {
RootBeanDefinition beanDefinition = registeredBean.getMergedBeanDefinition();
if (beanDefinition.hasConstructorArgumentValues()) {
ValueHolder indexedArgumentValue = beanDefinition.getConstructorArgumentValues().getIndexedArgumentValue(0, null);
Object value = indexedArgumentValue.getValue();
if (value instanceof Collection<?> values) {
if (values.stream().allMatch(it -> it instanceof Class)) {
return ManagedTypes.fromIterable((Collection<Class<?>>) values);
}
if (value instanceof Collection<?> values && values.stream().allMatch(it -> it instanceof Class)) {
return ManagedTypes.fromIterable((Collection<Class<?>>) values);
}
}
if (logger.isDebugEnabled()) {
logger.debug(
String.format("ManagedTypes BeanDefinition '%s' does serve arguments. Trying to resolve bean instance.",
@@ -93,29 +104,18 @@ public class ManagedTypesBeanRegistrationAotProcessor implements BeanRegistratio
return ManagedTypes.empty();
}
protected boolean isMatch(@Nullable Class<?> beanType, @Nullable String beanName) {
return matchesByType(beanType) && matchesPrefix(beanName);
}
protected boolean matchesByType(@Nullable Class<?> beanType) {
return beanType != null && ClassUtils.isAssignable(ManagedTypes.class, beanType);
}
protected boolean matchesPrefix(@Nullable String beanName) {
return StringUtils.startsWithIgnoreCase(beanName, getModuleIdentifier());
}
/**
* Hook to provide a customized flavor of {@link BeanRegistrationAotContribution}. By overriding this method calls to
* {@link #contributeType(ResolvableType, GenerationContext)} might no longer be issued.
*
* @param aotContext never {@literal null}.
* @param managedTypes never {@literal null}.
* @return new instance of {@link ManagedTypesBeanRegistrationAotProcessor} or {@literal null} if nothing to do.
* @return new instance of {@link BeanRegistrationAotContribution} or {@literal null} if nothing to do.
*/
@Nullable
protected BeanRegistrationAotContribution contribute(AotContext aotContext, ManagedTypes managedTypes, RegisteredBean registeredBean) {
return new ManagedTypesRegistrationAotContribution(aotContext, managedTypes, registeredBean, this::contributeType);
protected BeanRegistrationAotContribution contribute(AotContext aotContext, ManagedTypes managedTypes,
RegisteredBean registeredBean) {
return new ManagedTypesRegistrationAotContribution(managedTypes, registeredBean, this::contributeType);
}
/**
@@ -138,12 +138,15 @@ public class ManagedTypesBeanRegistrationAotProcessor implements BeanRegistratio
annotation -> TypeContributor.contribute(annotation.getType(), annotationNamespaces, generationContext));
}
public void setModuleIdentifier(@Nullable String moduleIdentifier) {
this.moduleIdentifier = moduleIdentifier;
protected boolean isMatch(@Nullable Class<?> beanType, @Nullable String beanName) {
return matchesByType(beanType) && matchesPrefix(beanName);
}
@Nullable
public String getModuleIdentifier() {
return this.moduleIdentifier;
protected boolean matchesByType(@Nullable Class<?> beanType) {
return beanType != null && ClassUtils.isAssignable(ManagedTypes.class, beanType);
}
protected boolean matchesPrefix(@Nullable String beanName) {
return StringUtils.startsWithIgnoreCase(beanName, getModuleIdentifier());
}
}

View File

@@ -50,51 +50,42 @@ import org.springframework.util.ReflectionUtils;
* {@link BeanRegistrationAotContribution#customizeBeanRegistrationCodeFragments(GenerationContext, BeanRegistrationCodeFragments)}.
* The generated code resolves potential factory methods accepting either a {@link ManagedTypes} instance, or a
* {@link List} of either {@link Class} or {@link String} (classname) values.
*
* <pre>
* <code>
*
* <pre class="code">
* public static InstanceSupplier&lt;ManagedTypes&gt; instance() {
* return (registeredBean) -> {
* var types = List.of("com.example.A", "com.example.B");
* return ManagedTypes.ofStream(types.stream().map(it -> ClassUtils.forName(it, registeredBean.getBeanFactory().getBeanClassLoader())));
* }
* }
* </code>
* </pre>
*
* @author John Blum
* @author Christoph Strobl
* @author Mark Paluch
* @see org.springframework.beans.factory.aot.BeanRegistrationAotContribution
* @since 3.0.0
* @since 3.0
*/
public class ManagedTypesRegistrationAotContribution implements RegisteredBeanAotContribution {
class ManagedTypesRegistrationAotContribution implements RegisteredBeanAotContribution {
private final AotContext aotContext;
private final ManagedTypes managedTypes;
private final Lazy<List<Class<?>>> sourceTypes;
private final BiConsumer<ResolvableType, GenerationContext> contributionAction;
private final RegisteredBean source;
public ManagedTypesRegistrationAotContribution(AotContext aotContext, @Nullable ManagedTypes managedTypes,
RegisteredBean registeredBean, BiConsumer<ResolvableType, GenerationContext> contributionAction) {
public ManagedTypesRegistrationAotContribution(ManagedTypes managedTypes, RegisteredBean registeredBean,
BiConsumer<ResolvableType, GenerationContext> contributionAction) {
this.aotContext = aotContext;
this.managedTypes = managedTypes;
this.sourceTypes = Lazy.of(managedTypes::toList);
this.contributionAction = contributionAction;
this.source = registeredBean;
}
protected AotContext getAotContext() {
return this.aotContext;
}
protected ManagedTypes getManagedTypes() {
return managedTypes == null ? ManagedTypes.empty() : managedTypes;
}
@Override
public void applyTo(GenerationContext generationContext, BeanRegistrationCode beanRegistrationCode) {
List<Class<?>> types = getManagedTypes().toList();
List<Class<?>> types = sourceTypes.get();
if (!types.isEmpty()) {
TypeCollector.inspect(types).forEach(type -> contributionAction.accept(type, generationContext));
@@ -109,7 +100,7 @@ public class ManagedTypesRegistrationAotContribution implements RegisteredBeanAo
return codeFragments;
}
ManagedTypesInstanceCodeFragment fragment = new ManagedTypesInstanceCodeFragment(getManagedTypes(), source,
ManagedTypesInstanceCodeFragment fragment = new ManagedTypesInstanceCodeFragment(sourceTypes.get(), source,
codeFragments);
return fragment.canGenerateCode() ? fragment : codeFragments;
}
@@ -119,32 +110,27 @@ public class ManagedTypesRegistrationAotContribution implements RegisteredBeanAo
return source;
}
/**
* Class used to generate the fragment of code needed to define a {@link ManagedTypes} bean from previously discovered
* managed types.
*/
static class ManagedTypesInstanceCodeFragment extends BeanRegistrationCodeFragments {
private ManagedTypes sourceTypes;
private RegisteredBean source;
private Lazy<Method> instanceMethod = Lazy.of(this::findInstanceFactory);
public static final ResolvableType LIST_TYPE = ResolvableType.forType(List.class);
public static final ResolvableType MANAGED_TYPES_TYPE = ResolvableType.forType(ManagedTypes.class);
private final List<Class<?>> sourceTypes;
private final RegisteredBean source;
private final Lazy<Method> instanceMethod = Lazy.of(this::findInstanceFactory);
protected ManagedTypesInstanceCodeFragment(ManagedTypes managedTypes, RegisteredBean source,
protected ManagedTypesInstanceCodeFragment(List<Class<?>> sourceTypes, RegisteredBean source,
BeanRegistrationCodeFragments codeFragments) {
super(codeFragments);
this.sourceTypes = managedTypes;
this.sourceTypes = sourceTypes;
this.source = source;
}
/**
* @return {@literal true} if the instance method code can be generated. {@literal false} otherwise.
*/
boolean canGenerateCode() {
if (ObjectUtils.nullSafeEquals(source.getBeanClass(), ManagedTypes.class)) {
return true;
}
return instanceMethod.getNullable() != null;
}
@Override
public CodeBlock generateInstanceSupplierCode(GenerationContext generationContext,
BeanRegistrationCode beanRegistrationCode, Executable constructorOrFactoryMethod,
@@ -156,33 +142,20 @@ public class ManagedTypesRegistrationAotContribution implements RegisteredBeanAo
return CodeBlock.of("$T.$L()", beanRegistrationCode.getClassName(), generatedMethod.getName());
}
private CodeBlock toCodeBlock(List<Class<?>> values, boolean allPublic) {
/**
* @return {@literal true} if the instance method code can be generated. {@literal false} otherwise.
*/
boolean canGenerateCode() {
if (allPublic) {
return CodeBlock.join(values.stream().map(value -> CodeBlock.of("$T.class", value)).toList(), ", ");
if (ObjectUtils.nullSafeEquals(source.getBeanClass(), ManagedTypes.class)) {
return true;
}
return CodeBlock.join(values.stream().map(value -> CodeBlock.of("$S", value.getName())).toList(), ", ");
}
private Method findInstanceFactory() {
for (Method beanMethod : ReflectionUtils.getDeclaredMethods(source.getBeanClass())) {
if (beanMethod.getParameterCount() == 1 && java.lang.reflect.Modifier.isPublic(beanMethod.getModifiers())
&& java.lang.reflect.Modifier.isStatic(beanMethod.getModifiers())) {
ResolvableType parameterType = ResolvableType.forMethodParameter(beanMethod, 0, source.getBeanClass());
if (parameterType.isAssignableFrom(ResolvableType.forType(List.class))
|| parameterType.isAssignableFrom(ResolvableType.forType(ManagedTypes.class))) {
return beanMethod;
}
}
}
return null;
return instanceMethod.getNullable() != null;
}
void generateInstanceFactory(Builder method) {
List<Class<?>> sourceTypes = this.sourceTypes.toList();
boolean allSourceTypesVisible = sourceTypes.stream()
.allMatch(it -> AccessVisibility.PUBLIC.equals(AccessVisibility.forClass(it)));
@@ -207,6 +180,7 @@ public class ManagedTypesRegistrationAotContribution implements RegisteredBeanAo
.addStatement("throw new $T($S, e)", IllegalArgumentException.class, "Cannot to load type").endControlFlow()
.endControlFlow("))").build());
}
if (ObjectUtils.nullSafeEquals(source.getBeanClass(), ManagedTypes.class)) {
builder.add("return managedTypes");
} else {
@@ -221,8 +195,42 @@ public class ManagedTypesRegistrationAotContribution implements RegisteredBeanAo
instanceFactoryMethod.getName(), "managedTypes");
}
}
builder.endControlFlow(")");
method.addCode(builder.build());
}
private CodeBlock toCodeBlock(List<Class<?>> values, boolean allPublic) {
if (allPublic) {
return CodeBlock.join(values.stream().map(value -> CodeBlock.of("$T.class", value)).toList(), ", ");
}
return CodeBlock.join(values.stream().map(value -> CodeBlock.of("$S", value.getName())).toList(), ", ");
}
@Nullable
private Method findInstanceFactory() {
for (Method beanMethod : ReflectionUtils.getDeclaredMethods(source.getBeanClass())) {
if (!isInstanceFactory(beanMethod)) {
continue;
}
ResolvableType parameterType = ResolvableType.forMethodParameter(beanMethod, 0, source.getBeanClass());
if (parameterType.isAssignableFrom(LIST_TYPE) || parameterType.isAssignableFrom(MANAGED_TYPES_TYPE)) {
return beanMethod;
}
}
return null;
}
private static boolean isInstanceFactory(Method beanMethod) {
return beanMethod.getParameterCount() == 1 //
&& java.lang.reflect.Modifier.isPublic(beanMethod.getModifiers()) //
&& java.lang.reflect.Modifier.isStatic(beanMethod.getModifiers());
}
}
}

View File

@@ -19,9 +19,16 @@ import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.support.RegisteredBean;
/**
* Extension to {@link BeanRegistrationAotContribution} that bases its contribution on a {@link RegisteredBean}. This
* interface exposes its {@link #getSource() source}.
*
* @author Christoph Strobl
* @since 3.0
*/
public interface RegisteredBeanAotContribution extends BeanRegistrationAotContribution {
/**
* @return the source {@link RegisteredBean}.
*/
RegisteredBean getSource();
}

View File

@@ -36,7 +36,7 @@ import org.springframework.util.ClassUtils;
*
* @author Christoph Strobl
* @author John Blum
* @since 3.0.0
* @since 3.0
*/
class RepositoryBeanDefinitionReader {

View File

@@ -61,7 +61,7 @@ import org.springframework.util.StringUtils;
*
* @author Christoph Strobl
* @author John Blum
* @since 3.0.0
* @since 3.0
*/
@SuppressWarnings("unused")
public class RepositoryRegistrationAotProcessor implements BeanRegistrationAotProcessor, BeanFactoryAware {

View File

@@ -31,6 +31,8 @@ import org.springframework.javapoet.MethodSpec;
import org.springframework.javapoet.ParameterizedTypeName;
/**
* Test utility to build and compile AOT code contributions.
*
* @author Christoph Strobl
*/
public class AotTestCodeContributionBuilder {

View File

@@ -21,6 +21,7 @@ import static org.mockito.Mockito.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
@@ -47,21 +48,23 @@ import org.springframework.javapoet.MethodSpec.Builder;
import org.springframework.test.util.ReflectionTestUtils;
/**
* Unit tests for {@link ManagedTypesBeanRegistrationAotProcessor}.
*
* @author Christoph Strobl
*/
class ManagedTypesBeanRegistrationAotProcessorUnitTests {
final RootBeanDefinition managedTypesDefinition = (RootBeanDefinition) BeanDefinitionBuilder
private final RootBeanDefinition managedTypesDefinition = (RootBeanDefinition) BeanDefinitionBuilder
.rootBeanDefinition(ManagedTypes.class).setFactoryMethod("fromIterable")
.addConstructorArgValue(Collections.singleton(A.class)).getBeanDefinition();
final RootBeanDefinition myManagedTypesDefinition = (RootBeanDefinition) BeanDefinitionBuilder
private final RootBeanDefinition myManagedTypesDefinition = (RootBeanDefinition) BeanDefinitionBuilder
.rootBeanDefinition(MyManagedTypes.class).getBeanDefinition();
final RootBeanDefinition invocationCountingManagedTypesDefinition = (RootBeanDefinition) BeanDefinitionBuilder
private final RootBeanDefinition invocationCountingManagedTypesDefinition = (RootBeanDefinition) BeanDefinitionBuilder
.rootBeanDefinition(InvocationRecordingManagedTypes.class).getBeanDefinition();
DefaultListableBeanFactory beanFactory;
private DefaultListableBeanFactory beanFactory;
@BeforeEach
void beforeEach() {
@@ -221,8 +224,8 @@ class ManagedTypesBeanRegistrationAotProcessorUnitTests {
beanFactory.registerBeanDefinition("managed-types", managedTypesDefinition);
RegisteredBean registeredBean = RegisteredBean.of(beanFactory, "managed-types");
ManagedTypesInstanceCodeFragment fragment = new ManagedTypesInstanceCodeFragment(
ManagedTypes.from(A.class, B.class), registeredBean, Mockito.mock(BeanRegistrationCodeFragments.class));
ManagedTypesInstanceCodeFragment fragment = new ManagedTypesInstanceCodeFragment(List.of(A.class, B.class),
registeredBean, Mockito.mock(BeanRegistrationCodeFragments.class));
Builder methodBuilder = MethodSpec.methodBuilder("instance");
fragment.generateInstanceFactory(methodBuilder);
@@ -235,8 +238,8 @@ class ManagedTypesBeanRegistrationAotProcessorUnitTests {
beanFactory.registerBeanDefinition("managed-types", myManagedTypesDefinition);
RegisteredBean registeredBean = RegisteredBean.of(beanFactory, "managed-types");
ManagedTypesInstanceCodeFragment fragment = new ManagedTypesInstanceCodeFragment(
ManagedTypes.from(A.class, B.class), registeredBean, Mockito.mock(BeanRegistrationCodeFragments.class));
ManagedTypesInstanceCodeFragment fragment = new ManagedTypesInstanceCodeFragment(List.of(A.class, B.class),
registeredBean, Mockito.mock(BeanRegistrationCodeFragments.class));
assertThat(fragment.canGenerateCode()).isFalse();
}
@@ -290,7 +293,7 @@ class ManagedTypesBeanRegistrationAotProcessorUnitTests {
public static class InvocationRecordingManagedTypes implements ManagedTypes {
private AtomicInteger counter = new AtomicInteger(0);
private final AtomicInteger counter = new AtomicInteger(0);
private ManagedTypes source = ManagedTypes.from(A.class, B.class);
public static InvocationRecordingManagedTypes from(ManagedTypes source) {