diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassWithPlaceholderConfigurerBeanTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassWithPlaceholderConfigurerBeanTests.java index 3c8d933d06..e628f4ff23 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassWithPlaceholderConfigurerBeanTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassWithPlaceholderConfigurerBeanTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,6 @@ package org.springframework.context.annotation.configuration; -import org.junit.Ignore; import org.junit.Test; import org.springframework.beans.factory.annotation.Value; @@ -31,28 +30,37 @@ import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; /** - * A configuration class that registers a placeholder configurer @Bean method - * cannot also have @Value fields. Logically, the config class must be instantiated - * in order to invoke the placeholder configurer bean method, and it is a - * chicken-and-egg problem to process the @Value field. + * A configuration class that registers a non-static placeholder configurer {@code @Bean} + * method cannot also have {@code @Value} fields. Logically, the config class must be + * instantiated in order to invoke the placeholder configurer bean method, and it is a + * chicken-and-egg problem to process the {@code @Value} field. * - * Therefore, placeholder configurers should be put in separate configuration classes - * as has been done in the test below. Simply said, placeholder configurer @Bean methods - * and @Value fields in the same configuration class are mutually exclusive. + *

Therefore, placeholder configurer bean methods should either be {@code static} or + * put in separate configuration classes as has been done in the tests below. Simply said, + * placeholder configurer {@code @Bean} methods and {@code @Value} fields in the same + * configuration class are mutually exclusive unless the placeholder configurer + * {@code @Bean} method is {@code static}. * * @author Chris Beams * @author Juergen Hoeller + * @author Sam Brannen */ public class ConfigurationClassWithPlaceholderConfigurerBeanTests { /** - * Intentionally ignored test proving that a property placeholder bean - * cannot be declared in the same configuration class that has a @Value - * field in need of placeholder replacement. It's an obvious chicken-and-egg issue. - * The solution is to do as {@link #valueFieldsAreProcessedWhenPlaceholderConfigurerIsSegregated()} + * Test which proves that a non-static property placeholder bean cannot be declared + * in the same configuration class that has a {@code @Value} field in need of + * placeholder replacement. It's an obvious chicken-and-egg issue. + * + *

One solution is to do as {@link #valueFieldsAreProcessedWhenPlaceholderConfigurerIsSegregated()} * does and segregate the two bean definitions across configuration classes. + * + *

Another solution is to simply make the {@code @Bean} method for the property + * placeholder {@code static} as in + * {@link #valueFieldsAreProcessedWhenStaticPlaceholderConfigurerIsIntegrated()}. */ - @Ignore @Test + @Test + @SuppressWarnings("resource") public void valueFieldsAreNotProcessedWhenPlaceholderConfigurerIsIntegrated() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(ConfigWithValueFieldAndPlaceholderConfigurer.class); @@ -61,10 +69,25 @@ public class ConfigurationClassWithPlaceholderConfigurerBeanTests { System.clearProperty("test.name"); TestBean testBean = ctx.getBean(TestBean.class); + // Proof that the @Value field did not get set: assertThat(testBean.getName(), nullValue()); } @Test + @SuppressWarnings("resource") + public void valueFieldsAreProcessedWhenStaticPlaceholderConfigurerIsIntegrated() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(ConfigWithValueFieldAndStaticPlaceholderConfigurer.class); + System.setProperty("test.name", "foo"); + ctx.refresh(); + System.clearProperty("test.name"); + + TestBean testBean = ctx.getBean(TestBean.class); + assertThat(testBean.getName(), equalTo("foo")); + } + + @Test + @SuppressWarnings("resource") public void valueFieldsAreProcessedWhenPlaceholderConfigurerIsSegregated() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(ConfigWithValueField.class); @@ -78,7 +101,8 @@ public class ConfigurationClassWithPlaceholderConfigurerBeanTests { } @Test - public void valueFieldsResolveToPlaceholderSpecifiedDefaultValue() { + @SuppressWarnings("resource") + public void valueFieldsResolveToPlaceholderSpecifiedDefaultValuesWithPlaceholderConfigurer() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(ConfigWithValueField.class); ctx.register(ConfigWithPlaceholderConfigurer.class); @@ -88,6 +112,18 @@ public class ConfigurationClassWithPlaceholderConfigurerBeanTests { assertThat(testBean.getName(), equalTo("bar")); } + @Test + @SuppressWarnings("resource") + public void valueFieldsResolveToPlaceholderSpecifiedDefaultValuesWithoutPlaceholderConfigurer() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(ConfigWithValueField.class); + // ctx.register(ConfigWithPlaceholderConfigurer.class); + ctx.refresh(); + + TestBean testBean = ctx.getBean(TestBean.class); + assertThat(testBean.getName(), equalTo("bar")); + } + @Configuration static class ConfigWithValueField { @@ -129,4 +165,21 @@ public class ConfigurationClassWithPlaceholderConfigurerBeanTests { } } + @Configuration + static class ConfigWithValueFieldAndStaticPlaceholderConfigurer { + + @Value("${test.name}") + private String name; + + @Bean + public ITestBean testBean() { + return new TestBean(this.name); + } + + @Bean + public static PropertySourcesPlaceholderConfigurer ppc() { + return new PropertySourcesPlaceholderConfigurer(); + } + } + }