Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Externalized Configuration ignores null values in SPRING_APPLICATION_JSON #21542

Closed
rgordeev opened this issue May 22, 2020 · 8 comments
Closed
Assignees
Labels
type: bug A general bug
Milestone

Comments

@rgordeev
Copy link

rgordeev commented May 22, 2020

E.g. there is a configuration application.yaml

application:
  a: some string
  b:
    - 1
    - 2

I try to override these properties with

SPRING_APPLICATION_JSON={"application": {"a": null, "b": null}}

And it doesn't override values from yaml file, but when values in json are not null everything works fine.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label May 22, 2020
@philwebb
Copy link
Member

Here's a small test that reproduces the issue:

@Test
void nulls() {
	TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "foo=bar");
	assertThat(this.environment.resolvePlaceholders("${foo}")).isEqualTo("bar");
	TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
			"SPRING_APPLICATION_JSON={\"foo\":null}");
	this.processor.postProcessEnvironment(this.environment, null);
	assertThat(this.environment.resolvePlaceholders("${foo}")).isNull();
}

Debugging things it appears that we SpringApplicationJsonEnvironmentPostProcessor does actually insert a null entry in the appropriate place.

The problem is that PropertySourcesPropertyResolver does not use containsValue and always skips over nulls. I'll open an issue with the Spring Framework team to discuss options.

@philwebb
Copy link
Member

I've raised spring-projects/spring-framework#25142. Please track that issue to see what the framework team have to say. For now, I suggest using an empty string instead of null.

@philwebb philwebb added for: external-project For an external project and not something we can fix and removed status: waiting-for-triage An issue we've not yet triaged labels May 27, 2020
@rgordeev
Copy link
Author

rgordeev commented May 27, 2020

@philwebb

For now, I suggest using an empty string instead of null.

But the problem concerns not only null values for strings, but empty values for lists or maps - it's impossible to override values from application.yaml with SPRING_APPLICATION_JSON, that contains empty values or nulls.
E.g.

application:
  a: some string
  b:
    - 1
    - 2

If I try to override b property with

SPRING_APPLICATION_JSON={"application": {"b": null}}

or

SPRING_APPLICATION_JSON={"application": {"b": {}}}

or

SPRING_APPLICATION_JSON={"application": {"b": []}}

nothing happens, application will get

application:
  a: some string
  b:
    - 1
    - 2

in every mentioned case.

@philwebb philwebb reopened this May 27, 2020
@philwebb philwebb added status: waiting-for-triage An issue we've not yet triaged and removed for: external-project For an external project and not something we can fix labels May 27, 2020
@philwebb
Copy link
Member

Reopening to consider spring-projects/spring-framework#25142 (comment)

@philwebb
Copy link
Member

@rgordeev Does SPRING_APPLICATION_JSON={"application": {"b": ""}} work?

@rgordeev
Copy link
Author

rgordeev commented May 28, 2020

@philwebb Yes, that works for all types of properties, but it not obvious at all. You may see test cases
tests

Test case Defaults

application-test.yaml
application:
  a: "some string"
  b:
    - 1
    - 2
    - 3
  c:
    - "one"
    - "two"
    - "three"
  m:
    - one: 1
    - two: 2
Expecting                    Actual
 a == ""                     a == ""
 b == [1,2,3]                b == [1,2,3]
 c == ["one","two","three"]  c == ["one","two","three"]
 m == {"one":1, "two":2}     m == {"one":1, "two":2}

Test case With Empty Lists

application-test.yaml
application:
  a: "some string"
  b:
    - 1
    - 2
    - 3
  c:
    - "one"
    - "two"
    - "three"
  m:
    - one: 1
    - two: 2

We are trying to override

  • string property with null,
  • list properties with empty json array [],
  • map with empty json object {}
SPRING_APPLICATION_JSON = {
    "application": {
        "a": null,
        "b": [],
        "c": [],
        "m": {}
    }
}
Expecting                            Actual
 a == null                           a == "some string"
 b == null | empty array list        b == [1,2,3]
 c == null | empty array list        c == ["one","two","three"]
 m == null | empty map               m == {"one":1, "two":2}

Test case With Empty Objects

