util:properties supports multiple resource locations and ignore-resource-not-found

Issue: SPR-10614
This commit is contained in:
Juergen Hoeller 2014-08-20 16:31:54 +02:00
parent e48c315ad1
commit 662d8aa9f1
4 changed files with 106 additions and 50 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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.
@ -120,12 +120,14 @@ public class UtilNamespaceHandler extends NamespaceHandlerSupport {
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
String listClass = element.getAttribute("list-class");
List<Object> parsedList = parserContext.getDelegate().parseListElement(element, builder.getRawBeanDefinition());
builder.addPropertyValue("sourceList", parsedList);
String listClass = element.getAttribute("list-class");
if (StringUtils.hasText(listClass)) {
builder.addPropertyValue("targetListClass", listClass);
}
String scope = element.getAttribute(SCOPE_ATTRIBUTE);
if (StringUtils.hasLength(scope)) {
builder.setScope(scope);
@ -143,12 +145,14 @@ public class UtilNamespaceHandler extends NamespaceHandlerSupport {
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
String setClass = element.getAttribute("set-class");
Set<Object> parsedSet = parserContext.getDelegate().parseSetElement(element, builder.getRawBeanDefinition());
builder.addPropertyValue("sourceSet", parsedSet);
String setClass = element.getAttribute("set-class");
if (StringUtils.hasText(setClass)) {
builder.addPropertyValue("targetSetClass", setClass);
}
String scope = element.getAttribute(SCOPE_ATTRIBUTE);
if (StringUtils.hasLength(scope)) {
builder.setScope(scope);
@ -166,12 +170,14 @@ public class UtilNamespaceHandler extends NamespaceHandlerSupport {
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
String mapClass = element.getAttribute("map-class");
Map<Object, Object> parsedMap = parserContext.getDelegate().parseMapElement(element, builder.getRawBeanDefinition());
builder.addPropertyValue("sourceMap", parsedMap);
String mapClass = element.getAttribute("map-class");
if (StringUtils.hasText(mapClass)) {
builder.addPropertyValue("targetMapClass", mapClass);
}
String scope = element.getAttribute(SCOPE_ATTRIBUTE);
if (StringUtils.hasLength(scope)) {
builder.setScope(scope);
@ -180,23 +186,30 @@ public class UtilNamespaceHandler extends NamespaceHandlerSupport {
}
private static class PropertiesBeanDefinitionParser extends AbstractSimpleBeanDefinitionParser {
private static class PropertiesBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
return PropertiesFactoryBean.class;
}
@Override
protected boolean isEligibleAttribute(String attributeName) {
return super.isEligibleAttribute(attributeName) && !SCOPE_ATTRIBUTE.equals(attributeName);
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
super.doParse(element, parserContext, builder);
Properties parsedProps = parserContext.getDelegate().parsePropsElement(element);
builder.addPropertyValue("properties", parsedProps);
String location = element.getAttribute("location");
if (StringUtils.hasLength(location)) {
String[] locations = StringUtils.commaDelimitedListToStringArray(location);
builder.addPropertyValue("locations", locations);
}
builder.addPropertyValue("ignoreResourceNotFound",
Boolean.valueOf(element.getAttribute("ignore-resource-not-found")));
builder.addPropertyValue("localOverride",
Boolean.valueOf(element.getAttribute("local-override")));
String scope = element.getAttribute(SCOPE_ATTRIBUTE);
if (StringUtils.hasLength(scope)) {
builder.setScope(scope);

View File

@ -177,14 +177,23 @@
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="location" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation>
<tool:expected-type type="org.springframework.core.io.Resource"/>
</tool:annotation>
</xsd:appinfo>
<xsd:documentation><![CDATA[
The location of the properties file, as a Spring resource location: a URL,
a "classpath:" pseudo URL, or a relative file path. Multiple locations may be
specified, separated by commas.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="local-override" type="xsd:boolean">
<xsd:attribute name="ignore-resource-not-found" type="xsd:boolean" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
Specifies if failure to find the property resource location should be ignored.
Default is "false", meaning that if there is no file in the location specified
an exception will be raised at runtime.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="local-override" type="xsd:boolean" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
Specifies whether local properties override properties from files.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@ -17,14 +17,15 @@
package org.springframework.beans.factory.xml;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.Arrays;
import junit.framework.TestCase;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.config.FieldRetrievingFactoryBean;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
@ -36,18 +37,21 @@ import org.springframework.tests.beans.CollectingReaderEventListener;
import org.springframework.tests.sample.beans.CustomEnum;
import org.springframework.tests.sample.beans.TestBean;
import static org.junit.Assert.*;
/**
* @author Rob Harrop
* @author Juergen Hoeller
* @author Mark Fisher
*/
public class UtilNamespaceHandlerTests extends TestCase {
public class UtilNamespaceHandlerTests {
private DefaultListableBeanFactory beanFactory;
private CollectingReaderEventListener listener = new CollectingReaderEventListener();
@Override
@Before
public void setUp() {
this.beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.beanFactory);
@ -55,17 +59,21 @@ public class UtilNamespaceHandlerTests extends TestCase {
reader.loadBeanDefinitions(new ClassPathResource("testUtilNamespace.xml", getClass()));
}
public void testConstant() throws Exception {
@Test
public void testConstant() {
Integer min = (Integer) this.beanFactory.getBean("min");
assertEquals(Integer.MIN_VALUE, min.intValue());
}
public void testConstantWithDefaultName() throws Exception {
@Test
public void testConstantWithDefaultName() {
Integer max = (Integer) this.beanFactory.getBean("java.lang.Integer.MAX_VALUE");
assertEquals(Integer.MAX_VALUE, max.intValue());
}
public void testEvents() throws Exception {
@Test
public void testEvents() {
ComponentDefinition propertiesComponent = this.listener.getComponentDefinition("myProperties");
assertNotNull("Event for 'myProperties' not sent", propertiesComponent);
AbstractBeanDefinition propertiesBean = (AbstractBeanDefinition) propertiesComponent.getBeanDefinitions()[0];
@ -77,30 +85,35 @@ public class UtilNamespaceHandlerTests extends TestCase {
assertEquals("Incorrect BeanDefinition", FieldRetrievingFactoryBean.class, constantBean.getBeanClass());
}
public void testNestedProperties() throws Exception {
@Test
public void testNestedProperties() {
TestBean bean = (TestBean) this.beanFactory.getBean("testBean");
Properties props = bean.getSomeProperties();
assertEquals("Incorrect property value", "bar", props.get("foo"));
}
public void testPropertyPath() throws Exception {
@Test
public void testPropertyPath() {
String name = (String) this.beanFactory.getBean("name");
assertEquals("Rob Harrop", name);
}
public void testNestedPropertyPath() throws Exception {
@Test
public void testNestedPropertyPath() {
TestBean bean = (TestBean) this.beanFactory.getBean("testBean");
assertEquals("Rob Harrop", bean.getName());
}
public void testSimpleMap() throws Exception {
@Test
public void testSimpleMap() {
Map map = (Map) this.beanFactory.getBean("simpleMap");
assertEquals("bar", map.get("foo"));
Map map2 = (Map) this.beanFactory.getBean("simpleMap");
assertTrue(map == map2);
}
public void testScopedMap() throws Exception {
@Test
public void testScopedMap() {
Map map = (Map) this.beanFactory.getBean("scopedMap");
assertEquals("bar", map.get("foo"));
Map map2 = (Map) this.beanFactory.getBean("scopedMap");
@ -108,14 +121,16 @@ public class UtilNamespaceHandlerTests extends TestCase {
assertTrue(map != map2);
}
public void testSimpleList() throws Exception {
@Test
public void testSimpleList() {
List list = (List) this.beanFactory.getBean("simpleList");
assertEquals("Rob Harrop", list.get(0));
List list2 = (List) this.beanFactory.getBean("simpleList");
assertTrue(list == list2);
}
public void testScopedList() throws Exception {
@Test
public void testScopedList() {
List list = (List) this.beanFactory.getBean("scopedList");
assertEquals("Rob Harrop", list.get(0));
List list2 = (List) this.beanFactory.getBean("scopedList");
@ -123,14 +138,16 @@ public class UtilNamespaceHandlerTests extends TestCase {
assertTrue(list != list2);
}
public void testSimpleSet() throws Exception {
@Test
public void testSimpleSet() {
Set set = (Set) this.beanFactory.getBean("simpleSet");
assertTrue(set.contains("Rob Harrop"));
Set set2 = (Set) this.beanFactory.getBean("simpleSet");
assertTrue(set == set2);
}
public void testScopedSet() throws Exception {
@Test
public void testScopedSet() {
Set set = (Set) this.beanFactory.getBean("scopedSet");
assertTrue(set.contains("Rob Harrop"));
Set set2 = (Set) this.beanFactory.getBean("scopedSet");
@ -138,13 +155,15 @@ public class UtilNamespaceHandlerTests extends TestCase {
assertTrue(set != set2);
}
public void testMapWithRef() throws Exception {
@Test
public void testMapWithRef() {
Map map = (Map) this.beanFactory.getBean("mapWithRef");
assertTrue(map instanceof TreeMap);
assertEquals(this.beanFactory.getBean("testBean"), map.get("bean"));
}
public void testNestedCollections() throws Exception {
@Test
public void testNestedCollections() {
TestBean bean = (TestBean) this.beanFactory.getBean("nestedCollectionsBean");
List list = bean.getSomeList();
@ -171,7 +190,8 @@ public class UtilNamespaceHandlerTests extends TestCase {
assertFalse(map == bean2.getSomeMap());
}
public void testNestedShortcutCollections() throws Exception {
@Test
public void testNestedShortcutCollections() {
TestBean bean = (TestBean) this.beanFactory.getBean("nestedShortcutCollections");
assertEquals(1, bean.getStringArray().length);
@ -194,7 +214,8 @@ public class UtilNamespaceHandlerTests extends TestCase {
assertFalse(set == bean2.getSomeSet());
}
public void testNestedInCollections() throws Exception {
@Test
public void testNestedInCollections() {
TestBean bean = (TestBean) this.beanFactory.getBean("nestedCustomTagBean");
List list = bean.getSomeList();
@ -219,7 +240,8 @@ public class UtilNamespaceHandlerTests extends TestCase {
assertFalse(map == bean2.getSomeMap());
}
public void testCircularCollections() throws Exception {
@Test
public void testCircularCollections() {
TestBean bean = (TestBean) this.beanFactory.getBean("circularCollectionsBean");
List list = bean.getSomeList();
@ -235,7 +257,8 @@ public class UtilNamespaceHandlerTests extends TestCase {
assertEquals(bean, map.get("foo"));
}
public void testCircularCollectionBeansStartingWithList() throws Exception {
@Test
public void testCircularCollectionBeansStartingWithList() {
this.beanFactory.getBean("circularList");
TestBean bean = (TestBean) this.beanFactory.getBean("circularCollectionBeansBean");
@ -255,7 +278,8 @@ public class UtilNamespaceHandlerTests extends TestCase {
assertEquals(bean, map.get("foo"));
}
public void testCircularCollectionBeansStartingWithSet() throws Exception {
@Test
public void testCircularCollectionBeansStartingWithSet() {
this.beanFactory.getBean("circularSet");
TestBean bean = (TestBean) this.beanFactory.getBean("circularCollectionBeansBean");
@ -275,7 +299,8 @@ public class UtilNamespaceHandlerTests extends TestCase {
assertEquals(bean, map.get("foo"));
}
public void testCircularCollectionBeansStartingWithMap() throws Exception {
@Test
public void testCircularCollectionBeansStartingWithMap() {
this.beanFactory.getBean("circularMap");
TestBean bean = (TestBean) this.beanFactory.getBean("circularCollectionBeansBean");
@ -295,12 +320,14 @@ public class UtilNamespaceHandlerTests extends TestCase {
assertEquals(bean, map.get("foo"));
}
public void testNestedInConstructor() throws Exception {
@Test
public void testNestedInConstructor() {
TestBean bean = (TestBean) this.beanFactory.getBean("constructedTestBean");
assertEquals("Rob Harrop", bean.getName());
}
public void testLoadProperties() throws Exception {
@Test
public void testLoadProperties() {
Properties props = (Properties) this.beanFactory.getBean("myProperties");
assertEquals("Incorrect property value", "bar", props.get("foo"));
assertEquals("Incorrect property value", null, props.get("foo2"));
@ -308,7 +335,8 @@ public class UtilNamespaceHandlerTests extends TestCase {
assertTrue(props == props2);
}
public void testScopedProperties() throws Exception {
@Test
public void testScopedProperties() {
Properties props = (Properties) this.beanFactory.getBean("myScopedProperties");
assertEquals("Incorrect property value", "bar", props.get("foo"));
assertEquals("Incorrect property value", null, props.get("foo2"));
@ -318,30 +346,35 @@ public class UtilNamespaceHandlerTests extends TestCase {
assertTrue(props != props2);
}
public void testLocalProperties() throws Exception {
@Test
public void testLocalProperties() {
Properties props = (Properties) this.beanFactory.getBean("myLocalProperties");
assertEquals("Incorrect property value", null, props.get("foo"));
assertEquals("Incorrect property value", "bar2", props.get("foo2"));
}
public void testMergedProperties() throws Exception {
@Test
public void testMergedProperties() {
Properties props = (Properties) this.beanFactory.getBean("myMergedProperties");
assertEquals("Incorrect property value", "bar", props.get("foo"));
assertEquals("Incorrect property value", "bar2", props.get("foo2"));
}
@Test
public void testLocalOverrideDefault() {
Properties props = (Properties) this.beanFactory.getBean("defaultLocalOverrideProperties");
assertEquals("Incorrect property value", "bar", props.get("foo"));
assertEquals("Incorrect property value", "local2", props.get("foo2"));
}
@Test
public void testLocalOverrideFalse() {
Properties props = (Properties) this.beanFactory.getBean("falseLocalOverrideProperties");
assertEquals("Incorrect property value", "bar", props.get("foo"));
assertEquals("Incorrect property value", "local2", props.get("foo2"));
}
@Test
public void testLocalOverrideTrue() {
Properties props = (Properties) this.beanFactory.getBean("trueLocalOverrideProperties");
assertEquals("Incorrect property value", "local", props.get("foo"));

View File

@ -2,8 +2,8 @@
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd">
<util:constant id="min" static-field="
java.lang.Integer.
@ -157,7 +157,8 @@
location="classpath:/org/springframework/beans/factory/xml/util.properties"/>
<util:properties id="myScopedProperties"
location="classpath:/org/springframework/beans/factory/xml/util.properties" scope="prototype"/>
location="classpath:/org/springframework/beans/factory/xml/util.properties,classpath:override.properties"
ignore-resource-not-found="true" scope="prototype"/>
<util:properties id="myLocalProperties">
<prop key="foo2">bar2</prop>