diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.java index a0152ed4478..f7223a9a1ce 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -107,6 +107,8 @@ public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfi /** Defaults to {@value #DEFAULT_VALUE_SEPARATOR} */ protected String valueSeparator = DEFAULT_VALUE_SEPARATOR; + protected boolean trimValues = false; + protected String nullValue; protected boolean ignoreUnresolvablePlaceholders = false; @@ -142,6 +144,16 @@ public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfi this.valueSeparator = valueSeparator; } + /** + * Specify whether to trim resolved values before applying them, + * removing superfluous whitespace from the beginning and end. + *

Default is {@code false}. + * @since 4.3 + */ + public void setTrimValues(boolean trimValues) { + this.trimValues = trimValues; + } + /** * Set a value that should be treated as {@code null} when resolved * as a placeholder value: e.g. "" (empty String) or "null". diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.java index f98ce40e608..a0243a3396d 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -255,8 +255,11 @@ public class PropertyPlaceholderConfigurer extends PlaceholderConfigurerSupport @Override public String resolveStringValue(String strVal) throws BeansException { - String value = this.helper.replacePlaceholders(strVal, this.resolver); - return (value.equals(nullValue) ? null : value); + String resolved = this.helper.replacePlaceholders(strVal, this.resolver); + if (trimValues) { + resolved = resolved.trim(); + } + return (resolved.equals(nullValue) ? null : resolved); } } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurerTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurerTests.java index 38a42d1d64e..903b34f1152 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurerTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2016 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. @@ -39,11 +39,10 @@ import static org.springframework.beans.factory.support.BeanDefinitionReaderUtil /** * Unit tests for {@link PropertyPlaceholderConfigurer}. * - * @see PropertySourcesPlaceholderConfigurerTests - * @see PropertyResourceConfigurerTests * @author Chris Beams */ public class PropertyPlaceholderConfigurerTests { + private static final String P1 = "p1"; private static final String P1_LOCAL_PROPS_VAL = "p1LocalPropsVal"; private static final String P1_SYSTEM_PROPS_VAL = "p1SystemPropsVal"; @@ -55,11 +54,12 @@ public class PropertyPlaceholderConfigurerTests { private AbstractBeanDefinition p1BeanDef; + @Before public void setUp() { p1BeanDef = rootBeanDefinition(TestBean.class) - .addPropertyValue("name", "${"+P1+"}") - .getBeanDefinition(); + .addPropertyValue("name", "${" + P1 + "}") + .getBeanDefinition(); bf = new DefaultListableBeanFactory(); @@ -97,9 +97,9 @@ public class PropertyPlaceholderConfigurerTests { public void resolveFromSystemProperties() { getModifiableSystemEnvironment().put("otherKey", "systemValue"); p1BeanDef = rootBeanDefinition(TestBean.class) - .addPropertyValue("name", "${"+P1+"}") - .addPropertyValue("sex", "${otherKey}") - .getBeanDefinition(); + .addPropertyValue("name", "${" + P1 + "}") + .addPropertyValue("sex", "${otherKey}") + .getBeanDefinition(); registerWithGeneratedName(p1BeanDef, bf); ppc.postProcessBeanFactory(bf); TestBean bean = bf.getBean(TestBean.class); @@ -167,9 +167,9 @@ public class PropertyPlaceholderConfigurerTests { String P2_SYSTEM_ENV_VAL = "p2SystemEnvVal"; AbstractBeanDefinition p2BeanDef = rootBeanDefinition(TestBean.class) - .addPropertyValue("name", "${"+P1+"}") - .addPropertyValue("country", "${"+P2+"}") - .getBeanDefinition(); + .addPropertyValue("name", "${" + P1 + "}") + .addPropertyValue("country", "${" + P2 + "}") + .getBeanDefinition(); bf.registerBeanDefinition("p1Bean", p1BeanDef); bf.registerBeanDefinition("p2Bean", p2BeanDef); @@ -238,6 +238,33 @@ public class PropertyPlaceholderConfigurerTests { getModifiableSystemEnvironment().remove("my.name"); } + @Test + public void trimValuesIsOffByDefault() { + PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); + getModifiableSystemEnvironment().put("my.name", " myValue "); + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerBeanDefinition("testBean", rootBeanDefinition(TestBean.class) + .addPropertyValue("name", "${my.name}") + .getBeanDefinition()); + ppc.postProcessBeanFactory(bf); + assertThat(bf.getBean(TestBean.class).getName(), equalTo(" myValue ")); + getModifiableSystemEnvironment().remove("my.name"); + } + + @Test + public void trimValuesIsApplied() { + PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); + ppc.setTrimValues(true); + getModifiableSystemEnvironment().put("my.name", " myValue "); + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerBeanDefinition("testBean", rootBeanDefinition(TestBean.class) + .addPropertyValue("name", "${my.name}") + .getBeanDefinition()); + ppc.postProcessBeanFactory(bf); + assertThat(bf.getBean(TestBean.class).getName(), equalTo("myValue")); + getModifiableSystemEnvironment().remove("my.name"); + } + @SuppressWarnings("unchecked") private static Map getModifiableSystemEnvironment() { @@ -253,7 +280,8 @@ public class PropertyPlaceholderConfigurerTests { if (obj != null && obj.getClass().getName().equals("java.lang.ProcessEnvironment$StringEnvironment")) { return (Map) obj; } - } catch (Exception ex) { + } + catch (Exception ex) { throw new RuntimeException(ex); } } @@ -263,8 +291,9 @@ public class PropertyPlaceholderConfigurerTests { Class processEnvironmentClass; try { processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment"); - } catch (Exception e) { - throw new RuntimeException(e); + } + catch (Exception ex) { + throw new RuntimeException(ex); } try { @@ -272,10 +301,12 @@ public class PropertyPlaceholderConfigurerTests { theCaseInsensitiveEnvironmentField.setAccessible(true); Object obj = theCaseInsensitiveEnvironmentField.get(null); return (Map) obj; - } catch (NoSuchFieldException e) { + } + catch (NoSuchFieldException ex) { // do nothing - } catch (Exception e) { - throw new RuntimeException(e); + } + catch (Exception ex) { + throw new RuntimeException(ex); } try { @@ -283,10 +314,12 @@ public class PropertyPlaceholderConfigurerTests { theEnvironmentField.setAccessible(true); Object obj = theEnvironmentField.get(null); return (Map) obj; - } catch (NoSuchFieldException e) { + } + catch (NoSuchFieldException ex) { // do nothing - } catch (Exception e) { - throw new RuntimeException(e); + } + catch (Exception ex) { + throw new RuntimeException(ex); } throw new IllegalStateException(); diff --git a/spring-context/src/main/java/org/springframework/context/config/PropertyPlaceholderBeanDefinitionParser.java b/spring-context/src/main/java/org/springframework/context/config/PropertyPlaceholderBeanDefinitionParser.java index f280159728a..cb38e6b0256 100644 --- a/spring-context/src/main/java/org/springframework/context/config/PropertyPlaceholderBeanDefinitionParser.java +++ b/spring-context/src/main/java/org/springframework/context/config/PropertyPlaceholderBeanDefinitionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -69,7 +69,9 @@ class PropertyPlaceholderBeanDefinitionParser extends AbstractPropertyLoadingBea if (element.hasAttribute("value-separator")) { builder.addPropertyValue("valueSeparator", element.getAttribute("value-separator")); } - + if (element.hasAttribute("trim-values")) { + builder.addPropertyValue("trimValues", element.getAttribute("trim-values")); + } if (element.hasAttribute("null-value")) { builder.addPropertyValue("nullValue", element.getAttribute("null-value")); } diff --git a/spring-context/src/main/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurer.java b/spring-context/src/main/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurer.java index 577eb93fdab..4a12a31e662 100644 --- a/spring-context/src/main/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurer.java +++ b/spring-context/src/main/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -167,9 +167,12 @@ public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerS StringValueResolver valueResolver = new StringValueResolver() { @Override public String resolveStringValue(String strVal) { - String resolved = ignoreUnresolvablePlaceholders ? + String resolved = (ignoreUnresolvablePlaceholders ? propertyResolver.resolvePlaceholders(strVal) : - propertyResolver.resolveRequiredPlaceholders(strVal); + propertyResolver.resolveRequiredPlaceholders(strVal)); + if (trimValues) { + resolved = resolved.trim(); + } return (resolved.equals(nullValue) ? null : resolved); } }; diff --git a/spring-context/src/main/resources/org/springframework/context/config/spring-context-4.3.xsd b/spring-context/src/main/resources/org/springframework/context/config/spring-context-4.3.xsd index 0a3c1952e03..c7439e98455 100644 --- a/spring-context/src/main/resources/org/springframework/context/config/spring-context-4.3.xsd +++ b/spring-context/src/main/resources/org/springframework/context/config/spring-context-4.3.xsd @@ -149,6 +149,14 @@ + + + + + diff --git a/spring-context/src/test/java/org/springframework/context/config/ContextNamespaceHandlerTests.java b/spring-context/src/test/java/org/springframework/context/config/ContextNamespaceHandlerTests.java index e6a3b30443c..ba04db4931b 100644 --- a/spring-context/src/test/java/org/springframework/context/config/ContextNamespaceHandlerTests.java +++ b/spring-context/src/test/java/org/springframework/context/config/ContextNamespaceHandlerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -18,14 +18,10 @@ package org.springframework.context.config; import java.util.Calendar; import java.util.Date; -import java.util.Map; import org.junit.After; import org.junit.Test; -import org.springframework.beans.factory.config.PlaceholderConfigurerSupport; -import org.springframework.beans.factory.config.PropertyOverrideConfigurer; -import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.GenericXmlApplicationContext; @@ -53,9 +49,6 @@ public class ContextNamespaceHandlerTests { public void propertyPlaceholder() throws Exception { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "contextNamespaceHandlerTests-replace.xml", getClass()); - Map beans = applicationContext - .getBeansOfType(PlaceholderConfigurerSupport.class); - assertFalse("No PropertyPlaceholderConfigurer found", beans.isEmpty()); assertEquals("bar", applicationContext.getBean("string")); assertEquals("null", applicationContext.getBean("nullString")); } @@ -66,9 +59,6 @@ public class ContextNamespaceHandlerTests { try { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "contextNamespaceHandlerTests-system.xml", getClass()); - Map beans = applicationContext - .getBeansOfType(PropertyPlaceholderConfigurer.class); - assertFalse("No PropertyPlaceholderConfigurer found", beans.isEmpty()); assertEquals("spam", applicationContext.getBean("string")); assertEquals("none", applicationContext.getBean("fallback")); } @@ -86,9 +76,6 @@ public class ContextNamespaceHandlerTests { applicationContext.setEnvironment(env); applicationContext.load(new ClassPathResource("contextNamespaceHandlerTests-simple.xml", getClass())); applicationContext.refresh(); - Map beans = applicationContext - .getBeansOfType(PlaceholderConfigurerSupport.class); - assertFalse("No PropertyPlaceholderConfigurer found", beans.isEmpty()); assertEquals("spam", applicationContext.getBean("string")); assertEquals("none", applicationContext.getBean("fallback")); } @@ -97,9 +84,6 @@ public class ContextNamespaceHandlerTests { public void propertyPlaceholderLocation() throws Exception { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "contextNamespaceHandlerTests-location.xml", getClass()); - Map beans = applicationContext - .getBeansOfType(PropertyPlaceholderConfigurer.class); - assertFalse("No PropertyPlaceholderConfigurer found", beans.isEmpty()); assertEquals("bar", applicationContext.getBean("foo")); assertEquals("foo", applicationContext.getBean("bar")); assertEquals("maps", applicationContext.getBean("spam")); @@ -109,9 +93,6 @@ public class ContextNamespaceHandlerTests { public void propertyPlaceholderIgnored() throws Exception { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "contextNamespaceHandlerTests-replace-ignore.xml", getClass()); - Map beans = applicationContext - .getBeansOfType(PlaceholderConfigurerSupport.class); - assertFalse("No PropertyPlaceholderConfigurer found", beans.isEmpty()); assertEquals("${bar}", applicationContext.getBean("string")); assertEquals("null", applicationContext.getBean("nullString")); } @@ -120,9 +101,6 @@ public class ContextNamespaceHandlerTests { public void propertyOverride() throws Exception { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "contextNamespaceHandlerTests-override.xml", getClass()); - Map beans = applicationContext - .getBeansOfType(PropertyOverrideConfigurer.class); - assertFalse("No PropertyOverrideConfigurer found", beans.isEmpty()); Date date = (Date) applicationContext.getBean("date"); Calendar calendar = Calendar.getInstance(); calendar.setTime(date); diff --git a/spring-context/src/test/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurerTests.java b/spring-context/src/test/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurerTests.java index e11ae4769bb..030446306fe 100644 --- a/spring-context/src/test/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurerTests.java +++ b/spring-context/src/test/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2016 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,6 +16,7 @@ package org.springframework.context.support; +import java.util.Optional; import java.util.Properties; import org.junit.Rule; @@ -24,6 +25,7 @@ import org.junit.rules.ExpectedException; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySource; import org.springframework.core.env.StandardEnvironment; @@ -39,6 +41,7 @@ import static org.springframework.beans.factory.support.BeanDefinitionBuilder.*; /** * @author Chris Beams + * @author Juergen Hoeller * @since 3.1 */ public class PropertySourcesPlaceholderConfigurerTests { @@ -46,6 +49,7 @@ public class PropertySourcesPlaceholderConfigurerTests { @Rule public ExpectedException thrown = ExpectedException.none(); + @Test public void replacementFromEnvironmentProperties() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); @@ -57,8 +61,7 @@ public class PropertySourcesPlaceholderConfigurerTests { MockEnvironment env = new MockEnvironment(); env.setProperty("my.name", "myValue"); - PropertySourcesPlaceholderConfigurer ppc = - new PropertySourcesPlaceholderConfigurer(); + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); ppc.setEnvironment(env); ppc.postProcessBeanFactory(bf); assertThat(bf.getBean(TestBean.class).getName(), equalTo("myValue")); @@ -73,10 +76,10 @@ public class PropertySourcesPlaceholderConfigurerTests { .addPropertyValue("name", "${my.name}") .getBeanDefinition()); - PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer(); + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); Resource resource = new ClassPathResource("PropertySourcesPlaceholderConfigurerTests.properties", this.getClass()); - pc.setLocation(resource); - pc.postProcessBeanFactory(bf); + ppc.setLocation(resource); + ppc.postProcessBeanFactory(bf); assertThat(bf.getBean(TestBean.class).getName(), equalTo("foo")); } @@ -101,11 +104,11 @@ public class PropertySourcesPlaceholderConfigurerTests { MutablePropertySources propertySources = new MutablePropertySources(); propertySources.addLast(new MockPropertySource().withProperty("my.name", "foo")); - PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer(); - pc.setPropertySources(propertySources); - pc.postProcessBeanFactory(bf); + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + ppc.setPropertySources(propertySources); + ppc.postProcessBeanFactory(bf); assertThat(bf.getBean(TestBean.class).getName(), equalTo("foo")); - assertEquals(pc.getAppliedPropertySources().iterator().next(), propertySources.iterator().next()); + assertEquals(ppc.getAppliedPropertySources().iterator().next(), propertySources.iterator().next()); } @Test @@ -119,13 +122,13 @@ public class PropertySourcesPlaceholderConfigurerTests { MutablePropertySources propertySources = new MutablePropertySources(); propertySources.addLast(new MockPropertySource()); - PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer(); - pc.setPropertySources(propertySources); - pc.setEnvironment(new MockEnvironment().withProperty("my.name", "env")); - pc.setIgnoreUnresolvablePlaceholders(true); - pc.postProcessBeanFactory(bf); + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + ppc.setPropertySources(propertySources); + ppc.setEnvironment(new MockEnvironment().withProperty("my.name", "env")); + ppc.setIgnoreUnresolvablePlaceholders(true); + ppc.postProcessBeanFactory(bf); assertThat(bf.getBean(TestBean.class).getName(), equalTo("${my.name}")); - assertEquals(pc.getAppliedPropertySources().iterator().next(), propertySources.iterator().next()); + assertEquals(ppc.getAppliedPropertySources().iterator().next(), propertySources.iterator().next()); } @Test @@ -140,17 +143,17 @@ public class PropertySourcesPlaceholderConfigurerTests { MutablePropertySources propertySources = new MutablePropertySources(); propertySources.addLast(new MockPropertySource()); - PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer(); - pc.setPropertySources(propertySources); - pc.setProperties(new Properties() {{ + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + ppc.setPropertySources(propertySources); + ppc.setProperties(new Properties() {{ put("my.name", "local"); }}); - pc.setIgnoreUnresolvablePlaceholders(true); - pc.postProcessBeanFactory(bf); + ppc.setIgnoreUnresolvablePlaceholders(true); + ppc.postProcessBeanFactory(bf); assertThat(bf.getBean(TestBean.class).getName(), equalTo("${my.name}")); } - @Test(expected=BeanDefinitionStoreException.class) + @Test(expected = BeanDefinitionStoreException.class) public void ignoreUnresolvablePlaceholders_falseIsDefault() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); bf.registerBeanDefinition("testBean", @@ -158,9 +161,9 @@ public class PropertySourcesPlaceholderConfigurerTests { .addPropertyValue("name", "${my.name}") .getBeanDefinition()); - PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer(); + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); //pc.setIgnoreUnresolvablePlaceholders(false); // the default - pc.postProcessBeanFactory(bf); // should throw + ppc.postProcessBeanFactory(bf); // should throw } @Test @@ -171,13 +174,13 @@ public class PropertySourcesPlaceholderConfigurerTests { .addPropertyValue("name", "${my.name}") .getBeanDefinition()); - PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer(); - pc.setIgnoreUnresolvablePlaceholders(true); - pc.postProcessBeanFactory(bf); + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + ppc.setIgnoreUnresolvablePlaceholders(true); + ppc.postProcessBeanFactory(bf); assertThat(bf.getBean(TestBean.class).getName(), equalTo("${my.name}")); } - @Test(expected=BeanDefinitionStoreException.class) + @Test(expected = BeanDefinitionStoreException.class) @SuppressWarnings("serial") public void nestedUnresolvablePlaceholder() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); @@ -186,11 +189,11 @@ public class PropertySourcesPlaceholderConfigurerTests { .addPropertyValue("name", "${my.name}") .getBeanDefinition()); - PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer(); - pc.setProperties(new Properties() {{ + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + ppc.setProperties(new Properties() {{ put("my.name", "${bogus}"); }}); - pc.postProcessBeanFactory(bf); // should throw + ppc.postProcessBeanFactory(bf); // should throw } @Test @@ -202,12 +205,12 @@ public class PropertySourcesPlaceholderConfigurerTests { .addPropertyValue("name", "${my.name}") .getBeanDefinition()); - PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer(); - pc.setProperties(new Properties() {{ + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + ppc.setProperties(new Properties() {{ put("my.name", "${bogus}"); }}); - pc.setIgnoreUnresolvablePlaceholders(true); - pc.postProcessBeanFactory(bf); + ppc.setIgnoreUnresolvablePlaceholders(true); + ppc.postProcessBeanFactory(bf); assertThat(bf.getBean(TestBean.class).getName(), equalTo("${bogus}")); } @@ -295,6 +298,31 @@ public class PropertySourcesPlaceholderConfigurerTests { assertThat(bf.getBean(TestBean.class).getName(), nullValue()); } + @Test + public void trimValuesIsOffByDefault() { + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerBeanDefinition("testBean", rootBeanDefinition(TestBean.class) + .addPropertyValue("name", "${my.name}") + .getBeanDefinition()); + ppc.setEnvironment(new MockEnvironment().withProperty("my.name", " myValue ")); + ppc.postProcessBeanFactory(bf); + assertThat(bf.getBean(TestBean.class).getName(), equalTo(" myValue ")); + } + + @Test + public void trimValuesIsApplied() { + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + ppc.setTrimValues(true); + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerBeanDefinition("testBean", rootBeanDefinition(TestBean.class) + .addPropertyValue("name", "${my.name}") + .getBeanDefinition()); + ppc.setEnvironment(new MockEnvironment().withProperty("my.name", " myValue ")); + ppc.postProcessBeanFactory(bf); + assertThat(bf.getBean(TestBean.class).getName(), equalTo("myValue")); + } + @Test public void getAppliedPropertySourcesTooEarly() throws Exception { PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); @@ -308,7 +336,7 @@ public class PropertySourcesPlaceholderConfigurerTests { PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); ClassPathResource doesNotHave = new ClassPathResource("test.properties", getClass()); ClassPathResource setToTrue = new ClassPathResource("placeholder.properties", getClass()); - ppc.setLocations(new Resource[] { doesNotHave, setToTrue }); + ppc.setLocations(doesNotHave, setToTrue); ppc.setIgnoreResourceNotFound(true); ppc.setIgnoreUnresolvablePlaceholders(true); DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); @@ -320,4 +348,57 @@ public class PropertySourcesPlaceholderConfigurerTests { assertThat(bf.getBean(TestBean.class).isJedi(), equalTo(true)); } + @Test + public void optionalPropertyWithValue() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.setConversionService(new DefaultConversionService()); + bf.registerBeanDefinition("testBean", + genericBeanDefinition(OptionalTestBean.class) + .addPropertyValue("name", "${my.name}") + .getBeanDefinition()); + + MockEnvironment env = new MockEnvironment(); + env.setProperty("my.name", "myValue"); + + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + ppc.setEnvironment(env); + ppc.setIgnoreUnresolvablePlaceholders(true); + ppc.postProcessBeanFactory(bf); + assertThat(bf.getBean(OptionalTestBean.class).getName(), equalTo(Optional.of("myValue"))); + } + + @Test + public void optionalPropertyWithoutValue() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.setConversionService(new DefaultConversionService()); + bf.registerBeanDefinition("testBean", + genericBeanDefinition(OptionalTestBean.class) + .addPropertyValue("name", "${my.name}") + .getBeanDefinition()); + + MockEnvironment env = new MockEnvironment(); + env.setProperty("my.name", ""); + + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + ppc.setEnvironment(env); + ppc.setIgnoreUnresolvablePlaceholders(true); + ppc.setNullValue(""); + ppc.postProcessBeanFactory(bf); + assertThat(bf.getBean(OptionalTestBean.class).getName(), equalTo(Optional.empty())); + } + + + private static class OptionalTestBean { + + private Optional name; + + public Optional getName() { + return name; + } + + public void setName(Optional name) { + this.name = name; + } + } + } diff --git a/spring-context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-location.xml b/spring-context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-location.xml index e90a5e42b34..f6a4be6fc05 100644 --- a/spring-context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-location.xml +++ b/spring-context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-location.xml @@ -2,12 +2,12 @@ + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> + file-encoding="ISO-8859-1" trim-values="true"/> diff --git a/spring-context/src/test/resources/org/springframework/context/config/test-bar.properties b/spring-context/src/test/resources/org/springframework/context/config/test-bar.properties index b0e291695e7..6d7afb4ec9f 100644 --- a/spring-context/src/test/resources/org/springframework/context/config/test-bar.properties +++ b/spring-context/src/test/resources/org/springframework/context/config/test-bar.properties @@ -1,2 +1,2 @@ -bar=foo -spam=maps +bar= foo\t +spam=\tmaps