Revert "Fix nested type discovery in ConfigurationPropertiesReflectionHintsProcessor"

This reverts commit 785588826e.
pull/31828/head
Moritz Halbritter 2 years ago
parent 1aadc2abc9
commit a4e84c26f0

@ -21,6 +21,7 @@ import java.beans.IntrospectionException;
import java.beans.Introspector; import java.beans.Introspector;
import java.beans.PropertyDescriptor; import java.beans.PropertyDescriptor;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -34,10 +35,12 @@ import org.springframework.beans.BeanInfoFactory;
import org.springframework.beans.ExtendedBeanInfoFactory; import org.springframework.beans.ExtendedBeanInfoFactory;
import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.util.ReflectionUtils;
/** /**
* Registers a given type on {@link ReflectionHints} for binding purposes, discovering any * Registers a given type on {@link ReflectionHints} for binding purposes, discovering any
* referenced types it may expose via a property. * nested type it may expose via a property.
* *
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Moritz Halbritter * @author Moritz Halbritter
@ -74,22 +77,12 @@ public final class ConfigurationPropertiesReflectionHintsProcessor {
.process(reflectionHints); .process(reflectionHints);
} }
private void processType(Class<?> type, ReflectionHints reflectionHints) { private void processNestedType(Class<?> type, ReflectionHints reflectionHints) {
if (isTypeIgnored(type)) { processNestedType(type, getBindConstructor(type, true), reflectionHints);
return;
}
new ConfigurationPropertiesReflectionHintsProcessor(type, getBindConstructor(type, true), this.seen)
.process(reflectionHints);
} }
private boolean isTypeIgnored(Class<?> type) { private void processNestedType(Class<?> type, Constructor<?> bindConstructor, ReflectionHints reflectionHints) {
if (type.getPackageName().startsWith("java.")) { new ConfigurationPropertiesReflectionHintsProcessor(type, bindConstructor, this.seen).process(reflectionHints);
return true;
}
if (type.isInterface()) {
return true;
}
return false;
} }
private static Constructor<?> getBindConstructor(Class<?> type, boolean nestedType) { private static Constructor<?> getBindConstructor(Class<?> type, boolean nestedType) {
@ -125,8 +118,9 @@ public final class ConfigurationPropertiesReflectionHintsProcessor {
private void handleValueObjectProperties(ReflectionHints reflectionHints) { private void handleValueObjectProperties(ReflectionHints reflectionHints) {
for (int i = 0; i < this.bindConstructor.getParameterCount(); i++) { for (int i = 0; i < this.bindConstructor.getParameterCount(); i++) {
String propertyName = this.bindConstructor.getParameters()[i].getName();
ResolvableType propertyType = ResolvableType.forConstructorParameter(this.bindConstructor, i); ResolvableType propertyType = ResolvableType.forConstructorParameter(this.bindConstructor, i);
registerType(reflectionHints, propertyType); handleProperty(reflectionHints, propertyName, propertyType);
} }
} }
@ -135,12 +129,16 @@ public final class ConfigurationPropertiesReflectionHintsProcessor {
Method readMethod = propertyDescriptor.getReadMethod(); Method readMethod = propertyDescriptor.getReadMethod();
if (readMethod != null) { if (readMethod != null) {
ResolvableType propertyType = ResolvableType.forMethodReturnType(readMethod, this.type); ResolvableType propertyType = ResolvableType.forMethodReturnType(readMethod, this.type);
registerType(reflectionHints, propertyType); String propertyName = propertyDescriptor.getName();
if (isSetterMandatory(propertyName, propertyType) && propertyDescriptor.getWriteMethod() == null) {
continue;
}
handleProperty(reflectionHints, propertyName, propertyType);
} }
} }
} }
private void registerType(ReflectionHints reflectionHints, ResolvableType propertyType) { private void handleProperty(ReflectionHints reflectionHints, String propertyName, ResolvableType propertyType) {
Class<?> propertyClass = propertyType.resolve(); Class<?> propertyClass = propertyType.resolve();
if (propertyClass == null) { if (propertyClass == null) {
return; return;
@ -150,13 +148,27 @@ public final class ConfigurationPropertiesReflectionHintsProcessor {
} }
Class<?> componentType = getComponentType(propertyType); Class<?> componentType = getComponentType(propertyType);
if (componentType != null) { if (componentType != null) {
processType(componentType, reflectionHints); // Can be a list of simple types
if (!isJavaType(componentType)) {
processNestedType(componentType, reflectionHints);
} }
else { }
processType(propertyClass, reflectionHints); else if (isNestedType(propertyName, propertyClass)) {
processNestedType(propertyClass, reflectionHints);
} }
} }
private boolean isSetterMandatory(String propertyName, ResolvableType propertyType) {
Class<?> propertyClass = propertyType.resolve();
if (propertyClass == null) {
return true;
}
if (getComponentType(propertyType) != null) {
return false;
}
return !isNestedType(propertyName, propertyClass);
}
private Class<?> getComponentType(ResolvableType propertyType) { private Class<?> getComponentType(ResolvableType propertyType) {
Class<?> propertyClass = propertyType.toClass(); Class<?> propertyClass = propertyType.toClass();
if (propertyType.isArray()) { if (propertyType.isArray()) {
@ -171,6 +183,27 @@ public final class ConfigurationPropertiesReflectionHintsProcessor {
return null; return null;
} }
/**
* Specify whether the specified property refer to a nested type. A nested type
* represents a sub-namespace that need to be fully resolved.
* @param propertyName the name of the property
* @param propertyType the type of the property
* @return whether the specified {@code propertyType} is a nested type
*/
private boolean isNestedType(String propertyName, Class<?> propertyType) {
if (this.type.equals(propertyType.getDeclaringClass())) {
return true;
}
else {
Field field = ReflectionUtils.findField(this.type, propertyName);
return field != null && MergedAnnotations.from(field).isPresent(NestedConfigurationProperty.class);
}
}
private boolean isJavaType(Class<?> candidate) {
return candidate.getPackageName().startsWith("java.");
}
private static BeanInfo getBeanInfo(Class<?> beanType) { private static BeanInfo getBeanInfo(Class<?> beanType) {
try { try {
BeanInfo beanInfo = beanInfoFactory.getBeanInfo(beanType); BeanInfo beanInfo = beanInfoFactory.getBeanInfo(beanType);

@ -18,7 +18,9 @@ package org.springframework.boot.context.properties;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -39,6 +41,10 @@ import org.springframework.beans.factory.aot.BeanFactoryInitializationCode;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -82,6 +88,65 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests {
(hint) -> assertThat(hint.getMemberCategories()).contains(MemberCategory.INVOKE_DECLARED_METHODS)); (hint) -> assertThat(hint.getMemberCategories()).contains(MemberCategory.INVOKE_DECLARED_METHODS));
} }
@Test
void processJavaBeanConfigurationProperties() {
RuntimeHints runtimeHints = process(SampleProperties.class);
assertThat(runtimeHints.reflection().getTypeHint(SampleProperties.class))
.satisfies(javaBeanBinding(SampleProperties.class));
}
@Test
void processJavaBeanConfigurationPropertiesWithSeveralConstructors() throws NoSuchMethodException {
RuntimeHints runtimeHints = process(SamplePropertiesWithSeveralConstructors.class);
assertThat(runtimeHints.reflection().getTypeHint(SamplePropertiesWithSeveralConstructors.class))
.satisfies(javaBeanBinding(SamplePropertiesWithSeveralConstructors.class,
SamplePropertiesWithSeveralConstructors.class.getDeclaredConstructor()));
}
@Test
void processJavaBeanConfigurationPropertiesWithMapOfPojo() {
RuntimeHints runtimeHints = process(SamplePropertiesWithMap.class);
List<TypeHint> typeHints = runtimeHints.reflection().typeHints().toList();
assertThat(typeHints).anySatisfy(javaBeanBinding(SamplePropertiesWithMap.class));
assertThat(typeHints).anySatisfy(javaBeanBinding(Address.class));
assertThat(typeHints).hasSize(3);
}
@Test
void processJavaBeanConfigurationPropertiesWithListOfPojo() {
RuntimeHints runtimeHints = process(SamplePropertiesWithList.class);
List<TypeHint> typeHints = runtimeHints.reflection().typeHints().toList();
assertThat(typeHints).anySatisfy(javaBeanBinding(SamplePropertiesWithList.class));
assertThat(typeHints).anySatisfy(javaBeanBinding(Address.class));
assertThat(typeHints).hasSize(3);
}
@Test
void processJavaBeanConfigurationPropertiesWitArrayOfPojo() {
RuntimeHints runtimeHints = process(SamplePropertiesWithArray.class);
List<TypeHint> typeHints = runtimeHints.reflection().typeHints().toList();
assertThat(typeHints).anySatisfy(javaBeanBinding(SamplePropertiesWithArray.class));
assertThat(typeHints).anySatisfy(javaBeanBinding(Address.class));
assertThat(typeHints).hasSize(3);
}
@Test
void processJavaBeanConfigurationPropertiesWithListOfJavaType() {
RuntimeHints runtimeHints = process(SamplePropertiesWithSimpleList.class);
List<TypeHint> typeHints = runtimeHints.reflection().typeHints().toList();
assertThat(typeHints).anySatisfy(javaBeanBinding(SamplePropertiesWithSimpleList.class));
assertThat(typeHints).hasSize(2);
}
@Test
void processValueObjectConfigurationProperties() {
RuntimeHints runtimeHints = process(SampleImmutableProperties.class);
List<TypeHint> typeHints = runtimeHints.reflection().typeHints().toList();
assertThat(typeHints).anySatisfy(valueObjectBinding(SampleImmutableProperties.class,
SampleImmutableProperties.class.getDeclaredConstructors()[0]));
assertThat(typeHints).hasSize(2);
}
@Test @Test
void processValueObjectConfigurationPropertiesWithSpecificConstructor() throws NoSuchMethodException { void processValueObjectConfigurationPropertiesWithSpecificConstructor() throws NoSuchMethodException {
RuntimeHints runtimeHints = process(SampleImmutablePropertiesWithSeveralConstructors.class); RuntimeHints runtimeHints = process(SampleImmutablePropertiesWithSeveralConstructors.class);
@ -91,6 +156,17 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests {
assertThat(typeHints).hasSize(2); assertThat(typeHints).hasSize(2);
} }
@Test
void processValueObjectConfigurationPropertiesWithSeveralLayersOfPojo() {
RuntimeHints runtimeHints = process(SampleImmutablePropertiesWithList.class);
List<TypeHint> typeHints = runtimeHints.reflection().typeHints().toList();
assertThat(typeHints).anySatisfy(valueObjectBinding(SampleImmutablePropertiesWithList.class,
SampleImmutablePropertiesWithList.class.getDeclaredConstructors()[0]));
assertThat(typeHints).anySatisfy(valueObjectBinding(Person.class, Person.class.getDeclaredConstructors()[0]));
assertThat(typeHints).anySatisfy(valueObjectBinding(Address.class, Address.class.getDeclaredConstructors()[0]));
assertThat(typeHints).hasSize(4);
}
@Test @Test
void processConfigurationPropertiesWithNestedTypeNotUsedIsIgnored() { void processConfigurationPropertiesWithNestedTypeNotUsedIsIgnored() {
RuntimeHints runtimeHints = process(SamplePropertiesWithNested.class); RuntimeHints runtimeHints = process(SamplePropertiesWithNested.class);
@ -98,6 +174,23 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests {
.satisfies(javaBeanBinding(SamplePropertiesWithNested.class)); .satisfies(javaBeanBinding(SamplePropertiesWithNested.class));
} }
@Test
void processConfigurationPropertiesWithNestedExternalType() {
RuntimeHints runtimeHints = process(SamplePropertiesWithExternalNested.class);
assertThat(runtimeHints.reflection().typeHints())
.anySatisfy(javaBeanBinding(SamplePropertiesWithExternalNested.class))
.anySatisfy(javaBeanBinding(SampleType.class)).anySatisfy(javaBeanBinding(SampleType.Nested.class))
.hasSize(4);
}
@Test
void processConfigurationPropertiesWithRecursiveType() {
RuntimeHints runtimeHints = process(SamplePropertiesWithRecursive.class);
assertThat(runtimeHints.reflection().typeHints())
.anySatisfy(javaBeanBinding(SamplePropertiesWithRecursive.class))
.anySatisfy(javaBeanBinding(Recursive.class)).hasSize(3);
}
@Test @Test
void processValueObjectConfigurationPropertiesWithRecursiveType() { void processValueObjectConfigurationPropertiesWithRecursiveType() {
RuntimeHints runtimeHints = process(SampleImmutablePropertiesWithRecursive.class); RuntimeHints runtimeHints = process(SampleImmutablePropertiesWithRecursive.class);
@ -109,6 +202,15 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests {
.hasSize(3); .hasSize(3);
} }
@Test
void processConfigurationPropertiesWithWellKnownTypes() {
RuntimeHints runtimeHints = process(SamplePropertiesWithWellKnownTypes.class);
assertThat(runtimeHints.reflection().typeHints())
.anySatisfy(javaBeanBinding(SamplePropertiesWithWellKnownTypes.class))
// TODO
.hasSize(2);
}
@Test @Test
void processConfigurationPropertiesWithCrossReference() { void processConfigurationPropertiesWithCrossReference() {
RuntimeHints runtimeHints = process(SamplePropertiesWithCrossReference.class); RuntimeHints runtimeHints = process(SamplePropertiesWithCrossReference.class);
@ -177,6 +279,65 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests {
} }
@ConfigurationProperties("test")
public static class SamplePropertiesWithSeveralConstructors {
SamplePropertiesWithSeveralConstructors() {
}
SamplePropertiesWithSeveralConstructors(String ignored) {
}
}
@ConfigurationProperties("test")
public static class SamplePropertiesWithMap {
public Map<String, Address> getAddresses() {
return Collections.emptyMap();
}
}
@ConfigurationProperties("test")
public static class SamplePropertiesWithList {
public List<Address> getAllAddresses() {
return Collections.emptyList();
}
}
@ConfigurationProperties("test")
public static class SamplePropertiesWithSimpleList {
public List<String> getNames() {
return Collections.emptyList();
}
}
@ConfigurationProperties("test")
public static class SamplePropertiesWithArray {
public Address[] getAllAddresses() {
return new Address[0];
}
}
@ConfigurationProperties
public static class SampleImmutableProperties {
@SuppressWarnings("unused")
private final String name;
SampleImmutableProperties(String name) {
this.name = name;
}
}
@ConfigurationProperties @ConfigurationProperties
public static class SampleImmutablePropertiesWithSeveralConstructors { public static class SampleImmutablePropertiesWithSeveralConstructors {
@ -194,6 +355,18 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests {
} }
@ConfigurationProperties
public static class SampleImmutablePropertiesWithList {
@SuppressWarnings("unused")
private final List<Person> family;
SampleImmutablePropertiesWithList(List<Person> family) {
this.family = family;
}
}
@ConfigurationProperties("nested") @ConfigurationProperties("nested")
public static class SamplePropertiesWithNested { public static class SamplePropertiesWithNested {
@ -203,6 +376,48 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests {
} }
@ConfigurationProperties("nested")
public static class SamplePropertiesWithExternalNested {
private String name;
@NestedConfigurationProperty
private SampleType sampleType;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public SampleType getSampleType() {
return this.sampleType;
}
public void setSampleType(SampleType sampleType) {
this.sampleType = sampleType;
}
}
@ConfigurationProperties("recursive")
public static class SamplePropertiesWithRecursive {
@NestedConfigurationProperty
private Recursive recursive;
public Recursive getRecursive() {
return this.recursive;
}
public void setRecursive(Recursive recursive) {
this.recursive = recursive;
}
}
@ConfigurationProperties @ConfigurationProperties
public static class SampleImmutablePropertiesWithRecursive { public static class SampleImmutablePropertiesWithRecursive {
@ -215,6 +430,84 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests {
} }
@ConfigurationProperties("wellKnownTypes")
public static class SamplePropertiesWithWellKnownTypes implements ApplicationContextAware, EnvironmentAware {
private ApplicationContext applicationContext;
private Environment environment;
public ApplicationContext getApplicationContext() {
return this.applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public Environment getEnvironment() {
return this.environment;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}
public static class SampleType {
private final Nested nested = new Nested();
public Nested getNested() {
return this.nested;
}
static class Nested {
}
}
public static class Address {
}
public static class Person {
@SuppressWarnings("unused")
private final String firstName;
@SuppressWarnings("unused")
private final String lastName;
@NestedConfigurationProperty
private final Address address;
Person(String firstName, String lastName, Address address) {
this.firstName = firstName;
this.lastName = lastName;
this.address = address;
}
}
public static class Recursive {
private Recursive recursive;
public Recursive getRecursive() {
return this.recursive;
}
public void setRecursive(Recursive recursive) {
this.recursive = recursive;
}
}
public static class ImmutableRecursive { public static class ImmutableRecursive {
@SuppressWarnings("unused") @SuppressWarnings("unused")

@ -1,437 +0,0 @@
/*
* Copyright 2012-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.boot.context.properties;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.util.ReflectionUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
/**
* Tests for {@link ConfigurationPropertiesReflectionHintsProcessor}.
*
* @author Moritz Halbritter
*/
class ConfigurationPropertiesReflectionHintsProcessorTests {
@Test
void shouldRegisterNoArgConstructor() throws NoSuchMethodException {
RuntimeHints hints = runProcessor(NoArgsCtorProperties.class);
assertThat(RuntimeHintsPredicates.reflection()
.onConstructor(ReflectionUtils.accessibleConstructor(NoArgsCtorProperties.class))).accepts(hints);
}
@Test
void shouldRegisterMemberCategories() {
RuntimeHints hints = runProcessor(NoArgsCtorProperties.class);
hasReflectionHintsForType(hints, NoArgsCtorProperties.class);
}
@Test
void shouldNotRegisterJavaTypes() {
RuntimeHints hints = runProcessor(NoArgsCtorProperties.class);
assertThat(RuntimeHintsPredicates.reflection().onType(String.class)).rejects(hints);
}
@Test
void shouldNotRegisterJavaTypesInLists() {
RuntimeHints hints = runProcessor(StringListProperties.class);
assertThat(RuntimeHintsPredicates.reflection().onType(String.class)).rejects(hints);
}
@Test
void shouldRegisterConstructorBinding() throws NoSuchMethodException {
RuntimeHints hints = runProcessor(ConstructorBindingProperties.class);
assertThat(RuntimeHintsPredicates.reflection()
.onConstructor(ReflectionUtils.accessibleConstructor(ConstructorBindingProperties.class, String.class)))
.accepts(hints);
}
@Test
void shouldRegisterConstructorBindingWithRecords() throws NoSuchMethodException {
RuntimeHints hints = runProcessor(RecordProperties.class);
assertThat(RuntimeHintsPredicates.reflection()
.onConstructor(ReflectionUtils.accessibleConstructor(RecordProperties.class, String.class)))
.accepts(hints);
}
@Test
void shouldRegisterNestedTypes() {
RuntimeHints hints = runProcessor(NestedProperties.class);
hasReflectionHintsForType(hints, Nested.class);
}
@Test
void shouldRegisterNestedTypesWhenNoSetterIsPresent() {
RuntimeHints hints = runProcessor(NestedNoSetterProperties.class);
hasReflectionHintsForType(hints, Nested.class);
}
@Test
void shouldRegisterNestedTypesInLists() {
RuntimeHints hints = runProcessor(NestedListProperties.class);
hasReflectionHintsForType(hints, Nested.class);
}
@Test
void shouldRegisterNestedTypesInMaps() {
RuntimeHints hints = runProcessor(NestedMapProperties.class);
hasReflectionHintsForType(hints, Nested.class);
}
@Test
void shouldRegisterNestedTypesInArrays() {
RuntimeHints hints = runProcessor(NestedArrayProperties.class);
hasReflectionHintsForType(hints, Nested.class);
}
@Test
void shouldRegisterNestedWithRecords() {
RuntimeHints hints = runProcessor(NestedRecordProperties.class);
hasReflectionHintsForType(hints, Nested.class);
}
@Test
void shouldRegisterMultipleLevelsOfNested() {
RuntimeHints hints = runProcessor(NestedMultipleLevelsProperties.class);
hasReflectionHintsForType(hints, NestedLevel1.class);
hasReflectionHintsForType(hints, NestedLevel2.class);
hasReflectionHintsForType(hints, NestedLevel3.class);
}
@Test
void shouldNotCrashOnCycles() {
assertThatCode(() -> runProcessor(CycleProperties.class)).doesNotThrowAnyException();
}
@Test
void shouldNotRegisterInterfaces() {
RuntimeHints hints = runProcessor(InterfaceProperties.class);
assertThat(RuntimeHintsPredicates.reflection().onType(SomeInterface.class)).rejects(hints);
}
@Test
void shouldNotRegisterKnownTypes() {
RuntimeHints hints = runProcessor(AwareProperties.class);
assertThat(RuntimeHintsPredicates.reflection().onType(Environment.class)).rejects(hints);
assertThat(RuntimeHintsPredicates.reflection().onType(ApplicationContext.class)).rejects(hints);
assertThat(RuntimeHintsPredicates.reflection().onType(BeanFactory.class)).rejects(hints);
}
private RuntimeHints runProcessor(Class<?> type) {
RuntimeHints hints = new RuntimeHints();
ConfigurationPropertiesReflectionHintsProcessor.processConfigurationProperties(type, hints.reflection());
return hints;
}
private void hasReflectionHintsForType(RuntimeHints hints, Class<?> type) {
assertThat(RuntimeHintsPredicates.reflection().onType(type)
.withMemberCategories(MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.INVOKE_PUBLIC_METHODS))
.accepts(hints);
}
@ConfigurationProperties
public static class NoArgsCtorProperties {
private String field;
NoArgsCtorProperties() {
}
NoArgsCtorProperties(String field) {
this.field = field;
}
public String getField() {
return this.field;
}
public void setField(String field) {
this.field = field;
}
}
@ConfigurationProperties
public static class StringListProperties {
private final List<String> stringList = new ArrayList<>();
public List<String> getStringList() {
return this.stringList;
}
}
@ConfigurationProperties
public static class ConstructorBindingProperties {
private final String field;
ConstructorBindingProperties(String field) {
this.field = field;
}
public String getField() {
return this.field;
}
}
@ConfigurationProperties
public record RecordProperties(String field) {
}
@ConfigurationProperties
public static class NestedProperties {
private Nested nested;
public Nested getNested() {
return this.nested;
}
public void setNested(Nested nested) {
this.nested = nested;
}
}
@ConfigurationProperties
public static class NestedNoSetterProperties {
private final Nested nested = new Nested();
public Nested getNested() {
return this.nested;
}
}
@ConfigurationProperties
public static class NestedListProperties {
private List<Nested> nestedList;
public List<Nested> getNestedList() {
return this.nestedList;
}
public void setNestedList(List<Nested> nestedList) {
this.nestedList = nestedList;
}
}
@ConfigurationProperties
public static class NestedMapProperties {
private Map<String, Nested> nestedMap = new HashMap<>();
public Map<String, Nested> getNestedMap() {
return this.nestedMap;
}
}
@ConfigurationProperties
public static class NestedArrayProperties {
private Nested[] nestedArray;
public Nested[] getNestedArray() {
return this.nestedArray;
}
public void setNestedArray(Nested[] nestedArray) {
this.nestedArray = nestedArray;
}
}
@ConfigurationProperties
public record NestedRecordProperties(Nested nested) {
}
@ConfigurationProperties
public static class CycleProperties {
private CycleProperties cycleProperties;
public CycleProperties getCycleProperties() {
return this.cycleProperties;
}
public void setCycleProperties(CycleProperties cycleProperties) {
this.cycleProperties = cycleProperties;
}
}
@ConfigurationProperties
public static class NestedMultipleLevelsProperties {
private NestedLevel1 nestedLevel1;
public NestedLevel1 getNestedLevel1() {
return this.nestedLevel1;
}
public void setNestedLevel1(NestedLevel1 nestedLevel1) {
this.nestedLevel1 = nestedLevel1;
}
}
@ConfigurationProperties
public static class InterfaceProperties {
private SomeInterface someInterface;
public SomeInterface getSomeInterface() {
return this.someInterface;
}
public void setSomeInterface(SomeInterface someInterface) {
this.someInterface = someInterface;
}
}
@ConfigurationProperties
public static class AwareProperties implements ApplicationContextAware, BeanFactoryAware, EnvironmentAware {
private String field;
private BeanFactory beanFactory;
private ApplicationContext applicationContext;
private Environment environment;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
public String getField() {
return this.field;
}
public BeanFactory getBeanFactory() {
return this.beanFactory;
}
public ApplicationContext getApplicationContext() {
return this.applicationContext;
}
public Environment getEnvironment() {
return this.environment;
}
}
interface SomeInterface {
}
public static class Nested {
private String field;
public String getField() {
return this.field;
}
public void setField(String field) {
this.field = field;
}
}
public static class NestedLevel1 {
private NestedLevel2 nestedLevel2;
public NestedLevel2 getNestedLevel2() {
return this.nestedLevel2;
}
public void setNestedLevel2(NestedLevel2 nestedLevel2) {
this.nestedLevel2 = nestedLevel2;
}
}
public static class NestedLevel2 {
private NestedLevel3 nestedLevel3;
public NestedLevel3 getNestedLevel3() {
return this.nestedLevel3;
}
public void setNestedLevel3(NestedLevel3 nestedLevel3) {
this.nestedLevel3 = nestedLevel3;
}
}
public class NestedLevel3 {
private String field;
public String getField() {
return this.field;
}
public void setField(String field) {
this.field = field;
}
}
}
Loading…
Cancel
Save