Skip to content

Incorrect ConfigurationMetadataRepository when loaded from json files containing properties of the same group #25501

Closed
@brenuart

Description

@brenuart

Constructing a ConfigurationMetadataRepository from two distinct metadata file leads to incorrect results when the files contain properties that belong to the same group.
Here is a scenario to illustrate the case.

Suppose the two following spring-configuration-metadata files. As you can see, they hold properties of different names but they all belong to the same group:

----------
meta1.json
----------
{
  "groups": [
    {
      "name": "server",
      "type": "org.springframework.boot.autoconfigure.web.ServerProperties",
      "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties"
    }
  ],
  "properties": [
    {
      "name": "server.port",
      "type": "java.lang.Integer",
      "description": "Server HTTP port.",
      "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties"
    }
  ]
}

----------
meta2.json
----------
{
  "groups": [
    {
      "name": "server",
      "type": "org.springframework.boot.autoconfigure.web.ServerProperties",
      "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties"
    }
  ],
  "properties": [
    {
      "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties",
      "name": "server.address",
      "description": "Network address to which the server should bind to.",
      "type": "java.net.InetAddress"
    }
  ]
}

Now I try to read these two files into the same ConfigurationMetadataRepository as follows:

ConfigurationMetadataRepositoryJsonBuilder metadataBuilder = ConfigurationMetadataRepositoryJsonBuilder.create();
metadataBuilder.withJsonResource(new FileInputStream("meta1.json"));
metadataBuilder.withJsonResource(new FileInputStream("meta2.json"));

ConfigurationMetadataRepository metadata = metadataBuilder.build();

As shown below, #getAllProperties() returns both properties as expected, and #getAllGroups() returns the only server group. Listing the properties of that group correctly returns to two properties as well. All this seems to work as expected.

metadata.getAllProperties()    --> server.port
                                   server.address

metadata.getAllGroups()        --> server

"server group".getProperties() --> server.port
                                   server.address

The "server" group contains a single "source" (as expected). However, listing the properties of that single source returns only the server.port address, not both as I would expect.

"server group".getSources()                  --> server
"server group".getSources().getProperties()  --> server.port

As far as I understand the model the following should apply:

  • group.properties should contain all properties of all the sources
  • the union of all source.properties should match group.properties

The last assumption is not verified in my test scenario.

According to me the issue is in the merge logic implemented in SimpleConfigurationMetadata#include..
The repository already contains a "server" group when the second metadata file is loaded and the include method tries to merge the content of the new group into the existing one. This is done by adding the properties of the new group into the existing one if they are missing. When done, the logic goes further by "merging" the sources. However, the merge logic for the sources seems incorrect: their properties should be merged as well.

Stated differently, adding the following method should solve the issue:

private void putIfAbsent(Map<String, ConfigurationMetadataSource> sources, String name, ConfigurationMetadataSource source) {
  ConfigurationMetadataSource existing = sources.get(name);
  if (existing==null) {
    sources.put(name, source);
  }
  else {
    source.getProperties().forEach((k,v) -> putIfAbsent(existing.getProperties(), k, v));
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: supersededAn issue that has been superseded by another

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions