SimpleAliasRegistry detects resolved aliases that loop back to the original name (SPR-5419); PropertyPlaceholderConfigurer does not modify Map in case of equal String keys (SPR-5318); inner class names in Java source style ("java.lang.Thread.State") supported as well (SPR-5210)
This commit is contained in:
parent
ff8e7a1289
commit
eb1631f458
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -264,7 +264,9 @@ public class BeanDefinitionVisitor {
|
||||||
throw new IllegalStateException("No StringValueResolver specified - pass a resolver " +
|
throw new IllegalStateException("No StringValueResolver specified - pass a resolver " +
|
||||||
"object into the constructor or override the 'resolveStringValue' method");
|
"object into the constructor or override the 'resolveStringValue' method");
|
||||||
}
|
}
|
||||||
return this.valueResolver.resolveStringValue(strVal);
|
String resolvedValue = this.valueResolver.resolveStringValue(strVal);
|
||||||
|
// Return original String if not modified.
|
||||||
|
return (strVal.equals(resolvedValue) ? strVal : resolvedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,23 +16,26 @@
|
||||||
|
|
||||||
package org.springframework.beans.factory.config;
|
package org.springframework.beans.factory.config;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import java.util.Collections;
|
||||||
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition;
|
|
||||||
import static test.util.TestResourceUtils.qualifiedResource;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.prefs.Preferences;
|
import java.util.prefs.Preferences;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import test.beans.IndexedTestBean;
|
||||||
|
import test.beans.TestBean;
|
||||||
|
import static test.util.TestResourceUtils.*;
|
||||||
|
|
||||||
import org.springframework.beans.MutablePropertyValues;
|
import org.springframework.beans.MutablePropertyValues;
|
||||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||||
import org.springframework.beans.factory.BeanInitializationException;
|
import org.springframework.beans.factory.BeanInitializationException;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
|
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.*;
|
||||||
import org.springframework.beans.factory.support.ChildBeanDefinition;
|
import org.springframework.beans.factory.support.ChildBeanDefinition;
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.beans.factory.support.ManagedList;
|
import org.springframework.beans.factory.support.ManagedList;
|
||||||
|
@ -41,9 +44,6 @@ import org.springframework.beans.factory.support.ManagedSet;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
|
|
||||||
import test.beans.IndexedTestBean;
|
|
||||||
import test.beans.TestBean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for various {@link PropertyResourceConfigurer} implementations including:
|
* Unit tests for various {@link PropertyResourceConfigurer} implementations including:
|
||||||
* {@link PropertyPlaceholderConfigurer}, {@link PropertyOverrideConfigurer} and
|
* {@link PropertyPlaceholderConfigurer}, {@link PropertyOverrideConfigurer} and
|
||||||
|
@ -296,7 +296,7 @@ public final class PropertyResourceConfigurerTests {
|
||||||
poc.postProcessBeanFactory(factory);
|
poc.postProcessBeanFactory(factory);
|
||||||
} catch (BeanInitializationException ex) {
|
} catch (BeanInitializationException ex) {
|
||||||
// prove that the processor chokes on the invalid key
|
// prove that the processor chokes on the invalid key
|
||||||
assertTrue(ex.getMessage().toLowerCase().indexOf("argh") != -1);
|
assertTrue(ex.getMessage().toLowerCase().contains("argh"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -345,13 +345,14 @@ public final class PropertyResourceConfigurerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doTestPropertyPlaceholderConfigurer(boolean parentChildSeparation) {
|
private void doTestPropertyPlaceholderConfigurer(boolean parentChildSeparation) {
|
||||||
|
Map singletonMap = Collections.singletonMap("myKey", "myValue");
|
||||||
if (parentChildSeparation) {
|
if (parentChildSeparation) {
|
||||||
MutablePropertyValues pvs1 = new MutablePropertyValues();
|
MutablePropertyValues pvs1 = new MutablePropertyValues();
|
||||||
pvs1.addPropertyValue("age", "${age}");
|
pvs1.addPropertyValue("age", "${age}");
|
||||||
MutablePropertyValues pvs2 = new MutablePropertyValues();
|
MutablePropertyValues pvs2 = new MutablePropertyValues();
|
||||||
pvs2.addPropertyValue("name", "name${var}${var}${");
|
pvs2.addPropertyValue("name", "name${var}${var}${");
|
||||||
pvs2.addPropertyValue("spouse", new RuntimeBeanReference("${ref}"));
|
pvs2.addPropertyValue("spouse", new RuntimeBeanReference("${ref}"));
|
||||||
|
pvs2.addPropertyValue("someMap", singletonMap);
|
||||||
RootBeanDefinition parent = new RootBeanDefinition(TestBean.class, pvs1);
|
RootBeanDefinition parent = new RootBeanDefinition(TestBean.class, pvs1);
|
||||||
ChildBeanDefinition bd = new ChildBeanDefinition("${parent}", pvs2);
|
ChildBeanDefinition bd = new ChildBeanDefinition("${parent}", pvs2);
|
||||||
factory.registerBeanDefinition("parent1", parent);
|
factory.registerBeanDefinition("parent1", parent);
|
||||||
|
@ -362,6 +363,7 @@ public final class PropertyResourceConfigurerTests {
|
||||||
pvs.addPropertyValue("age", "${age}");
|
pvs.addPropertyValue("age", "${age}");
|
||||||
pvs.addPropertyValue("name", "name${var}${var}${");
|
pvs.addPropertyValue("name", "name${var}${var}${");
|
||||||
pvs.addPropertyValue("spouse", new RuntimeBeanReference("${ref}"));
|
pvs.addPropertyValue("spouse", new RuntimeBeanReference("${ref}"));
|
||||||
|
pvs.addPropertyValue("someMap", singletonMap);
|
||||||
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, pvs);
|
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, pvs);
|
||||||
factory.registerBeanDefinition("tb1", bd);
|
factory.registerBeanDefinition("tb1", bd);
|
||||||
}
|
}
|
||||||
|
@ -415,6 +417,8 @@ public final class PropertyResourceConfigurerTests {
|
||||||
assertEquals("namemyvarmyvar${", tb1.getName());
|
assertEquals("namemyvarmyvar${", tb1.getName());
|
||||||
assertEquals("myvarname98", tb2.getName());
|
assertEquals("myvarname98", tb2.getName());
|
||||||
assertEquals(tb2, tb1.getSpouse());
|
assertEquals(tb2, tb1.getSpouse());
|
||||||
|
assertEquals(1, tb1.getSomeMap().size());
|
||||||
|
assertEquals("myValue", tb1.getSomeMap().get("myKey"));
|
||||||
assertEquals(2, tb2.getFriends().size());
|
assertEquals(2, tb2.getFriends().size());
|
||||||
assertEquals("na98me", tb2.getFriends().iterator().next());
|
assertEquals("na98me", tb2.getFriends().iterator().next());
|
||||||
assertEquals(tb2, tb2.getFriends().toArray()[1]);
|
assertEquals(tb2, tb2.getFriends().toArray()[1]);
|
||||||
|
@ -498,7 +502,7 @@ public final class PropertyResourceConfigurerTests {
|
||||||
}
|
}
|
||||||
catch (BeanDefinitionStoreException ex) {
|
catch (BeanDefinitionStoreException ex) {
|
||||||
// expected
|
// expected
|
||||||
assertTrue(ex.getMessage().indexOf("user.dir") != -1);
|
assertTrue(ex.getMessage().contains("user.dir"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -516,7 +520,7 @@ public final class PropertyResourceConfigurerTests {
|
||||||
}
|
}
|
||||||
catch (BeanDefinitionStoreException ex) {
|
catch (BeanDefinitionStoreException ex) {
|
||||||
// expected
|
// expected
|
||||||
assertTrue(ex.getMessage().indexOf("ref") != -1);
|
assertTrue(ex.getMessage().contains("ref"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,6 +586,39 @@ public final class PropertyResourceConfigurerTests {
|
||||||
assertEquals("myname", tb.getName());
|
assertEquals("myname", tb.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPropertyPlaceholderConfigurerWithPlaceholderInAlias() {
|
||||||
|
factory.registerBeanDefinition("tb",
|
||||||
|
genericBeanDefinition(TestBean.class).getBeanDefinition());
|
||||||
|
factory.registerAlias("tb", "${alias}");
|
||||||
|
|
||||||
|
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||||
|
Properties props = new Properties();
|
||||||
|
props.put("alias", "tb2");
|
||||||
|
ppc.setProperties(props);
|
||||||
|
ppc.postProcessBeanFactory(factory);
|
||||||
|
|
||||||
|
TestBean tb = (TestBean) factory.getBean("tb");
|
||||||
|
TestBean tb2 = (TestBean) factory.getBean("tb2");
|
||||||
|
assertSame(tb, tb2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPropertyPlaceholderConfigurerWithSelfReferencingPlaceholderInAlias() {
|
||||||
|
factory.registerBeanDefinition("tb",
|
||||||
|
genericBeanDefinition(TestBean.class).getBeanDefinition());
|
||||||
|
factory.registerAlias("tb", "${alias}");
|
||||||
|
|
||||||
|
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||||
|
Properties props = new Properties();
|
||||||
|
props.put("alias", "tb");
|
||||||
|
ppc.setProperties(props);
|
||||||
|
ppc.postProcessBeanFactory(factory);
|
||||||
|
|
||||||
|
TestBean tb = (TestBean) factory.getBean("tb");
|
||||||
|
assertEquals(0, factory.getAliases("tb").length);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPropertyPlaceholderConfigurerWithCircularReference() {
|
public void testPropertyPlaceholderConfigurerWithCircularReference() {
|
||||||
factory.registerBeanDefinition("tb",
|
factory.registerBeanDefinition("tb",
|
||||||
|
@ -760,6 +797,7 @@ public final class PropertyResourceConfigurerTests {
|
||||||
|
|
||||||
|
|
||||||
private static class ConvertingOverrideConfigurer extends PropertyOverrideConfigurer {
|
private static class ConvertingOverrideConfigurer extends PropertyOverrideConfigurer {
|
||||||
|
|
||||||
protected String convertPropertyValue(String originalValue) {
|
protected String convertPropertyValue(String originalValue) {
|
||||||
return "X" + originalValue;
|
return "X" + originalValue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -24,17 +24,16 @@ import java.util.Set;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
import test.beans.CustomEnum;
|
||||||
|
import test.beans.TestBean;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.config.FieldRetrievingFactoryBean;
|
||||||
|
import org.springframework.beans.factory.config.PropertiesFactoryBean;
|
||||||
import org.springframework.beans.factory.parsing.ComponentDefinition;
|
import org.springframework.beans.factory.parsing.ComponentDefinition;
|
||||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
|
||||||
import org.springframework.beans.factory.config.PropertiesFactoryBean;
|
|
||||||
import org.springframework.beans.factory.config.FieldRetrievingFactoryBean;
|
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
|
||||||
import test.beans.TestBean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Rob Harrop
|
* @author Rob Harrop
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
@ -163,19 +162,19 @@ public class UtilNamespaceHandlerTests extends TestCase {
|
||||||
|
|
||||||
public void testNestedInCollections() throws Exception {
|
public void testNestedInCollections() throws Exception {
|
||||||
TestBean bean = (TestBean) this.beanFactory.getBean("nestedCustomTagBean");
|
TestBean bean = (TestBean) this.beanFactory.getBean("nestedCustomTagBean");
|
||||||
Integer min = new Integer(Integer.MIN_VALUE);
|
|
||||||
|
|
||||||
List list = bean.getSomeList();
|
List list = bean.getSomeList();
|
||||||
assertEquals(1, list.size());
|
assertEquals(1, list.size());
|
||||||
assertEquals(min, list.get(0));
|
assertEquals(Integer.MIN_VALUE, list.get(0));
|
||||||
|
|
||||||
Set set = bean.getSomeSet();
|
Set set = bean.getSomeSet();
|
||||||
assertEquals(1, set.size());
|
assertEquals(2, set.size());
|
||||||
assertTrue(set.contains(min));
|
assertTrue(set.contains(Thread.State.NEW));
|
||||||
|
assertTrue(set.contains(Thread.State.RUNNABLE));
|
||||||
|
|
||||||
Map map = bean.getSomeMap();
|
Map map = bean.getSomeMap();
|
||||||
assertEquals(1, map.size());
|
assertEquals(1, map.size());
|
||||||
assertEquals(min, map.get("min"));
|
assertEquals(CustomEnum.VALUE_1, map.get("min"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCircularCollections() throws Exception {
|
public void testCircularCollections() throws Exception {
|
||||||
|
|
|
@ -97,14 +97,15 @@
|
||||||
</property>
|
</property>
|
||||||
<property name="someSet">
|
<property name="someSet">
|
||||||
<set>
|
<set>
|
||||||
<util:constant static-field="java.lang.Integer.MIN_VALUE"/>
|
<util:constant static-field="java.lang.Thread$State.NEW"/>
|
||||||
|
<util:constant static-field="java.lang.Thread.State.RUNNABLE"/>
|
||||||
</set>
|
</set>
|
||||||
</property>
|
</property>
|
||||||
<property name="someMap">
|
<property name="someMap">
|
||||||
<map>
|
<map>
|
||||||
<entry>
|
<entry>
|
||||||
<key><value>min</value></key>
|
<key><value>min</value></key>
|
||||||
<util:constant static-field="java.lang.Integer.MIN_VALUE"/>
|
<util:constant static-field="test.beans.CustomEnum.VALUE_1"/>
|
||||||
</entry>
|
</entry>
|
||||||
</map>
|
</map>
|
||||||
</property>
|
</property>
|
||||||
|
|
|
@ -117,7 +117,10 @@ public class SimpleAliasRegistry implements AliasRegistry {
|
||||||
String registeredName = aliasCopy.get(alias);
|
String registeredName = aliasCopy.get(alias);
|
||||||
String resolvedAlias = valueResolver.resolveStringValue(alias);
|
String resolvedAlias = valueResolver.resolveStringValue(alias);
|
||||||
String resolvedName = valueResolver.resolveStringValue(registeredName);
|
String resolvedName = valueResolver.resolveStringValue(registeredName);
|
||||||
if (!resolvedAlias.equals(alias)) {
|
if (resolvedAlias.equals(resolvedName)) {
|
||||||
|
this.aliasMap.remove(alias);
|
||||||
|
}
|
||||||
|
else if (!resolvedAlias.equals(alias)) {
|
||||||
String existingName = this.aliasMap.get(resolvedAlias);
|
String existingName = this.aliasMap.get(resolvedAlias);
|
||||||
if (existingName != null && !existingName.equals(resolvedName)) {
|
if (existingName != null && !existingName.equals(resolvedName)) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
|
@ -125,8 +128,8 @@ public class SimpleAliasRegistry implements AliasRegistry {
|
||||||
"') for name '" + resolvedName + "': It is already registered for name '" +
|
"') for name '" + resolvedName + "': It is already registered for name '" +
|
||||||
registeredName + "'.");
|
registeredName + "'.");
|
||||||
}
|
}
|
||||||
this.aliasMap.put(resolvedAlias, resolvedName);
|
|
||||||
this.aliasMap.remove(alias);
|
this.aliasMap.remove(alias);
|
||||||
|
this.aliasMap.put(resolvedAlias, resolvedName);
|
||||||
}
|
}
|
||||||
else if (!registeredName.equals(resolvedName)) {
|
else if (!registeredName.equals(resolvedName)) {
|
||||||
this.aliasMap.put(alias, resolvedName);
|
this.aliasMap.put(alias, resolvedName);
|
||||||
|
|
|
@ -201,7 +201,9 @@ public abstract class ClassUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replacement for <code>Class.forName()</code> that also returns Class instances
|
* Replacement for <code>Class.forName()</code> that also returns Class instances
|
||||||
* for primitives (like "int") and array class names (like "String[]").
|
* for primitives (e.g."int") and array class names (e.g. "String[]").
|
||||||
|
* Furthermore, it is also capable of resolving inner class names in Java source
|
||||||
|
* style (e.g. "java.lang.Thread.State" instead of "java.lang.Thread$State").
|
||||||
* @param name the name of the Class
|
* @param name the name of the Class
|
||||||
* @param classLoader the class loader to use
|
* @param classLoader the class loader to use
|
||||||
* (may be <code>null</code>, which indicates the default class loader)
|
* (may be <code>null</code>, which indicates the default class loader)
|
||||||
|
@ -246,7 +248,22 @@ public abstract class ClassUtils {
|
||||||
if (classLoaderToUse == null) {
|
if (classLoaderToUse == null) {
|
||||||
classLoaderToUse = getDefaultClassLoader();
|
classLoaderToUse = getDefaultClassLoader();
|
||||||
}
|
}
|
||||||
return classLoaderToUse.loadClass(name);
|
try {
|
||||||
|
return classLoaderToUse.loadClass(name);
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException ex) {
|
||||||
|
int lastDotIndex = name.lastIndexOf('.');
|
||||||
|
if (lastDotIndex != -1) {
|
||||||
|
String innerClassName = name.substring(0, lastDotIndex) + '$' + name.substring(lastDotIndex + 1);
|
||||||
|
try {
|
||||||
|
return classLoaderToUse.loadClass(innerClassName);
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException ex2) {
|
||||||
|
// swallow - let original exception get through
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue