Home / Class/ BinderTests Class — spring-boot Architecture

BinderTests Class — spring-boot Architecture

Architecture documentation for the BinderTests class in BinderTests.java from the spring-boot codebase.

Entity Profile

Relationship Graph

Source Code

core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BinderTests.java lines 68–526

class BinderTests {

	private final List<ConfigurationPropertySource> sources = new ArrayList<>();

	private Binder binder = new Binder(this.sources);

	@Test
	@SuppressWarnings("NullAway") // Test null check
	void createWhenSourcesIsNullArrayShouldThrowException() {
		assertThatIllegalArgumentException().isThrownBy(() -> new Binder((ConfigurationPropertySource[]) null))
			.withMessageContaining("'sources' must not be null");
	}

	@Test
	@SuppressWarnings("NullAway") // Test null check
	void createWhenSourcesIsNullIterableShouldThrowException() {
		assertThatIllegalArgumentException().isThrownBy(() -> new Binder((Iterable<ConfigurationPropertySource>) null))
			.withMessageContaining("'sources' must not be null");
	}

	@Test
	void createWhenArraySourcesContainsNullElementShouldThrowException() {
		assertThatIllegalArgumentException().isThrownBy(() -> new Binder(new ConfigurationPropertySource[] { null }))
			.withMessageContaining("'sources' must not contain null elements");
	}

	@Test
	void createWhenIterableSourcesContainsNullElementShouldThrowException() {
		assertThatIllegalArgumentException().isThrownBy(() -> new Binder(Collections.singletonList(null)))
			.withMessageContaining("'sources' must not contain null elements");
	}

	@Test
	@SuppressWarnings("NullAway") // Test null check
	void bindWhenNameIsNullShouldThrowException() {
		assertThatIllegalArgumentException()
			.isThrownBy(() -> this.binder.bind((ConfigurationPropertyName) null, Bindable.of(String.class),
					BindHandler.DEFAULT))
			.withMessageContaining("'name' must not be null");
	}

	@Test
	@SuppressWarnings("NullAway") // Test null check
	void bindWhenTargetIsNullShouldThrowException() {
		assertThatIllegalArgumentException()
			.isThrownBy(() -> this.binder.bind(ConfigurationPropertyName.of("foo"), null, BindHandler.DEFAULT))
			.withMessageContaining("'target' must not be null");
	}

	@Test
	void bindToValueWhenPropertyIsMissingShouldReturnUnbound() {
		this.sources.add(new MockConfigurationPropertySource());
		BindResult<String> result = this.binder.bind("foo", Bindable.of(String.class));
		assertThat(result.isBound()).isFalse();
	}

	@Test
	void bindToValueShouldReturnPropertyValue() {
		this.sources.add(new MockConfigurationPropertySource("foo", 123));
		BindResult<Integer> result = this.binder.bind("foo", Bindable.of(Integer.class));
		assertThat(result.get()).isEqualTo(123);
	}

	@Test
	void bindToValueShouldReturnPropertyValueFromSecondSource() {
		this.sources.add(new MockConfigurationPropertySource("foo", 123));
		this.sources.add(new MockConfigurationPropertySource("bar", 234));
		BindResult<Integer> result = this.binder.bind("bar", Bindable.of(Integer.class));
		assertThat(result.get()).isEqualTo(234);
	}

	@Test
	void bindToValueShouldReturnConvertedPropertyValue() {
		this.sources.add(new MockConfigurationPropertySource("foo", "123"));
		BindResult<Integer> result = this.binder.bind("foo", Bindable.of(Integer.class));
		assertThat(result.get()).isEqualTo(123);
	}

	@Test
	void bindToValueWhenMultipleCandidatesShouldReturnFirst() {
		this.sources.add(new MockConfigurationPropertySource("foo", 123));
		this.sources.add(new MockConfigurationPropertySource("foo", 234));
		BindResult<Integer> result = this.binder.bind("foo", Bindable.of(Integer.class));
		assertThat(result.get()).isEqualTo(123);
	}

	@Test
	void bindToValueWithPlaceholdersShouldResolve() {
		StandardEnvironment environment = new StandardEnvironment();
		TestPropertySourceUtils.addInlinedPropertiesToEnvironment(environment, "bar=23");
		this.sources.add(new MockConfigurationPropertySource("foo", "1${bar}"));
		this.binder = new Binder(this.sources, new PropertySourcesPlaceholdersResolver(environment));
		BindResult<Integer> result = this.binder.bind("foo", Bindable.of(Integer.class));
		assertThat(result.get()).isEqualTo(123);
	}

