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

Support null values when binding properties #24133

Open
chengaofeng opened this issue Nov 12, 2020 · 8 comments
Open

Support null values when binding properties #24133

chengaofeng opened this issue Nov 12, 2020 · 8 comments
Labels
type: enhancement A general enhancement

Comments

@chengaofeng
Copy link

chengaofeng commented Nov 12, 2020

Application has a ben annotated with@ConfigurationProperties("test") that has a List<String> attribute called users. at the beginning, one item listed in the external configuration file

test:
  users:
  - Andy

as the application is running, change the configuration file to the following

test:
  users:

or

test:
  users: null

what I expect is users=null or users =[], while the result is still users[0]=Andy

it‘s ok for the following pattern :

test:
  users: ""

Here's a test that fails with Spring Boot 2.1.17.RELEASE

@SpringBootTest(classes=ConfigPropertiesTest.class)
@RunWith(SpringRunner.class)
@EnableConfigurationProperties(ConfigPropertiesTest.TestProperties.class)
@TestPropertySource(properties = {"test.users[0]=Andy"})
public class ConfigPropertiesTest {

    @Autowired
    private TestProperties properties;

    @Autowired
    private ConfigurationPropertiesBindingPostProcessor processor;

    @Autowired
    private ConfigurableEnvironment environment;

    @Test
    public void liveRebindToNull() throws Exception {
        assertEquals(properties.getUsers().get(0),"Andy");
        setNullProperties("test.users");
	assertTrue(environment.getPropertySources().get("test").containsProperty("test.users"));;
        assertNull(environment.getPropertySources().get("test").getProperty("test.users"));
        processor.postProcessBeforeInitialization(properties, "testProperties");
        assertEquals(properties.getUsers().size(), 0); //**_TEST NG_**
    }

    /**
     * TestPropertyValues has no public method set null value, using reflect to do it
     * 
     * @param prefix
     * @throws Exception
     */
    private void setNullProperties(String prefix) throws Exception {
        TestPropertyValues testPropertyValues =  TestPropertyValues.empty();
        Method method = TestPropertyValues.class.getDeclaredMethod("and", Stream.class);
        method.setAccessible(true);

        TestPropertyValues.Pair pair = new TestPropertyValues.Pair(prefix,null);
        testPropertyValues = (TestPropertyValues) method.invoke(testPropertyValues, Stream.of(pair));

        testPropertyValues.applyTo(environment);
    }

    @ConfigurationProperties("test")
    public static class TestProperties {

        private List<String> users;

        public List<String> getUsers() {
            return users;
        }

        public void setUsers(List<String> users) {
            this.users = users;
        }
    }
}
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Nov 12, 2020
@wilkinsona
Copy link
Member

Spring Boot does not support the reloading of properties at runtime. You may be interested in Spring Cloud's support for changing the environment and its refresh scope.

@wilkinsona wilkinsona added status: invalid An issue that we don't feel is valid and removed status: waiting-for-triage An issue we've not yet triaged labels Nov 12, 2020
@chengaofeng
Copy link
Author

chengaofeng commented Nov 14, 2020

I am sorry not make myself clear.My project is indeed a spring cloud application, The Properties bean is also annotated by @RefreshScope.While The config server is alibaba‘s nacos. When I change the external config file as above(set the value to null), the properties's value didn't change as expect.

In debug mode, when the external config file changed from

test:
  users:
  - Andy

to

test:
  users:

I can find that the propertySource in Environment#propertySources#propertySourceList changed to test.users => null, and then an EnvironmentChangeEvent published. but after the ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization method invoked, the value of the users in the Properties bean is still users[0]=Andy

Then I dig into the source of

org.springframework.boot.context.properties.source.SpringConfigurationPropertySource#find(PropertyMapping mapping)

private ConfigurationProperty find(PropertyMapping mapping) {
	String propertySourceName = mapping.getPropertySourceName();
	Object value = getPropertySource().getProperty(propertySourceName);
	if (value == null) {
		return null;
	}
	...
}	

when the value is null, the method is return null, which means no such item. while in my situation,set test.users=>null is different from not configuring at all

Spring Cloud version: Hoxton.SR8
Spring Boot version: 2.2.5.RELEASE

@wilkinsona,I'm appreciate that you could take a look at this problem again.

@wilkinsona wilkinsona reopened this Nov 14, 2020
@wilkinsona wilkinsona added for: team-attention An issue we'd like other members of the team to review status: waiting-for-feedback We need additional information before we can continue and removed status: invalid An issue that we don't feel is valid labels Nov 14, 2020
@philwebb
Copy link
Member

philwebb commented Nov 16, 2020

See spring-projects/spring-framework#25142 for background on null values in a MapPropertySource and #21542 (comment) for a previous Boot issue.

@philwebb philwebb added type: enhancement A general enhancement and removed for: team-attention An issue we'd like other members of the team to review status: waiting-for-feedback We need additional information before we can continue labels Nov 16, 2020
@philwebb philwebb added this to the General Backlog milestone Nov 16, 2020
@philwebb
Copy link
Member

This is a limitation of the way that null is handled both in Boot and Spring Framework. I'm afraid the fix for this will be quite involved and is unlikely to happen soon.

@philwebb philwebb changed the title ConfigurationProperties Cannot be cleared at runtime in some situation Support null values when binding properties Nov 16, 2020
@wilkinsona
Copy link
Member

#28139 describes another use case for being able to clear the value of a property somehow.

@wilkinsona
Copy link
Member

#31037 is another case of #28139.

@Sroca3
Copy link

Sroca3 commented Apr 10, 2024

@philwebb do you know what all is needed to get this fixed? If spring-projects/spring-framework#19986 is addressed, would it be easy for spring-boot to support nulls? Trying to see how to move this forward.

@wilkinsona
Copy link
Member

It's not just spring-projects/spring-framework#19986. Spring Framework's Environment abstraction would also have to be able to distinguish between an absent property and a property with a null value. spring-projects/spring-framework#25142 was opened to explore this but it was effectively rejected and turned into a documentation issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

5 participants