application-test.yaml
application:
  a: "some string"
  b:
    - 1
    - 2
    - 3
  c:
    - "one"
    - "two"
    - "three"
  m:
    - one: 1
    - two: 2

We are trying to override

  • string property with null,
  • list properties with empty object {},
  • map with empty json object {}
SPRING_APPLICATION_JSON = {
    "application": {
        "a": null,
        "b": {},
        "c": {},
        "m": {}
    }
}
Expecting                            Actual
 a == null                           a == "some string"
 b == null | empty array list        b == [1,2,3]
 c == null | empty array list        c == ["one","two","three"]
 m == null | empty map               m == {"one":1, "two":2}

Test case With Empty Strings

application-test.yaml
application:
  a: "some string"
  b:
    - 1
    - 2
    - 3
  c:
    - "one"
    - "two"
    - "three"
  m:
    - one: 1
    - two: 2

We are trying to override

  • string property with empty string "",
  • list properties with empty string "",
  • map properties with empty string ""
SPRING_APPLICATION_JSON = {
    "application": {
        "a": "",
        "b": "",
        "c": "",
        "m": ""
    }
}
Expecting                            Actual
 a == ""                             a == ""
 b == null | empty array list        b == []
 c == null | empty array list        c == []
 m == null | empty map               m == {}

Test case With Non null Values

application-test.yaml
application:
  a: "some string"
  b:
    - 1
    - 2
    - 3
  c:
    - "one"
    - "two"
    - "three"
  m:
    - one: 1
    - two: 2

We are trying to override

  • string property with empty string "",
  • list properties with non empty json arrays [9, 10] and ["ten", "nine"],
  • map properties with non empty json object {"nine": 9}
SPRING_APPLICATION_JSON = {
    "application": {
        "a": "",
        "b": [9,10],
        "c": ["ten", "nine"],
        "m": {"nine": 9}
    }
}
Expecting                    Actual
 a == ""                     a == ""
 b == [9,10]                 b == [9,10]
 c == ["ten","nine"]         c == ["ten","nine"]
 m == {"nine": 9}            m == {"one":1, "two":2, "nine":9}

Test case With Null values

application-test.yaml
application:
  a: "some string"
  b:
    - 1
    - 2
    - 3
  c:
    - "one"
    - "two"
    - "three"
  m:
    - one: 1
    - two: 2

We are trying to override

  • string property with null,
  • list properties with null,
  • map properties with null
SPRING_APPLICATION_JSON = {
    "application": {
        "a": null,
        "b": null,
        "c": null,
        "m": null
    }
}
Expecting                    Actual
 a == ""                     a == "some string"
 b == null | empty           b == [1,2,3]
 c == null | empty           c == ["one","two","three"]
 m == null | empty           m == {"one":1, "two":2}

@mbhave
Copy link
Contributor

mbhave commented Jun 1, 2020

I think this is because of the way flatten works. If the collection is empty, it skips adding the value. This looks like a bug to me. Let's see what the rest of the team thinks.

@mbhave mbhave added the for: team-attention An issue we'd like other members of the team to review label Jun 1, 2020
@philwebb philwebb added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged for: team-attention An issue we'd like other members of the team to review labels Jun 5, 2020
@philwebb philwebb added this to the 2.2.x milestone Jun 5, 2020
@mbhave mbhave added the for: team-attention An issue we'd like other members of the team to review label Aug 7, 2020
@mbhave mbhave self-assigned this Aug 7, 2020
@mbhave
Copy link
Contributor

mbhave commented Aug 11, 2020

We have decided to add the values specified by the user as is to the property source for SPRING_APPLICATION_JSON. For Collections, this means that [] will work as expected. For Maps, an empty map will be added to the property source. However, with the way the MapBinder currently works, an empty map will not be able to override a non-empty map. I've created a separate issue for that. Furthermore, any null values will be skipped by the MapPropertySource so we should document that.

@mbhave mbhave removed the for: team-attention An issue we'd like other members of the team to review label Aug 11, 2020
@mbhave mbhave closed this as completed in cdbb7f4 Aug 11, 2020
@mbhave mbhave modified the milestones: 2.2.x, 2.2.10 Aug 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

4 participants