	@Test
	void bindToValueWithMissingPlaceholderShouldResolveToValueWithPlaceholder() {
		StandardEnvironment environment = new StandardEnvironment();
		this.sources.add(new MockConfigurationPropertySource("foo", "${bar}"));
		this.binder = new Binder(this.sources, new PropertySourcesPlaceholdersResolver(environment));
		BindResult<String> result = this.binder.bind("foo", Bindable.of(String.class));
		assertThat(result.get()).isEqualTo("${bar}");
	}

	@Test
	void bindToValueWithCustomPropertyEditorShouldReturnConvertedValue() {
		this.binder = new Binder(this.sources, null, null,
				(registry) -> registry.registerCustomEditor(JavaBean.class, new JavaBeanPropertyEditor()));
		this.sources.add(new MockConfigurationPropertySource("foo", "123"));
		BindResult<JavaBean> result = this.binder.bind("foo", Bindable.of(JavaBean.class));
		assertThat(result.get().getValue()).isEqualTo("123");
	}

	@Test
	void bindToValueShouldTriggerOnSuccess() {
		this.sources.add(new MockConfigurationPropertySource("foo", "1", "line1"));
		BindHandler handler = mockBindHandler();
		Bindable<Integer> target = Bindable.of(Integer.class);
		this.binder.bind("foo", target, handler);
		InOrder ordered = inOrder(handler);
		ordered.verify(handler).onSuccess(eq(ConfigurationPropertyName.of("foo")), eq(target), any(), eq(1));
	}

	@Test
	void bindOrCreateWhenNotBoundShouldTriggerOnCreate() {
		BindHandler handler = mock(BindHandler.class);
		Bindable<JavaBean> target = Bindable.of(JavaBean.class);
		this.binder.bindOrCreate("foo", target, handler);
		InOrder ordered = inOrder(handler);
		ordered.verify(handler).onCreate(eq(ConfigurationPropertyName.of("foo")), eq(target), any(), any());
	}

	@Test
	void bindToJavaBeanShouldReturnPopulatedBean() {
		this.sources.add(new MockConfigurationPropertySource("foo.value", "bar"));
		JavaBean result = this.binder.bind("foo", Bindable.of(JavaBean.class)).get();
		assertThat(result.getValue()).isEqualTo("bar");
	}

	@Test
	void bindToJavaBeanWhenNonIterableShouldReturnPopulatedBean() {
		MockConfigurationPropertySource source = new MockConfigurationPropertySource("foo.value", "bar");
		this.sources.add(source.nonIterable());
		JavaBean result = this.binder.bind("foo", Bindable.of(JavaBean.class)).get();
		assertThat(result.getValue()).isEqualTo("bar");
	}

	@Test
	void bindToJavaBeanWhenHasPropertyWithSameNameShouldStillBind() {
		// gh-10945
		MockConfigurationPropertySource source = new MockConfigurationPropertySource();
		source.put("foo", "boom");
		source.put("foo.value", "bar");
		this.sources.add(source);
		JavaBean result = this.binder.bind("foo", Bindable.of(JavaBean.class)).get();
		assertThat(result.getValue()).isEqualTo("bar");
	}

	@Test
	void bindToJavaBeanShouldTriggerOnSuccess() {
		this.sources.add(new MockConfigurationPropertySource("foo.value", "bar", "line1"));
		BindHandler handler = mockBindHandler();
		Bindable<JavaBean> target = Bindable.of(JavaBean.class);
		this.binder.bind("foo", target, handler);
		InOrder inOrder = inOrder(handler);
		inOrder.verify(handler)
			.onSuccess(eq(ConfigurationPropertyName.of("foo.value")), eq(Bindable.of(String.class)), any(), eq("bar"));
		inOrder.verify(handler)
			.onSuccess(eq(ConfigurationPropertyName.of("foo")), eq(target), any(), isA(JavaBean.class));
	}

