From cdbb7f441a1f25eba7a4369b975e4600b1329904 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Thu, 6 Aug 2020 17:49:00 -0700 Subject: [PATCH] Do not ignore null/empty values from SPRING_APPLICATION_JSON Fixes gh-21542 --- .../main/asciidoc/spring-boot-features.adoc | 5 +++ ...plicationJsonEnvironmentPostProcessor.java | 11 +++++- ...tionJsonEnvironmentPostProcessorTests.java | 37 ++++++++++++++++++- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 7d24e878a4..00fcfc9495 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -426,6 +426,11 @@ You can also supply the JSON as a JNDI variable, as follows: `java:comp/env/spri ==== +NOTE: Although `null` values from the JSON will be added to the resulting property source, the `PropertySourcesPropertyResolver` treats `null` properties as missing values. +This means that the JSON cannot override properties from lower order property sources with a `null` value. + + + [[boot-features-external-config-random-values]] === Configuring Random Values diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java index 01f5f48319..ba10642b13 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -38,6 +38,7 @@ import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySource; import org.springframework.core.env.StandardEnvironment; import org.springframework.util.ClassUtils; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.web.context.support.StandardServletEnvironment; @@ -123,9 +124,17 @@ public class SpringApplicationJsonEnvironmentPostProcessor implements Environmen @SuppressWarnings("unchecked") private void extract(String name, Map result, Object value) { if (value instanceof Map) { + if (CollectionUtils.isEmpty((Map) value)) { + result.put(name, value); + return; + } flatten(name, result, (Map) value); } else if (value instanceof Collection) { + if (CollectionUtils.isEmpty((Collection) value)) { + result.put(name, value); + return; + } int index = 0; for (Object object : (Collection) value) { extract(name + "[" + index + "]", result, object); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessorTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessorTests.java index 1148850804..0f9178d357 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessorTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -17,6 +17,7 @@ package org.springframework.boot.env; import java.util.Collections; +import java.util.Map; import org.junit.jupiter.api.Test; @@ -26,6 +27,7 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; import org.springframework.core.env.StandardEnvironment; +import org.springframework.mock.env.MockPropertySource; import org.springframework.test.context.support.TestPropertySourceUtils; import org.springframework.web.context.support.StandardServletEnvironment; @@ -170,6 +172,39 @@ class SpringApplicationJsonEnvironmentPostProcessorTests { assertThat(this.environment.getPropertySources()).containsSequence(custom, json, servlet, jndi); } + @Test + void nullValuesShouldBeAddedToPropertySource() { + TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, + "SPRING_APPLICATION_JSON={\"foo\":null}"); + this.processor.postProcessEnvironment(this.environment, null); + assertThat(this.environment.containsProperty("foo")).isTrue(); + } + + @Test + void emptyValuesForCollectionShouldNotBeIgnored() { + TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, + "SPRING_APPLICATION_JSON={\"foo\":[]}"); + MockPropertySource source = new MockPropertySource(); + source.setProperty("foo", "bar"); + this.environment.getPropertySources().addLast(source); + assertThat(this.environment.resolvePlaceholders("${foo}")).isEqualTo("bar"); + this.environment.getPropertySources().addLast(source); + this.processor.postProcessEnvironment(this.environment, null); + assertThat(this.environment.resolvePlaceholders("${foo}")).isEmpty(); + } + + @Test + @SuppressWarnings("unchecked") + void emptyMapValuesShouldNotBeIgnored() { + TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, + "SPRING_APPLICATION_JSON={\"foo\":{}}"); + MockPropertySource source = new MockPropertySource(); + source.setProperty("foo.baz", "bar"); + this.environment.getPropertySources().addLast(source); + this.processor.postProcessEnvironment(this.environment, null); + assertThat(this.environment.getProperty("foo", Map.class)).isEmpty(); + } + private void testServletPropertySource(String servletPropertySourceName) { this.environment.getPropertySources().addFirst(getPropertySource(servletPropertySourceName, "servlet")); TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,