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

Change to placeholder value in XML is not reevaluated at runtime #25022

Closed
quaff opened this issue May 7, 2020 · 6 comments
Closed

Change to placeholder value in XML is not reevaluated at runtime #25022

quaff opened this issue May 7, 2020 · 6 comments
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: documentation A documentation task
Milestone

Comments

@quaff
Copy link
Contributor

quaff commented May 7, 2020

package com.example;
public class PlainBean {
	private int value;
	public int getValue() {
		return value;
	}
	public void setValue(int value) {
		this.value = value;
	}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans default-autowire="byName"
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	https://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer" />
	<bean class="com.example.PlainBean" p:value="${value:10}" scope="prototype" />
</beans>
@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "ctx.xml")
public class PlainBeanTest {
	@Autowired
	private ApplicationContext ctx;
	@Test
	public void test() {
		assertEquals(10, ctx.getBean(PlainBean.class).getValue()); // default value
		((ConfigurableEnvironment) ctx.getEnvironment()).getPropertySources()
				.addFirst(new MapPropertySource("overriden", Collections.singletonMap("value", "12")));
		assertEquals(12, ctx.getBean(PlainBean.class).getValue()); // test failed
	}
}

But test will pass if using @Value("${value:10}") instead of p:value="${value:10}" , here is test project ps.zip

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label May 7, 2020
@sbrannen sbrannen changed the title Placeholder in xml cannot sense change of property source at runtime Change to placeholder value in XML is not reevaluated at runtime May 7, 2020
@sbrannen sbrannen added type: documentation A documentation task and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels May 7, 2020
@sbrannen sbrannen added this to the 5.2.7 milestone May 7, 2020
@sbrannen
Copy link
Member

sbrannen commented May 7, 2020

Thanks for raising the issue.

Your analysis is correct: placeholder values in XML are evaluated only once.

This is by design.

Consequently, we are labeling this issue as a documentation issue to improve the documentation for such scenarios.

@quaff
Copy link
Contributor Author

quaff commented May 8, 2020

It's weird that not keep consistency between xml and annotation, is there any workaround to fix this? I'm using spring-batch and configure job in xml, migration is hard and risky, but changing job behavior at runtime is quite desired.

@jhoeller
Copy link
Contributor

jhoeller commented May 8, 2020

It's rather the other way round: ${...} placeholders are fundamentally static, meant to be resolved once-only ever since they have been introduced in the XML bean definition format (where they get resolved in a dedicated metadata post-process step on startup).

@Value supports such placeholders as well but in the course of annotation values where it falls back to on-demand resolution which effectively results in later resolution than with XML. This is technically not consistent with XML indeed (unavoidably since there is no metadata post-process step for annotation-contained values), however, those placeholders are not meant to change anyway, so the effect should not matter per the original design of such placeholders.

Note that #{...} expressions are dynamic by design and always evaluated on-demand - in XML and annotation values. For values that are expected to change at runtime, that's the recommended approach.

@quaff
Copy link
Contributor Author

quaff commented May 8, 2020

Thanks for elaboration. I found only systemProperties are predefined, please guide me how to refer Environment in spel, such as #{env.getProperty('parts','10')}

UPDATED: I found #{@environment.getProperty('parts','10')} works.
UPDATED: #{environment['parts']?:10} is much better.

@jhoeller jhoeller added the in: core Issues in core modules (aop, beans, core, context, expression) label May 8, 2020
@sbrannen
Copy link
Member

UPDATED: #{environment['parts']?:10} is much better.

Yes, that would be the recommended approach to dynamically accessing an environment variable with a default, fallback value.

I'm using spring-batch and configure job in xml, migration is hard and risky, but changing job behavior at runtime is quite desired.

Have you considered using Spring Batch's step scope and/or accessing job parameters via a SpEL expression? Perhaps @mminella can provide further insight here.

@quaff
Copy link
Contributor Author

quaff commented May 11, 2020

UPDATED: #{environment['parts']?:10} is much better.

Yes, that would be the recommended approach to dynamically accessing an environment variable with a default, fallback value.

I'm using spring-batch and configure job in xml, migration is hard and risky, but changing job behavior at runtime is quite desired.

Have you considered using Spring Batch's step scope and/or accessing job parameters via a SpEL expression? Perhaps @mminella can provide further insight here.

Thanks, my puzzle is resolved by #{environment['parts']?:10} and step scope.

@quaff quaff closed this as completed May 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: documentation A documentation task
Projects
None yet
Development

No branches or pull requests

4 participants