parent
							
								
									fb439b6824
								
							
						
					
					
						commit
						2a405c94a8
					
				| 
						 | 
				
			
			@ -0,0 +1,565 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.lang.reflect.Constructor;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.function.Consumer;
 | 
			
		||||
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
 | 
			
		||||
import org.springframework.aot.generate.DefaultGenerationContext;
 | 
			
		||||
import org.springframework.aot.generate.GenerationContext;
 | 
			
		||||
import org.springframework.aot.generate.InMemoryGeneratedFiles;
 | 
			
		||||
import org.springframework.aot.hint.ExecutableHint;
 | 
			
		||||
import org.springframework.aot.hint.MemberCategory;
 | 
			
		||||
import org.springframework.aot.hint.RuntimeHints;
 | 
			
		||||
import org.springframework.aot.hint.TypeHint;
 | 
			
		||||
import org.springframework.aot.hint.TypeReference;
 | 
			
		||||
import org.springframework.beans.factory.aot.AotFactoriesLoader;
 | 
			
		||||
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;
 | 
			
		||||
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;
 | 
			
		||||
import org.springframework.beans.factory.aot.BeanFactoryInitializationCode;
 | 
			
		||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
 | 
			
		||||
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.mockito.Mockito.mock;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests for {@link ConfigurationPropertiesBeanFactoryInitializationAotProcessor}.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Stephane Nicoll
 | 
			
		||||
 */
 | 
			
		||||
class ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests {
 | 
			
		||||
 | 
			
