Move runtime hints into another package

Original Pull Request: #2624
This commit is contained in:
Christoph Strobl
2022-06-10 09:29:38 +02:00
parent 51cda9993f
commit 4e23153816
29 changed files with 659 additions and 618 deletions

View File

@@ -25,6 +25,8 @@ import org.assertj.core.api.AbstractAssert;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.hint.ClassProxyHint;
import org.springframework.aot.hint.JdkProxyHint;
import org.springframework.aot.hint.ProxyHintsPredicates;
import org.springframework.aot.hint.RuntimeHintsPredicates;
/**
* AssertJ {@link AbstractAssert Assertion} for code contributions originating from
@@ -45,9 +47,9 @@ public class CodeContributionAssert extends AbstractAssert<CodeContributionAsser
public CodeContributionAssert contributesReflectionFor(Class<?>... types) {
for (Class<?> type : types) {
assertThat(this.actual.getRuntimeHints().reflection().getTypeHint(type))
assertThat(this.actual.getRuntimeHints())
.describedAs("No reflection entry found for [%s]", type)
.isNotNull();
.matches(RuntimeHintsPredicates.reflection().onType(type));
}
return this;
@@ -56,9 +58,9 @@ public class CodeContributionAssert extends AbstractAssert<CodeContributionAsser
public CodeContributionAssert doesNotContributeReflectionFor(Class<?>... types) {
for (Class<?> type : types) {
assertThat(this.actual.getRuntimeHints().reflection().getTypeHint(type))
assertThat(this.actual.getRuntimeHints())
.describedAs("Reflection entry found for [%s]", type)
.isNull();
.matches(RuntimeHintsPredicates.reflection().onType(type).negate());
}
return this;

View File

@@ -20,37 +20,46 @@ import static org.assertj.core.api.Assertions.*;
import java.util.Collections;
import java.util.function.Consumer;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.aot.generate.ClassNameGenerator;
import org.springframework.aot.generate.DefaultGenerationContext;
import org.springframework.aot.generate.InMemoryGeneratedFiles;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.aot.hint.RuntimeHintsPredicates;
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.data.ManagedTypes;
import org.springframework.data.domain.ManagedTypes;
/**
* @author Christoph Strobl
*/
class ManagedTypesRegistrationAotProcessorUnitTests {
class ManagedTypesBeanRegistrationAotProcessorUnitTests {
final RootBeanDefinition managedTypesDefinition = (RootBeanDefinition) BeanDefinitionBuilder
.rootBeanDefinition(ManagedTypes.class).setFactoryMethod("of")
.rootBeanDefinition(ManagedTypes.class).setFactoryMethod("fromIterable")
.addConstructorArgValue(Collections.singleton(A.class)).getBeanDefinition();
final RootBeanDefinition myManagedTypesDefinition = (RootBeanDefinition) BeanDefinitionBuilder
.rootBeanDefinition(MyManagedTypes.class).getBeanDefinition();
DefaultListableBeanFactory beanFactory;
@BeforeEach
void beforeEach() {
beanFactory = new DefaultListableBeanFactory();
}
@Test // GH-2593
void processesBeanWithMatchingModulePrefix() {
BeanRegistrationAotContribution contribution = createPostProcessor("commons", bf -> {
bf.registerBeanDefinition("commons.managed-types", managedTypesDefinition);
}).contribute(managedTypesDefinition, ManagedTypes.class, "commons.managed-types");
beanFactory.registerBeanDefinition("commons.managed-types", managedTypesDefinition);
BeanRegistrationAotContribution contribution = createPostProcessor("commons")
.processAheadOfTime(RegisteredBean.of(beanFactory, "commons.managed-types"));
assertThat(contribution).isNotNull();
}
@@ -58,26 +67,27 @@ class ManagedTypesRegistrationAotProcessorUnitTests {
@Test // GH-2593
void contributesReflectionForManagedTypes() {
BeanRegistrationAotContribution contribution = createPostProcessor("commons", bf -> {
bf.registerBeanDefinition("commons.managed-types", managedTypesDefinition);
}).contribute(managedTypesDefinition, ManagedTypes.class, "commons.managed-types");
beanFactory.registerBeanDefinition("commons.managed-types", managedTypesDefinition);
BeanRegistrationAotContribution contribution = createPostProcessor("commons")
.processAheadOfTime(RegisteredBean.of(beanFactory, "commons.managed-types"));
DefaultGenerationContext generationContext = new DefaultGenerationContext(new ClassNameGenerator(),
new InMemoryGeneratedFiles(), new RuntimeHints());
contribution.applyTo(generationContext, null);
new CodeContributionAssert(generationContext) //
.contributesReflectionFor(A.class) //
.doesNotContributeReflectionFor(B.class);
assertThat(generationContext.getRuntimeHints()).matches(RuntimeHintsPredicates.reflection().onType(A.class)
.and(RuntimeHintsPredicates.reflection().onType(B.class).negate()));
}
@Test // GH-2593
void processesMatchingSubtypeBean() {
BeanRegistrationAotContribution contribution = createPostProcessor("commons", bf -> {
bf.registerBeanDefinition("commons.managed-types", myManagedTypesDefinition);
}).contribute(myManagedTypesDefinition, MyManagedTypes.class, "commons.managed-types");
beanFactory.registerBeanDefinition("commons.managed-types", myManagedTypesDefinition);
BeanRegistrationAotContribution contribution = createPostProcessor("commons")
.processAheadOfTime(RegisteredBean.of(beanFactory, "commons.managed-types"));
assertThat(contribution).isNotNull();
}
@@ -85,9 +95,11 @@ class ManagedTypesRegistrationAotProcessorUnitTests {
@Test // GH-2593
void ignoresBeanNotMatchingRequiredType() {
BeanRegistrationAotContribution contribution = createPostProcessor("commons", bf -> {
bf.registerBeanDefinition("commons.managed-types", managedTypesDefinition);
}).contribute(managedTypesDefinition, Object.class, "commons.managed-types");
beanFactory.registerBeanDefinition("commons.managed-types",
BeanDefinitionBuilder.rootBeanDefinition(NotManagedTypes.class).getBeanDefinition());
BeanRegistrationAotContribution contribution = createPostProcessor("commons")
.processAheadOfTime(RegisteredBean.of(beanFactory, "commons.managed-types"));
assertThat(contribution).isNull();
}
@@ -95,40 +107,31 @@ class ManagedTypesRegistrationAotProcessorUnitTests {
@Test // GH-2593
void ignoresBeanNotMatchingPrefix() {
BeanRegistrationAotContribution contribution = createPostProcessor("commons", bf -> {
bf.registerBeanDefinition("commons.managed-types", managedTypesDefinition);
}).contribute(managedTypesDefinition, ManagedTypes.class, "jpa.managed-types");
beanFactory.registerBeanDefinition("jpa.managed-types", managedTypesDefinition);
BeanRegistrationAotContribution contribution = createPostProcessor("commons")
.processAheadOfTime(RegisteredBean.of(beanFactory, "jpa.managed-types"));
assertThat(contribution).isNull();
}
private ManagedTypesRegistrationAotProcessor createPostProcessor(String prefix, Consumer<DefaultListableBeanFactory> action) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
action.accept(beanFactory);
ManagedTypesRegistrationAotProcessor postProcessor = createPostProcessor(beanFactory);
postProcessor.setModulePrefix(prefix);
private ManagedTypesBeanRegistrationAotProcessor createPostProcessor(String moduleIdentifier) {
ManagedTypesBeanRegistrationAotProcessor postProcessor = new ManagedTypesBeanRegistrationAotProcessor();
postProcessor.setModuleIdentifier(moduleIdentifier);
return postProcessor;
}
private ManagedTypesRegistrationAotProcessor createPostProcessor(BeanFactory beanFactory) {
ManagedTypesRegistrationAotProcessor managedTypesRegistrationAotProcessor = new ManagedTypesRegistrationAotProcessor();
managedTypesRegistrationAotProcessor.setBeanFactory(beanFactory);
return managedTypesRegistrationAotProcessor;
}
static class A {}
static class B {}
static class MyManagedTypes implements ManagedTypes {
@Override
public void forEach(Consumer<Class<?>> action) {
// just do nothing ¯\_()_/¯
}
}
static class NotManagedTypes {}
}

View File

@@ -73,7 +73,7 @@ public class RepositoryRegistrationAotProcessorIntegrationTests {
.contributesReflectionFor(ConfigWithSimpleCrudRepository.Person.class) // repository domain type
.contributesJdkProxy(ConfigWithSimpleCrudRepository.MyRepo.class, SpringProxy.class, Advised.class,
DecoratingProxy.class) //
.doesNotContributeJdkProxy(ConfigWithSimpleCrudRepository.MyRepo.class, Repository.class,
.contributesJdkProxy(ConfigWithSimpleCrudRepository.MyRepo.class, Repository.class,
TransactionalProxy.class, Advised.class, DecoratingProxy.class)
.doesNotContributeJdkProxy(ConfigWithSimpleCrudRepository.MyRepo.class, Repository.class,
TransactionalProxy.class, Advised.class, DecoratingProxy.class, Serializable.class);

View File

@@ -15,12 +15,8 @@
*/
package org.springframework.data.aot;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.util.Collections;
import java.util.LinkedHashSet;
@@ -31,7 +27,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.data.ManagedTypes;
import org.springframework.data.domain.ManagedTypes;
/**
* @author Christoph Strobl
@@ -58,7 +54,7 @@ class SpringDataBeanFactoryInitializationAotProcessorUnitTests {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("data.managed-types");
assertThat(beanDefinition.getFactoryMethodName()).isEqualTo("of");
assertThat(beanDefinition.getFactoryMethodName()).isEqualTo("fromIterable");
assertThat(beanDefinition.hasConstructorArgumentValues()).isTrue();
assertThat(beanDefinition.getConstructorArgumentValues().getArgumentValue(0, null).getValue())
.isEqualTo(Collections.singleton(DomainType.class));

View File

@@ -18,6 +18,8 @@ package org.springframework.data.repository.config;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.lang.annotation.Annotation;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -31,6 +33,7 @@ import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.data.mapping.Person;

View File

@@ -31,7 +31,7 @@ import org.springframework.core.MethodParameter;
*
* @author Jens Schauder
*/
class ParameterUnitTests {
class KParameterUnitTests {
@Test // DATAJPA-1185
void classParameterWithSameTypeParameterAsReturnedListIsDynamicProjectionParameter() throws Exception {

View File

@@ -0,0 +1,97 @@
/*
* Copyright 2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.util;
import static org.assertj.core.api.Assertions.*;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.springframework.data.classloadersupport.HidingClassLoader;
/**
* @author Christoph Strobl
*/
class TypeScannerUnitTests {
@Test // GH-2593
void looksForTypesMatchingAnnotationFilter() {
Set<Class<?>> result = TypeScanner.typeScanner(getClass().getClassLoader()) //
.scanPackages(getClass().getPackageName()) //
.forTypesAnnotatedWith(FindMe.class) //
.collectAsSet();
assertThat(result).containsExactlyInAnyOrder(AnnotatedWithFindMe.class, AnnotatedWithMetaFindMe.class);
}
@Test // GH-2593
void looksForAllTypesIfNoFilter() {
Set<Class<?>> result = TypeScanner.typeScanner(getClass().getClassLoader()) //
.scanPackages(getClass().getPackageName()) //
.collectAsSet();
assertThat(result).contains(AnnotatedWithFindMe.class, AnnotatedWithMetaFindMe.class, WithoutAnnotations.class);
}
@Test // GH-2593
void ignoresClassesNotFound() {
TypeScanner scanner = TypeScanner.typeScanner(HidingClassLoader.hideTypes(AnnotatedWithFindMe.class)) //
.scanPackages(getClass().getPackageName()) //
.forTypesAnnotatedWith(FindMe.class);
scanner.collectAsSet(); // no exception
}
@Test // GH-2593
void raisesErrorClassesNotFoundIfConfigured() {
TypeScanner scanner = TypeScanner.typeScanner(HidingClassLoader.hideTypes(AnnotatedWithFindMe.class)) //
.scanPackages(getClass().getPackageName()) //
.forTypesAnnotatedWith(FindMe.class).onClassNotFound(ex -> {
throw new IllegalStateException(ex);
});
assertThatExceptionOfType(IllegalStateException.class).isThrownBy(() -> scanner.collectAsSet()); // no exception
}
@Retention(RetentionPolicy.RUNTIME)
@interface FindMe {
}
@FindMe
@Retention(RetentionPolicy.RUNTIME)
@interface MetaAnnotatedWithFindMe {
}
@FindMe
private static class AnnotatedWithFindMe {
}
@MetaAnnotatedWithFindMe
private static class AnnotatedWithMetaFindMe {
}
private static class WithoutAnnotations {
}
}