	@Test
	void bindWhenHasCustomDefaultHandlerShouldTriggerOnSuccess() {
		this.sources.add(new MockConfigurationPropertySource("foo.value", "bar", "line1"));
		BindHandler handler = mockBindHandler();
		Binder binder = new Binder(this.sources, null, null, null, handler);
		Bindable<JavaBean> target = Bindable.of(JavaBean.class);
		binder.bind("foo", target);
		InOrder inOrder = inOrder(handler);
		inOrder.verify(handler)
			.onSuccess(eq(ConfigurationPropertyName.of("foo.value")), eq(Bindable.of(String.class)), any(), eq("bar"));
		inOrder.verify(handler)
			.onSuccess(eq(ConfigurationPropertyName.of("foo")), eq(target), any(), isA(JavaBean.class));
	}

	@Test
	void bindWhenHasMalformedDateShouldThrowException() {
		this.sources.add(new MockConfigurationPropertySource("foo", "2014-04-01T01:30:00.000-05:00"));
		assertThatExceptionOfType(BindException.class)
			.isThrownBy(() -> this.binder.bind("foo", Bindable.of(LocalDate.class)))
			.withCauseInstanceOf(ConversionFailedException.class);
	}

	@Test
	void bindWhenHasAnnotationsShouldChangeConvertedValue() {
		this.sources.add(new MockConfigurationPropertySource("foo", "2014-04-01T01:30:00.000-05:00"));
		DateTimeFormat annotation = AnnotationUtils.synthesizeAnnotation(
				Collections.singletonMap("iso", DateTimeFormat.ISO.DATE_TIME), DateTimeFormat.class, null);
		LocalDate result = this.binder.bind("foo", Bindable.of(LocalDate.class).withAnnotations(annotation)).get();
		assertThat(result).hasToString("2014-04-01");
	}

	@Test
	void bindToValidatedBeanWithResourceAndNonEnumerablePropertySource() {
		ConfigurationPropertySources.from(new PropertySource<String>("test") {

			@Override
			public @Nullable Object getProperty(String name) {
				return null;
			}

		}).forEach(this.sources::add);
		Validator validator = new SpringValidatorAdapter(
				Validation.byDefaultProvider().configure().buildValidatorFactory().getValidator());
		this.binder.bind("foo", Bindable.of(ResourceBean.class), new ValidationBindHandler(validator));
	}

	@Test
	void bindToBeanWithCycle() {
		MockConfigurationPropertySource source = new MockConfigurationPropertySource();
		this.sources.add(source.nonIterable());
		Bindable<CycleBean1> target = Bindable.of(CycleBean1.class);
		this.binder.bind("foo", target);
	}

	@Test
	@SuppressWarnings("rawtypes")
	void bindToBeanWithUnresolvableGenerics() {
		MockConfigurationPropertySource source = new MockConfigurationPropertySource();
		source.put("foo.bar", "hello");
		this.sources.add(source);
		Bindable<GenericBean> target = Bindable.of(GenericBean.class);
		this.binder.bind("foo", target);
	}

	@Test
	void bindWithEmptyPrefixShouldIgnorePropertiesWithEmptyName() {
		Map<String, Object> source = new HashMap<>();
		source.put("value", "hello");
		source.put("", "bar");
		Iterable<@Nullable ConfigurationPropertySource> propertySources = ConfigurationPropertySources
			.from(new MapPropertySource("test", source));
		propertySources.forEach(this.sources::add);
		Bindable<JavaBean> target = Bindable.of(JavaBean.class);
		JavaBean result = this.binder.bind("", target).get();
		assertThat(result.getValue()).isEqualTo("hello");
	}

	@Test
	void bindOrCreateWhenBindSuccessfulShouldReturnBoundValue() {
		this.sources.add(new MockConfigurationPropertySource("foo.value", "bar"));
		JavaBean result = this.binder.bindOrCreate("foo", Bindable.of(JavaBean.class));
		assertThat(result.getValue()).isEqualTo("bar");
		assertThat(result.getItems()).isEmpty();
	}

	@Test
	void bindOrCreateWhenUnboundShouldReturnCreatedValue() {
		JavaBean value = this.binder.bindOrCreate("foo", Bindable.of(JavaBean.class));
		assertThat(value).isNotNull();
		assertThat(value).isInstanceOf(JavaBean.class);
	}

	@Test
	void bindToJavaBeanWhenHandlerOnStartReturnsNullShouldReturnUnbound() { // gh-18129
		this.sources.add(new MockConfigurationPropertySource("foo.value", "bar"));
		BindResult<JavaBean> result = this.binder.bind("foo", Bindable.of(JavaBean.class), new BindHandler() {

			@Override
			public <T> @Nullable Bindable<T> onStart(ConfigurationPropertyName name, Bindable<T> target,
					BindContext context) {
				return null;
			}

		});
		assertThat(result.isBound()).isFalse();
	}