		||||
	private final ConfigurationPropertiesBeanFactoryInitializationAotProcessor processor = new ConfigurationPropertiesBeanFactoryInitializationAotProcessor();
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void configurationPropertiesBeanFactoryInitializationAotProcessorIsRegistered() {
 | 
			
		||||
		assertThat(new AotFactoriesLoader(new DefaultListableBeanFactory())
 | 
			
		||||
				.load(BeanFactoryInitializationAotProcessor.class))
 | 
			
		||||
						.anyMatch(ConfigurationPropertiesBeanFactoryInitializationAotProcessor.class::isInstance);
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void processNoMatchesReturnsNullContribution() {
 | 
			
		||||
		DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
 | 
			
		||||
		beanFactory.registerBeanDefinition("test", new RootBeanDefinition(String.class));
 | 
			
		||||
		assertThat(this.processor.processAheadOfTime(beanFactory)).isNull();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void processJavaBeanConfigurationProperties() {
 | 
			
		||||
		RuntimeHints runtimeHints = process(SampleProperties.class);
 | 
			
		||||
		assertThat(runtimeHints.reflection().typeHints()).singleElement()
 | 
			
		||||
				.satisfies(javaBeanBinding(SampleProperties.class));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void processJavaBeanConfigurationPropertiesWithSeveralConstructors() throws NoSuchMethodException {
 | 
			
		||||
		RuntimeHints runtimeHints = process(SamplePropertiesWithSeveralConstructors.class);
 | 
			
		||||
		assertThat(runtimeHints.reflection().typeHints()).singleElement()
 | 
			
		||||
				.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(2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@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(2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@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(2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void processJavaBeanConfigurationPropertiesWithListOfJavaType() {
 | 
			
		||||
		RuntimeHints runtimeHints = process(SamplePropertiesWithSimpleList.class);
 | 
			
		||||
		List<TypeHint> typeHints = runtimeHints.reflection().typeHints().toList();
 | 
			
		||||
		assertThat(typeHints).anySatisfy(javaBeanBinding(SamplePropertiesWithSimpleList.class));
 | 
			
		||||
		assertThat(typeHints).hasSize(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@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(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void processValueObjectConfigurationPropertiesWithSpecificConstructor() throws NoSuchMethodException {
 | 
			
		||||
		RuntimeHints runtimeHints = process(SampleImmutablePropertiesWithSeveralConstructors.class);
 | 
			
		||||
		List<TypeHint> typeHints = runtimeHints.reflection().typeHints().toList();
 | 
			
		||||
		assertThat(typeHints).anySatisfy(valueObjectBinding(SampleImmutablePropertiesWithSeveralConstructors.class,
 | 
			
		||||
				SampleImmutablePropertiesWithSeveralConstructors.class.getDeclaredConstructor(String.class)));
 | 
			
		||||
		assertThat(typeHints).hasSize(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@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(3);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void processConfigurationPropertiesWithNestedTypeNotUsedIsIgnored() {
 | 
			
		||||
		RuntimeHints runtimeHints = process(SamplePropertiesWithNested.class);
 | 
			
		||||
		assertThat(runtimeHints.reflection().typeHints()).singleElement()
 | 
			
		||||
				.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(3);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void processConfigurationPropertiesWithRecursiveType() {
 | 
			
		||||
		RuntimeHints runtimeHints = process(SamplePropertiesWithRecursive.class);
 | 
			
		||||
		assertThat(runtimeHints.reflection().typeHints())
 | 
			
		||||
				.anySatisfy(javaBeanBinding(SamplePropertiesWithRecursive.class))
 | 
			
		||||
				.anySatisfy(javaBeanBinding(Recursive.class)).hasSize(2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void processValueObjectConfigurationPropertiesWithRecursiveType() {
 | 
			
		||||
		RuntimeHints runtimeHints = process(SampleImmutablePropertiesWithRecursive.class);
 | 
			
		||||
		assertThat(runtimeHints.reflection().typeHints())
 | 
			
		||||
				.anySatisfy(valueObjectBinding(SampleImmutablePropertiesWithRecursive.class,
 | 
			
		||||
						SampleImmutablePropertiesWithRecursive.class.getDeclaredConstructors()[0]))
 | 
			
		||||
				.anySatisfy(valueObjectBinding(ImmutableRecursive.class,
 | 
			
		||||
						ImmutableRecursive.class.getDeclaredConstructors()[0]))
 | 
			
		||||
				.hasSize(2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void processConfigurationPropertiesWithWellKnownTypes() {
 | 
			
		||||
		RuntimeHints runtimeHints = process(SamplePropertiesWithWellKnownTypes.class);
 | 
			
		||||
		assertThat(runtimeHints.reflection().typeHints())
 | 
			
		||||
				.anySatisfy(javaBeanBinding(SamplePropertiesWithWellKnownTypes.class))
 | 
			
		||||
				// TODO
 | 
			
		||||
				.hasSize(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void processConfigurationPropertiesWithCrossReference() {
 | 
			
		||||
		RuntimeHints runtimeHints = process(SamplePropertiesWithCrossReference.class);
 | 
			
		||||
		assertThat(runtimeHints.reflection().typeHints())
 | 
			
		||||
				.anySatisfy(javaBeanBinding(SamplePropertiesWithCrossReference.class))
 | 
			
		||||
				.anySatisfy(javaBeanBinding(CrossReferenceA.class)).anySatisfy(javaBeanBinding(CrossReferenceB.class))
 | 
			
		||||
				.hasSize(3);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void processConfigurationPropertiesWithUnresolvedGeneric() {
 | 
			
		||||
		RuntimeHints runtimeHints = process(SamplePropertiesWithGeneric.class);
 | 
			
		||||
		assertThat(runtimeHints.reflection().typeHints()).anySatisfy(javaBeanBinding(SamplePropertiesWithGeneric.class))
 | 
			
		||||
				.anySatisfy(javaBeanBinding(GenericObject.class));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private Consumer<TypeHint> javaBeanBinding(Class<?> type) {
 | 
			
		||||
		return javaBeanBinding(type, type.getDeclaredConstructors()[0]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private Consumer<TypeHint> javaBeanBinding(Class<?> type, Constructor<?> constructor) {
 | 
			
		||||
		return (entry) -> {
 | 
			
		||||
			assertThat(entry.getType()).isEqualTo(TypeReference.of(type));
 | 
			
		||||
			assertThat(entry.constructors()).singleElement().satisfies(match(constructor));
 | 
			
		||||
			assertThat(entry.getMemberCategories()).containsOnly(MemberCategory.INVOKE_DECLARED_METHODS,
 | 
			
		||||
					MemberCategory.INVOKE_PUBLIC_METHODS);
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private Consumer<TypeHint> valueObjectBinding(Class<?> type, Constructor<?> constructor) {
 | 
			
		||||
		return (entry) -> {
 | 
			
		||||
			assertThat(entry.getType()).isEqualTo(TypeReference.of(type));
 | 
			
		||||
			assertThat(entry.constructors()).singleElement().satisfies(match(constructor));
 | 
			
		||||
			assertThat(entry.getMemberCategories()).containsOnly(MemberCategory.INVOKE_DECLARED_METHODS,
 | 
			
		||||
					MemberCategory.INVOKE_PUBLIC_METHODS);
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private Consumer<ExecutableHint> match(Constructor<?> constructor) {
 | 
			
		||||
		return (executableHint) -> {
 | 
			
		||||
			assertThat(executableHint.getName()).isEqualTo("<init>");
 | 
			
		||||
			assertThat(Arrays.stream(constructor.getParameterTypes()).map(TypeReference::of).toList())
 | 
			
		||||
					.isEqualTo(executableHint.getParameterTypes());
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private RuntimeHints process(Class<?>... types) {
 | 
			
		||||
		DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
 | 
			
		||||
		for (Class<?> type : types) {
 | 
			
		||||
			beanFactory.registerBeanDefinition(type.getName(), new RootBeanDefinition(type));
 | 
			
		||||
		}
 | 
			
		||||
		BeanFactoryInitializationAotContribution contribution = this.processor.processAheadOfTime(beanFactory);
 | 
			
		||||
		assertThat(contribution).isNotNull();
 | 
			
		||||
		GenerationContext generationContext = new DefaultGenerationContext(new InMemoryGeneratedFiles());
 | 
			
		||||
		contribution.applyTo(generationContext, mock(BeanFactoryInitializationCode.class));
 | 
			
		||||
		return generationContext.getRuntimeHints();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@ConfigurationProperties("test")
 | 
			
		||||
	static class SampleProperties {
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@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 {
 | 
			
		||||
 | 
			
		||||
		private final String name;
 | 
			
		||||
 | 
			
		||||
		SampleImmutableProperties(String name) {
 | 
			
		||||
			this.name = name;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@ConfigurationProperties
 | 
			
		||||
	public static class SampleImmutablePropertiesWithSeveralConstructors {
 | 
			
		||||
 | 
			
		||||
		private final String name;
 | 
			
		||||
 | 
			
		||||
		@ConstructorBinding
 | 
			
		||||
		SampleImmutablePropertiesWithSeveralConstructors(String name) {
 | 
			
		||||
			this.name = name;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		SampleImmutablePropertiesWithSeveralConstructors() {
 | 
			
		||||
			this("test");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@ConfigurationProperties
 | 
			
		||||
	public static class SampleImmutablePropertiesWithList {
 | 
			
		||||
 | 
			
		||||
		private final List<Person> family;
 | 
			
		||||
 | 
			
		||||
		SampleImmutablePropertiesWithList(List<Person> family) {
 | 
			
		||||
			this.family = family;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@ConfigurationProperties("nested")
 | 
			
		||||
	public static class SamplePropertiesWithNested {
 | 
			
		||||
 | 
			
		||||
		static class OneLevelDown {
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@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
 | 
			
		||||
	public static class SampleImmutablePropertiesWithRecursive {
 | 
			
		||||
 | 
			
		||||
		@NestedConfigurationProperty
 | 
			
		||||
		private ImmutableRecursive recursive;
 | 
			
		||||
 | 
			
		||||
		SampleImmutablePropertiesWithRecursive(ImmutableRecursive recursive) {
 | 
			
		||||
			this.recursive = recursive;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@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 {
 | 
			
		||||
 | 
			
		||||
		private final String firstName;
 | 
			
		||||
 | 
			
		||||
		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 {
 | 
			
		||||
 | 
			
		||||
		private ImmutableRecursive recursive;
 | 
			
		||||
 | 
			
		||||
		ImmutableRecursive(ImmutableRecursive recursive) {
 | 
			
		||||
			this.recursive = recursive;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@ConfigurationProperties("crossreference")
 | 
			
		||||
	public static class SamplePropertiesWithCrossReference {
 | 
			
		||||
 | 
			
		||||
		@NestedConfigurationProperty
 | 
			
		||||
		private CrossReferenceA crossReferenceA;
 | 
			
		||||
 | 
			
		||||
		public void setCrossReferenceA(CrossReferenceA crossReferenceA) {
 | 
			
		||||
			this.crossReferenceA = crossReferenceA;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public CrossReferenceA getCrossReferenceA() {
 | 
			
		||||
			return this.crossReferenceA;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static class CrossReferenceA {
 | 
			
		||||
 | 
			
		||||
		@NestedConfigurationProperty
 | 
			
		||||
		private CrossReferenceB crossReferenceB;
 | 
			
		||||
 | 
			
		||||
		public void setCrossReferenceB(CrossReferenceB crossReferenceB) {
 | 
			
		||||
			this.crossReferenceB = crossReferenceB;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public CrossReferenceB getCrossReferenceB() {
 | 
			
		||||
			return this.crossReferenceB;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static class CrossReferenceB {
 | 
			
		||||
 | 
			
		||||
		private CrossReferenceA crossReferenceA;
 | 
			
		||||
 | 
			
		||||
		public void setCrossReferenceA(CrossReferenceA crossReferenceA) {
 | 
			
		||||
			this.crossReferenceA = crossReferenceA;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public CrossReferenceA getCrossReferenceA() {
 | 
			
		||||
			return this.crossReferenceA;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@ConfigurationProperties(prefix = "generic")
 | 
			
		||||
	public static class SamplePropertiesWithGeneric {
 | 
			
		||||
 | 
			
		||||
		@NestedConfigurationProperty
 | 
			
		||||
		private GenericObject<?> generic;
 | 
			
		||||
 | 
			
		||||
		public GenericObject<?> getGeneric() {
 | 
			
		||||
			return this.generic;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static final class GenericObject<T> {
 | 
			
		||||
 | 
			
		||||
		private final T value;
 | 
			
		||||
 | 
			
		||||
		GenericObject(T value) {
 | 
			
		||||
			this.value = value;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T getValue() {
 | 
			
		||||
			return this.value;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue