Spring-boot: Empty YAML array does not override property from source with lower precedence

Created on 25 Apr 2018  路  7Comments  路  Source: spring-projects/spring-boot

SpringBoot version - 1.5.10.RELEASE
I'm using Spring Centralized Configuration to store my application configuration and it works fine for single valued properties but for MultiValued properties remote config is not able to override local properties.

remote config file: test-cloud-config.yml

test:
  empty:
    strKey: 
    listKey: []

SpringBoot resource local: application.yml

test:
  empty:
    strKey: local str Key
    listKey: localOne, localTwo

My spring boot class:-

@Component
public class TestRemoteConfig {

    @Value("${test.empty.strKey}")
    private String testEmptyStrKey;

    @Value("${test.empty.listKey}")
    private String[] testEmptyListKey;

    @PostConstruct
    public void init(){
        System.out.println("Test override EmptyStrKey's value :- "+ testEmptyStrKey);
        System.out.println("Test override EmptyListKey's value :- "+ Arrays.asList(testEmptyListKey));
    }

}

Output

Test override EmptyStrKey's value :- 
Test override EmptyListKey's value :- [localOne, localTwo]

but I expect 'testEmptyListKey' to be empty.

Note: This works when I use .properties in place of .yml as config file

bug

All 7 comments

Thanks for the report. I think this is a bug in Spring Framework's YamlPropertiesFactoryBean. When it's flattening the runtime representation of a YAML document into Properties, a collection that's empty is lost. You can avoid that behaviour by using an empty value instead of an empty array value:

test:
  empty:
    strKey: 
    listKey:

I've opened SPR-16769. If the Framework team agree with my assessment, we'll pick up a fix in due course. In the meantime, please use the alternative described above.

@wilkinsona - Thanks for the quick response and advice. However I can not use empty values because there are validation for property value in my project for cron sequence and the property is array of nested objects in actual
e.g

test:
  empty: 
    listKey:
     -
       name: foo
       type: fooType
       schedule: "0 0-58/2 * * * *"
       param:
         type: fooPramType
         count: 100

please let me know if I can use other alternative in this case

I can't think of a way for this to work where the list is of objects rather than scalars. I also don't think the likely fix for SPR-16769 will help.

This works when I use .properties in place of .yml as config file

I can't see how that can be the case with a list of objects that you're actually trying to use.

I'll re-open this issue so that we can investigate further, but we'll only be able to do so if you can provide a sample that demonstrates the actual problem that you're trying to solve. Note that there's no need to involve a remote config server, you can use local configuration files and local profile-specific configuration files instead. The profile-specific file should override in that case.

sorry for confusion, my statement-

This works when I use .properties in place of .yml as config file

was for the very first example in this thread where I'm trying to show the sample situation with scalers and I will use your advise to solve issue with scalers.(refer below example)

test:
  empty:
    strKey: local str Key
    listKey: localOne, localTwo

but the main issue is when I deal with nested Objects.. (refer below example). which I'm still unable to solve with yml. (I haven't tried .properties for this and will not able to do that as well)

test:
  empty: 
    listKey:
     -
       name: foo
       type: fooType
       schedule: "0 0-58/2 * * * *"
       param:
         type: fooPramType
         count: 100

Thanks for the clarification, @gautamceg. That means that SPR-16769 alone won't be enough to fix this problem. I believe that @snicoll only plans to fix the Framework issue in 5.0.x so we'll only be able to tackle this in Boot 2.0.x at the earliest.

As things stand, I'm not sure what we can do to fix this. When using @Value there's nothing we can do as we don't have any control over the binding there. I suspect a similar problem exists when using @ConfigurationProperties so we may be able to do something in Boot's binder so that an empty String can be mapped to an empty List.

I've labelled this for team attention to see if the rest of the team think we should be trying to fix this, and if so, to get some suggestions on what the best approach may be.

I think being able to replace a higher level value with an empty list is pretty important. At least of the binder support we should try to support that.

Was this page helpful?
0 / 5 - 0 ratings