	@Test
	void bindToJavaBeanWithPublicConstructor() {
		Bindable<JavaBeanWithPublicConstructor> bindable = Bindable.of(JavaBeanWithPublicConstructor.class);
		JavaBeanWithPublicConstructor result = bindToJavaBeanWithPublicConstructor(bindable);
		assertThat(result.getValue()).isEqualTo("constructor");
	}

	@Test
	void bindToJavaBeanWithPublicConstructorWhenHasBindRestriction() {
		Bindable<JavaBeanWithPublicConstructor> bindable = Bindable.of(JavaBeanWithPublicConstructor.class)
			.withBindRestrictions(BindRestriction.NO_DIRECT_PROPERTY);
		JavaBeanWithPublicConstructor result = bindToJavaBeanWithPublicConstructor(bindable);
		assertThat(result.getValue()).isEqualTo("setter");
	}

	private JavaBeanWithPublicConstructor bindToJavaBeanWithPublicConstructor(
			Bindable<JavaBeanWithPublicConstructor> bindable) {
		MockConfigurationPropertySource source = new MockConfigurationPropertySource();
		source.put("foo", "constructor");
		source.put("foo.value", "setter");
		this.sources.add(source);
		return this.binder.bindOrCreate("foo", bindable);
	}

	private BindHandler mockBindHandler() {
		BindHandler handler = mock(BindHandler.class);
		given(handler.onStart(any(), any(), any())).willAnswer(InvocationArgument.index(1));
		given(handler.onCreate(any(), any(), any(), any())).willAnswer(InvocationArgument.index(3));
		given(handler.onSuccess(any(), any(), any(), any())).willAnswer(InvocationArgument.index(3));
		return handler;
	}

	static class JavaBean {

		private @Nullable String value;

		private final List<String> items = Collections.emptyList();

		@Nullable String getValue() {
			return this.value;
		}

		void setValue(@Nullable String value) {
			this.value = value;
		}

		List<String> getItems() {
			return this.items;
		}

	}

	static class NestedJavaBean {

		private DefaultValuesBean valuesBean = new DefaultValuesBean();

		DefaultValuesBean getValuesBean() {
			return this.valuesBean;
		}

		void setValuesBean(DefaultValuesBean valuesBean) {
			this.valuesBean = valuesBean;
		}

	}

	static class DefaultValuesBean {

		private String value = "hello";

		private final List<String> items = Collections.emptyList();

		String getValue() {
			return this.value;
		}

		void setValue(String value) {
			this.value = value;
		}

		List<String> getItems() {
			return this.items;
		}

	}

	public enum ExampleEnum {

		FOO_BAR, BAR_BAZ, BAZ_BOO

	}

	@Validated
	static class ResourceBean {

		private @Nullable Resource resource;

		@Nullable Resource getResource() {
			return this.resource;
		}

		void setResource(@Nullable Resource resource) {
			this.resource = resource;
		}

	}

	static class CycleBean1 {

		private @Nullable CycleBean2 two;

		@Nullable CycleBean2 getTwo() {
			return this.two;
		}

		void setTwo(@Nullable CycleBean2 two) {
			this.two = two;
		}

	}

	static class CycleBean2 {

		private @Nullable CycleBean1 one;

		@Nullable CycleBean1 getOne() {
			return this.one;
		}

		void setOne(@Nullable CycleBean1 one) {
			this.one = one;
		}

	}

	static class GenericBean<T> {

		private @Nullable T bar;

		@Nullable T getBar() {
			return this.bar;
		}

		void setBar(@Nullable T bar) {
			this.bar = bar;
		}

	}

	static class JavaBeanPropertyEditor extends PropertyEditorSupport {

		@Override
		public void setAsText(String text) {
			JavaBean value = new JavaBean();
			value.setValue(text);
			setValue(value);
		}

	}

	private static final class InvocationArgument<T> implements Answer<T> {

		private final int index;

		private InvocationArgument(int index) {
			this.index = index;
		}

		@Override
		public T answer(InvocationOnMock invocation) throws Throwable {
			return invocation.getArgument(this.index);
		}

		private static <T> InvocationArgument<T> index(int index) {
			return new InvocationArgument<>(index);
		}

	}

}

Domain

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free