Fix AOT code generation for managed types.

Closes #2704
Original pull request: #2705.
This commit is contained in:
Christoph Strobl
2022-10-10 09:22:41 +02:00
committed by Mark Paluch
parent b55f098b43
commit 1fde452ab9
2 changed files with 51 additions and 1 deletions

View File

@@ -17,6 +17,7 @@ package org.springframework.data.aot;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.function.BiConsumer;
@@ -34,9 +35,12 @@ import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.core.ResolvableType;
import org.springframework.data.domain.ManagedTypes;
import org.springframework.data.util.Lazy;
import org.springframework.javapoet.ClassName;
import org.springframework.javapoet.CodeBlock;
import org.springframework.javapoet.MethodSpec.Builder;
import org.springframework.javapoet.ParameterizedTypeName;
import org.springframework.javapoet.TypeName;
import org.springframework.javapoet.WildcardTypeName;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -167,7 +171,15 @@ class ManagedTypesRegistrationAotContribution implements RegisteredBeanAotContri
CodeBlock.Builder builder = CodeBlock.builder().add("return ").beginControlFlow("(registeredBean -> ");
builder.addStatement("var types = $T.of($L)", List.class, toCodeBlock(sourceTypes, allSourceTypesVisible));
if(sourceTypes.isEmpty()) {
TypeName wildcard = WildcardTypeName.subtypeOf(Object.class);
TypeName classOfAny = ParameterizedTypeName.get(ClassName.get(Class.class), wildcard);
builder.addStatement("var types = $T.<$T>emptyList()", Collections.class, classOfAny);
} else {
builder.addStatement("var types = $T.of($L)", List.class, toCodeBlock(sourceTypes, allSourceTypesVisible));
}
if (allSourceTypesVisible) {
builder.addStatement("var managedTypes = $T.fromIterable($L)", ManagedTypes.class, "types");

View File

@@ -195,6 +195,28 @@ class ManagedTypesBeanRegistrationAotProcessorUnitTests {
});
}
@Test // GH-2680
void generatesInstanceSupplierCodeFragmentToAvoidDuplicateInvocationsForEmptyManagedTypes() {
beanFactory.registerBeanDefinition("commons.managed-types", BeanDefinitionBuilder.rootBeanDefinition(EmptyManagedTypes.class).getBeanDefinition());
RegisteredBean registeredBean = RegisteredBean.of(beanFactory, "commons.managed-types");
BeanRegistrationAotContribution contribution = createPostProcessor("commons")
.processAheadOfTime(RegisteredBean.of(beanFactory, "commons.managed-types"));
AotTestCodeContributionBuilder.withContextFor(this.getClass()).writeContentFor(contribution).compile(it -> {
InstanceSupplier<ManagedTypes> types = ReflectionTestUtils
.invokeMethod(it.getAllCompiledClasses().iterator().next(), "instance");
try {
assertThat(types.get(registeredBean).toList()).isEmpty();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
@Test // GH-2680
void generatesInstanceSupplierCodeFragmentForTypeWithCustomFactoryMethod() {
@@ -269,6 +291,22 @@ class ManagedTypesBeanRegistrationAotProcessorUnitTests {
}
}
public static class EmptyManagedTypes implements ManagedTypes {
public EmptyManagedTypes() {
}
public static EmptyManagedTypes of(ManagedTypes source) {
return new EmptyManagedTypes();
}
@Override
public void forEach(Consumer<Class<?>> action) {
}
}
public static class StoreManagedTypesWithCustomFactoryMethod implements ManagedTypes {
private ManagedTypes source;