diff --git a/.gitignore b/.gitignore index 2ddff7cd483..020a89367b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,11 @@ target integration-repo ivy-cache -spring-build jmx.log .springBeans .DS_Store +*.sw* +org.springframework.test/test-output/ +build.sh +org.springframework.beans/.settings/org.springframework.ide.eclipse.beans.core.prefs +org.springframework.beans/.settings/org.springframework.ide.eclipse.core.prefs diff --git a/build.properties b/build.properties index c4a2e63cce8..5f5f4b6ebf2 100644 --- a/build.properties +++ b/build.properties @@ -1,4 +1,4 @@ -version=3.0.5 +version=3.1.0 # osgi ranges spring.osgi.range.nq=${version:[=.=.=, =.=.+1)} spring.osgi.range="${spring.osgi.range.nq}" diff --git a/org.springframework.aop/.settings/org.eclipse.jdt.core.prefs b/org.springframework.aop/.settings/org.eclipse.jdt.core.prefs index 0e29d554498..7a583ba283d 100644 --- a/org.springframework.aop/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.aop/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ #Wed Jul 15 00:01:31 PDT 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/org.springframework.aop/pom.xml b/org.springframework.aop/pom.xml index 1ed23a35707..98c0cf409d4 100644 --- a/org.springframework.aop/pom.xml +++ b/org.springframework.aop/pom.xml @@ -4,12 +4,12 @@ org.springframework spring-aop jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.aop/src/main/resources/META-INF/spring.schemas b/org.springframework.aop/src/main/resources/META-INF/spring.schemas index 6ca4bbe595e..44614f454d1 100644 --- a/org.springframework.aop/src/main/resources/META-INF/spring.schemas +++ b/org.springframework.aop/src/main/resources/META-INF/spring.schemas @@ -1,4 +1,5 @@ http\://www.springframework.org/schema/aop/spring-aop-2.0.xsd=org/springframework/aop/config/spring-aop-2.0.xsd http\://www.springframework.org/schema/aop/spring-aop-2.5.xsd=org/springframework/aop/config/spring-aop-2.5.xsd http\://www.springframework.org/schema/aop/spring-aop-3.0.xsd=org/springframework/aop/config/spring-aop-3.0.xsd -http\://www.springframework.org/schema/aop/spring-aop.xsd=org/springframework/aop/config/spring-aop-3.0.xsd +http\://www.springframework.org/schema/aop/spring-aop-3.1.xsd=org/springframework/aop/config/spring-aop-3.1.xsd +http\://www.springframework.org/schema/aop/spring-aop.xsd=org/springframework/aop/config/spring-aop-3.1.xsd diff --git a/org.springframework.aop/src/main/resources/org/springframework/aop/config/spring-aop-3.1.xsd b/org.springframework.aop/src/main/resources/org/springframework/aop/config/spring-aop-3.1.xsd new file mode 100644 index 00000000000..591baf4a28a --- /dev/null +++ b/org.springframework.aop/src/main/resources/org/springframework/aop/config/spring-aop-3.1.xsd @@ -0,0 +1,407 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.asm/.settings/org.eclipse.jdt.core.prefs b/org.springframework.asm/.settings/org.eclipse.jdt.core.prefs index a15f738edcd..4655eeb423f 100644 --- a/org.springframework.asm/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.asm/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ #Wed Jul 15 00:01:30 PDT 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/org.springframework.asm/pom.xml b/org.springframework.asm/pom.xml index 5ecb2f0809f..5b66af1639b 100644 --- a/org.springframework.asm/pom.xml +++ b/org.springframework.asm/pom.xml @@ -4,12 +4,12 @@ org.springframework spring-asm jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.asm/src/main/java/.gitignore b/org.springframework.asm/src/main/java/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/org.springframework.asm/src/test/java/.gitignore b/org.springframework.asm/src/test/java/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/org.springframework.aspects/.settings/org.eclipse.jdt.core.prefs b/org.springframework.aspects/.settings/org.eclipse.jdt.core.prefs index 5b1fd1a9b1c..737639da31d 100644 --- a/org.springframework.aspects/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.aspects/.settings/org.eclipse.jdt.core.prefs @@ -1,12 +1,12 @@ #Wed Jul 15 00:01:30 PDT 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 diff --git a/org.springframework.aspects/pom.xml b/org.springframework.aspects/pom.xml index 9389097278c..d8fcd6aaf26 100644 --- a/org.springframework.aspects/pom.xml +++ b/org.springframework.aspects/pom.xml @@ -1,90 +1,84 @@ - - - 4.0.0 - org.springframework - spring-aspects - jar - 3.0.5.BUILD-SNAPSHOT - - org.springframework - spring-parent - ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT - - - - - - org.aspectj - aspectjweaver - true - - - org.springframework - spring-beans - ${project.version} - compile - - - org.springframework - spring-tx - ${project.version} - true - - - org.springframework - spring-orm - ${project.version} - true - - - org.springframework - spring-context - ${project.version} - compile - - - org.springframework - spring-context-support - ${project.version} - compile - - - org.springframework - spring-test - ${project.version} - compile - - - javax.persistence - persistence-api - 1.0 - true - - - junit - junit - test - - - javax.mail - mail - 1.4 - test - true - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - junit:junit - - - - - - + + + 4.0.0 + org.springframework + spring-aspects + jar + 3.1.0.BUILD-SNAPSHOT + + org.springframework + spring-parent + ../org.springframework.spring-parent + 3.1.0.BUILD-SNAPSHOT + + + + + + org.aspectj + aspectjweaver + true + + + org.springframework + spring-beans + ${project.version} + compile + + + org.springframework + spring-tx + ${project.version} + true + + + org.springframework + spring-context + ${project.version} + compile + + + org.springframework + spring-context-support + ${project.version} + compile + + + org.springframework + spring-test + ${project.version} + compile + + + javax.persistence + persistence-api + 1.0 + provided + + + junit + junit + test + + + javax.mail + mail + 1.4 + test + true + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + junit:junit + + + + + + diff --git a/org.springframework.beans/.classpath b/org.springframework.beans/.classpath index f79139da041..107c729066e 100644 --- a/org.springframework.beans/.classpath +++ b/org.springframework.beans/.classpath @@ -12,6 +12,7 @@ + diff --git a/org.springframework.beans/.settings/org.eclipse.jdt.core.prefs b/org.springframework.beans/.settings/org.eclipse.jdt.core.prefs index 0e29d554498..6d736b33d2e 100644 --- a/org.springframework.beans/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.beans/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ -#Wed Jul 15 00:01:31 PDT 2009 +#Mon Sep 06 21:54:17 CEST 2010 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/org.springframework.beans/beans.iml b/org.springframework.beans/beans.iml index 4a343bb3961..641d28b9c7e 100644 --- a/org.springframework.beans/beans.iml +++ b/org.springframework.beans/beans.iml @@ -17,6 +17,7 @@ + diff --git a/org.springframework.beans/ivy.xml b/org.springframework.beans/ivy.xml index 0c85216032b..7619ebbc822 100644 --- a/org.springframework.beans/ivy.xml +++ b/org.springframework.beans/ivy.xml @@ -31,6 +31,7 @@ + diff --git a/org.springframework.beans/pom.xml b/org.springframework.beans/pom.xml index 7a25adf440d..16504a2167c 100644 --- a/org.springframework.beans/pom.xml +++ b/org.springframework.beans/pom.xml @@ -4,12 +4,12 @@ org.springframework spring-beans jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/BeanFactory.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/BeanFactory.java index c43b9052218..c49b9065056 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/BeanFactory.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/BeanFactory.java @@ -87,6 +87,7 @@ import org.springframework.beans.BeansException; * * @author Rod Johnson * @author Juergen Hoeller + * @author Chris Beams * @since 13 April 2001 * @see BeanNameAware#setBeanName * @see BeanClassLoaderAware#setBeanClassLoader @@ -113,7 +114,6 @@ public interface BeanFactory { */ String FACTORY_BEAN_PREFIX = "&"; - /** * Return an instance, which may be shared or independent, of the specified bean. *

This method allows a Spring BeanFactory to be used as a replacement for the @@ -240,7 +240,7 @@ public interface BeanFactory { * @see #getBean * @see #getType */ - boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException; + boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException; /** * Determine the type of the bean with the given name. More specifically, diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java index 4061d7f923d..e7c08c2dc55 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java @@ -110,7 +110,7 @@ public interface ListableBeanFactory extends BeanFactory { * @see FactoryBean#getObjectType * @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, Class) */ - String[] getBeanNamesForType(Class type); + String[] getBeanNamesForType(Class type); /** * Return the names of beans matching the given type (including subclasses), @@ -123,7 +123,7 @@ public interface ListableBeanFactory extends BeanFactory { * FactoryBean doesn't match, the raw FactoryBean itself will be matched against the * type. If "allowEagerInit" is not set, only raw FactoryBeans will be checked * (which doesn't require initialization of each FactoryBean). -$ *

Does not consider any hierarchy this factory may participate in. + *

Does not consider any hierarchy this factory may participate in. * Use BeanFactoryUtils' beanNamesForTypeIncludingAncestors * to include beans in ancestor factories too. *

Note: Does not ignore singleton beans that have been registered @@ -143,7 +143,7 @@ $ *

Does not consider any hierarchy this factory may participate in. * @see FactoryBean#getObjectType * @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, Class, boolean, boolean) */ - String[] getBeanNamesForType(Class type, boolean includeNonSingletons, boolean allowEagerInit); + String[] getBeanNamesForType(Class type, boolean includeNonSingletons, boolean allowEagerInit); /** * Return the bean instances that match the given object type (including diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/access/SingletonBeanFactoryLocator.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/access/SingletonBeanFactoryLocator.java index 2bdc1e5e5b0..7f1f73d1cbd 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/access/SingletonBeanFactoryLocator.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/access/SingletonBeanFactoryLocator.java @@ -432,6 +432,7 @@ public class SingletonBeanFactoryLocator implements BeanFactoryLocator { protected BeanFactory createDefinition(String resourceLocation, String factoryKey) { DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); + // TODO SPR-7508: consider whether to allow for setEnvironment() here (where would it come from?) ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); try { diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/AbstractPropertyPlaceholderConfigurer.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/AbstractPropertyPlaceholderConfigurer.java new file mode 100644 index 00000000000..c3fd69f3f6d --- /dev/null +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/AbstractPropertyPlaceholderConfigurer.java @@ -0,0 +1,191 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.config; + +import java.util.Properties; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.util.PropertyPlaceholderHelper; +import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver; +import org.springframework.util.StringValueResolver; + + +/** + * TODO SPR-7508: document. + * + * @author Chris Beams + * @author Juergen Hoeller + * @since 3.1 + */ +public abstract class AbstractPropertyPlaceholderConfigurer extends PropertyResourceConfigurer + implements BeanNameAware, BeanFactoryAware { + + /** Default placeholder prefix: "${" */ + public static final String DEFAULT_PLACEHOLDER_PREFIX = "${"; + /** Default placeholder suffix: "}" */ + public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}"; + /** Default value separator: ":" */ + public static final String DEFAULT_VALUE_SEPARATOR = ":"; + + protected String placeholderPrefix = DEFAULT_PLACEHOLDER_PREFIX; + + protected String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX; + + protected String valueSeparator = DEFAULT_VALUE_SEPARATOR; + + protected boolean ignoreUnresolvablePlaceholders = false; + + private String nullValue; + + private String beanName; + + private BeanFactory beanFactory; + + + protected abstract PlaceholderResolver getPlaceholderResolver(Properties props); + + /** + * Set the prefix that a placeholder string starts with. + * The default is "${". + * @see #DEFAULT_PLACEHOLDER_PREFIX + */ + public void setPlaceholderPrefix(String placeholderPrefix) { + this.placeholderPrefix = placeholderPrefix; + } + + /** + * Set the suffix that a placeholder string ends with. + * The default is "}". + * @see #DEFAULT_PLACEHOLDER_SUFFIX + */ + public void setPlaceholderSuffix(String placeholderSuffix) { + this.placeholderSuffix = placeholderSuffix; + } + + /** + * Specify the separating character between the placeholder variable + * and the associated default value, or null if no such + * special character should be processed as a value separator. + * The default is ":". + */ + public void setValueSeparator(String valueSeparator) { + this.valueSeparator = valueSeparator; + } + + /** + * Set a value that should be treated as null when + * resolved as a placeholder value: e.g. "" (empty String) or "null". + *

Note that this will only apply to full property values, + * not to parts of concatenated values. + *

By default, no such null value is defined. This means that + * there is no way to express null as a property + * value unless you explictly map a corresponding value here. + */ + public void setNullValue(String nullValue) { + this.nullValue = nullValue; + } + + /** + * Set whether to ignore unresolvable placeholders. + *

Default is "false": An exception will be thrown if a placeholder fails + * to resolve. Switch this flag to "true" in order to preserve the placeholder + * String as-is in such a case, leaving it up to other placeholder configurers + * to resolve it. + */ + public void setIgnoreUnresolvablePlaceholders(boolean ignoreUnresolvablePlaceholders) { + this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders; + } + + /** + * Only necessary to check that we're not parsing our own bean definition, + * to avoid failing on unresolvable placeholders in properties file locations. + * The latter case can happen with placeholders for system properties in + * resource locations. + * @see #setLocations + * @see org.springframework.core.io.ResourceEditor + */ + public void setBeanName(String beanName) { + this.beanName = beanName; + } + + /** + * Only necessary to check that we're not parsing our own bean definition, + * to avoid failing on unresolvable placeholders in properties file locations. + * The latter case can happen with placeholders for system properties in + * resource locations. + * @see #setLocations + * @see org.springframework.core.io.ResourceEditor + */ + public void setBeanFactory(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + + + @Override + protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) + throws BeansException { + + StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props); + BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver); + + String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames(); + for (String curName : beanNames) { + // Check that we're not parsing our own bean definition, + // to avoid failing on unresolvable placeholders in properties file locations. + if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) { + BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName); + try { + visitor.visitBeanDefinition(bd); + } + catch (Exception ex) { + throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage()); + } + } + } + + // New in Spring 2.5: resolve placeholders in alias target names and aliases as well. + beanFactoryToProcess.resolveAliases(valueResolver); + + // New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes. + beanFactoryToProcess.addEmbeddedValueResolver(valueResolver); + } + + + private class PlaceholderResolvingStringValueResolver implements StringValueResolver { + + private final PropertyPlaceholderHelper helper; + + private final PlaceholderResolver resolver; + + public PlaceholderResolvingStringValueResolver(Properties props) { + this.helper = new PropertyPlaceholderHelper( + placeholderPrefix, placeholderSuffix, valueSeparator, ignoreUnresolvablePlaceholders); + this.resolver = getPlaceholderResolver(props); + } + + public String resolveStringValue(String strVal) throws BeansException { + String value = this.helper.replacePlaceholders(strVal, this.resolver); + return (value.equals(nullValue) ? null : value); + } + } + + +} diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java index a755ea124a7..2be34e583b2 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java @@ -173,7 +173,7 @@ public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, Single * @param requiredType type of the property * @param propertyEditorClass the {@link PropertyEditor} class to register */ - void registerCustomEditor(Class requiredType, Class propertyEditorClass); + void registerCustomEditor(Class requiredType, Class propertyEditorClass); /** * Initialize the given PropertyEditorRegistry with the custom editors diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ConfigurableListableBeanFactory.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ConfigurableListableBeanFactory.java index ff9d5ee1354..459003bb3d0 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ConfigurableListableBeanFactory.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ConfigurableListableBeanFactory.java @@ -44,7 +44,7 @@ public interface ConfigurableListableBeanFactory * for example, String. Default is none. * @param type the dependency type to ignore */ - void ignoreDependencyType(Class type); + void ignoreDependencyType(Class type); /** * Ignore the given dependency interface for autowiring. @@ -57,7 +57,7 @@ public interface ConfigurableListableBeanFactory * @see org.springframework.beans.factory.BeanFactoryAware * @see org.springframework.context.ApplicationContextAware */ - void ignoreDependencyInterface(Class ifc); + void ignoreDependencyInterface(Class ifc); /** * Register a special dependency type with corresponding autowired value. @@ -75,7 +75,7 @@ public interface ConfigurableListableBeanFactory * implementation of the {@link org.springframework.beans.factory.ObjectFactory} * interface, which allows for lazy resolution of the actual target value. */ - void registerResolvableDependency(Class dependencyType, Object autowiredValue); + void registerResolvableDependency(Class dependencyType, Object autowiredValue); /** * Determine whether the specified bean qualifies as an autowire candidate, diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.java index 7359d4e2160..5274e9a08b5 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.java @@ -19,15 +19,12 @@ package org.springframework.beans.factory.config; import java.util.Properties; import java.util.Set; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanDefinitionStoreException; -import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanNameAware; import org.springframework.core.Constants; import org.springframework.util.PropertyPlaceholderHelper; import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver; -import org.springframework.util.StringValueResolver; + /** * A property resource configurer that resolves placeholders in bean property values of @@ -81,6 +78,7 @@ import org.springframework.util.StringValueResolver; * be detected and decrypted accordingly before processing them. * * @author Juergen Hoeller + * @author Chris Beams * @since 02.10.2003 * @see #setLocations * @see #setProperties @@ -91,19 +89,9 @@ import org.springframework.util.StringValueResolver; * @see #convertPropertyValue * @see PropertyOverrideConfigurer */ -public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer +public class PropertyPlaceholderConfigurer extends AbstractPropertyPlaceholderConfigurer implements BeanNameAware, BeanFactoryAware { - /** Default placeholder prefix: "${" */ - public static final String DEFAULT_PLACEHOLDER_PREFIX = "${"; - - /** Default placeholder suffix: "}" */ - public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}"; - - /** Default value separator: ":" */ - public static final String DEFAULT_VALUE_SEPARATOR = ":"; - - /** Never check system properties. */ public static final int SYSTEM_PROPERTIES_MODE_NEVER = 0; @@ -122,52 +110,10 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer private static final Constants constants = new Constants(PropertyPlaceholderConfigurer.class); - private String placeholderPrefix = DEFAULT_PLACEHOLDER_PREFIX; - - private String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX; - - private String valueSeparator = DEFAULT_VALUE_SEPARATOR; - private int systemPropertiesMode = SYSTEM_PROPERTIES_MODE_FALLBACK; private boolean searchSystemEnvironment = true; - private boolean ignoreUnresolvablePlaceholders = false; - - private String nullValue; - - private String beanName; - - private BeanFactory beanFactory; - - - /** - * Set the prefix that a placeholder string starts with. - * The default is "${". - * @see #DEFAULT_PLACEHOLDER_PREFIX - */ - public void setPlaceholderPrefix(String placeholderPrefix) { - this.placeholderPrefix = placeholderPrefix; - } - - /** - * Set the suffix that a placeholder string ends with. - * The default is "}". - * @see #DEFAULT_PLACEHOLDER_SUFFIX - */ - public void setPlaceholderSuffix(String placeholderSuffix) { - this.placeholderSuffix = placeholderSuffix; - } - - /** - * Specify the separating character between the placeholder variable - * and the associated default value, or null if no such - * special character should be processed as a value separator. - * The default is ":". - */ - public void setValueSeparator(String valueSeparator) { - this.valueSeparator = valueSeparator; - } /** * Set the system property mode by the name of the corresponding constant, @@ -218,84 +164,6 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer this.searchSystemEnvironment = searchSystemEnvironment; } - /** - * Set whether to ignore unresolvable placeholders. - *

Default is "false": An exception will be thrown if a placeholder fails - * to resolve. Switch this flag to "true" in order to preserve the placeholder - * String as-is in such a case, leaving it up to other placeholder configurers - * to resolve it. - */ - public void setIgnoreUnresolvablePlaceholders(boolean ignoreUnresolvablePlaceholders) { - this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders; - } - - /** - * Set a value that should be treated as null when - * resolved as a placeholder value: e.g. "" (empty String) or "null". - *

Note that this will only apply to full property values, - * not to parts of concatenated values. - *

By default, no such null value is defined. This means that - * there is no way to express null as a property - * value unless you explictly map a corresponding value here. - */ - public void setNullValue(String nullValue) { - this.nullValue = nullValue; - } - - /** - * Only necessary to check that we're not parsing our own bean definition, - * to avoid failing on unresolvable placeholders in properties file locations. - * The latter case can happen with placeholders for system properties in - * resource locations. - * @see #setLocations - * @see org.springframework.core.io.ResourceEditor - */ - public void setBeanName(String beanName) { - this.beanName = beanName; - } - - /** - * Only necessary to check that we're not parsing our own bean definition, - * to avoid failing on unresolvable placeholders in properties file locations. - * The latter case can happen with placeholders for system properties in - * resource locations. - * @see #setLocations - * @see org.springframework.core.io.ResourceEditor - */ - public void setBeanFactory(BeanFactory beanFactory) { - this.beanFactory = beanFactory; - } - - - @Override - protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) - throws BeansException { - - StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props); - BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver); - - String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames(); - for (String curName : beanNames) { - // Check that we're not parsing our own bean definition, - // to avoid failing on unresolvable placeholders in properties file locations. - if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) { - BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName); - try { - visitor.visitBeanDefinition(bd); - } - catch (Exception ex) { - throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage()); - } - } - } - - // New in Spring 2.5: resolve placeholders in alias target names and aliases as well. - beanFactoryToProcess.resolveAliases(valueResolver); - - // New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes. - beanFactoryToProcess.addEmbeddedValueResolver(valueResolver); - } - /** * Resolve the given placeholder using the given properties, performing * a system properties check according to the given mode. @@ -379,30 +247,16 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer * Only retained for compatibility with Spring 2.5 extensions. */ @Deprecated - protected String parseStringValue(String strVal, Properties props, Set visitedPlaceholders) { + protected String parseStringValue(String strVal, Properties props, Set visitedPlaceholders) { PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper( placeholderPrefix, placeholderSuffix, valueSeparator, ignoreUnresolvablePlaceholders); PlaceholderResolver resolver = new PropertyPlaceholderConfigurerResolver(props); return helper.replacePlaceholders(strVal, resolver); } - - private class PlaceholderResolvingStringValueResolver implements StringValueResolver { - - private final PropertyPlaceholderHelper helper; - - private final PlaceholderResolver resolver; - - public PlaceholderResolvingStringValueResolver(Properties props) { - this.helper = new PropertyPlaceholderHelper( - placeholderPrefix, placeholderSuffix, valueSeparator, ignoreUnresolvablePlaceholders); - this.resolver = new PropertyPlaceholderConfigurerResolver(props); - } - - public String resolveStringValue(String strVal) throws BeansException { - String value = this.helper.replacePlaceholders(strVal, this.resolver); - return (value.equals(nullValue) ? null : value); - } + @Override + protected PlaceholderResolver getPlaceholderResolver(Properties props) { + return new PropertyPlaceholderConfigurerResolver(props); } @@ -419,4 +273,5 @@ public class PropertyPlaceholderConfigurer extends PropertyResourceConfigurer } } + } diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java index 37e5d98fc68..b2b1741f931 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java @@ -166,7 +166,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac setParentBeanFactory(parentBeanFactory); } - /** * Set the instantiation strategy to use for creating bean instances. * Default is CglibSubclassingInstantiationStrategy. diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinitionReader.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinitionReader.java index b991f208658..25fd17c84df 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinitionReader.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinitionReader.java @@ -21,8 +21,10 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.core.env.DefaultEnvironment; +import org.springframework.core.env.Environment; +import org.springframework.core.env.EnvironmentCapable; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; @@ -40,7 +42,7 @@ import org.springframework.util.Assert; * @since 11.12.2003 * @see BeanDefinitionReaderUtils */ -public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader { +public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable, BeanDefinitionReader { /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); @@ -51,6 +53,8 @@ public abstract class AbstractBeanDefinitionReader implements BeanDefinitionRead private ClassLoader beanClassLoader; + private Environment environment = new DefaultEnvironment(); + private BeanNameGenerator beanNameGenerator = new DefaultBeanNameGenerator(); @@ -62,9 +66,14 @@ public abstract class AbstractBeanDefinitionReader implements BeanDefinitionRead * {@link org.springframework.context.ApplicationContext} implementations. *

If given a plain BeanDefinitionRegistry, the default ResourceLoader will be a * {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}. + *

If the the passed-in bean factory also implements {@link EnvironmentCapable} its + * environment will be used by this reader. Otherwise, the reader will initialize and + * use a {@link DefaultEnvironment}. All ApplicationContext implementations are + * EnvironmentCapable, while normal BeanFactory implementations are not. * @param registry the BeanFactory to load bean definitions into, * in the form of a BeanDefinitionRegistry * @see #setResourceLoader + * @see #setEnvironment */ protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); @@ -77,6 +86,14 @@ public abstract class AbstractBeanDefinitionReader implements BeanDefinitionRead else { this.resourceLoader = new PathMatchingResourcePatternResolver(); } + + // Inherit Environment if possible + if (this.registry instanceof EnvironmentCapable) { + this.environment = ((EnvironmentCapable)this.registry).getEnvironment(); + } + else { + this.environment = new DefaultEnvironment(); + } } @@ -122,6 +139,21 @@ public abstract class AbstractBeanDefinitionReader implements BeanDefinitionRead return this.beanClassLoader; } + /** + * TODO SPR-7508: document + * @param environment + */ + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + /** + * TODO SPR-7508: document + */ + public Environment getEnvironment() { + return this.environment; + } + /** * Set the BeanNameGenerator to use for anonymous beans * (without explicit bean name specified). diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java index bab57620706..69701005050 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java @@ -68,6 +68,9 @@ import org.springframework.beans.factory.config.Scope; import org.springframework.core.DecoratingClassLoader; import org.springframework.core.NamedThreadLocal; import org.springframework.core.convert.ConversionService; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.DefaultEnvironment; +import org.springframework.core.env.Environment; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; @@ -100,6 +103,7 @@ import org.springframework.util.StringValueResolver; * @author Rod Johnson * @author Juergen Hoeller * @author Costin Leau + * @author Chris Beams * @since 15 April 2001 * @see #getBeanDefinition * @see #createBean @@ -166,6 +170,9 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp private final ThreadLocal prototypesCurrentlyInCreation = new NamedThreadLocal("Prototype beans currently in creation"); + private ConfigurableEnvironment environment = new DefaultEnvironment(); + + /** * Create a new AbstractBeanFactory. */ @@ -189,7 +196,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } - + public T getBean(String name, Class requiredType) throws BeansException { return doGetBean(name, requiredType, null, false); } @@ -682,7 +689,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp return this.propertyEditorRegistrars; } - public void registerCustomEditor(Class requiredType, Class propertyEditorClass) { + public void registerCustomEditor(Class requiredType, Class propertyEditorClass) { Assert.notNull(requiredType, "Required type must not be null"); Assert.isAssignable(PropertyEditor.class, propertyEditorClass); this.customEditors.put(requiredType, propertyEditorClass); @@ -1253,7 +1260,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err); } } - + private Class doResolveBeanClass(RootBeanDefinition mbd, Class... typesToMatch) throws ClassNotFoundException { if (!ObjectUtils.isEmpty(typesToMatch)) { ClassLoader tempClassLoader = getTempClassLoader(); diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index cabc026e12a..2a5c55ec45f 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -203,6 +203,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto */ public void setAutowireCandidateResolver(final AutowireCandidateResolver autowireCandidateResolver) { Assert.notNull(autowireCandidateResolver, "AutowireCandidateResolver must not be null"); + // TODO SPR-7515: should also do EnvironmentAware injection here? if (autowireCandidateResolver instanceof BeanFactoryAware) { if (System.getSecurityManager() != null) { final BeanFactory target = this; @@ -460,7 +461,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto // Implementation of ConfigurableListableBeanFactory interface //--------------------------------------------------------------------- - public void registerResolvableDependency(Class dependencyType, Object autowiredValue) { + public void registerResolvableDependency(Class dependencyType, Object autowiredValue) { Assert.notNull(dependencyType, "Type must not be null"); if (autowiredValue != null) { Assert.isTrue((autowiredValue instanceof ObjectFactory || dependencyType.isInstance(autowiredValue)), diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/MergedBeanDefinitionPostProcessor.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/MergedBeanDefinitionPostProcessor.java index 48a534a9142..d9846442a9f 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/MergedBeanDefinitionPostProcessor.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/MergedBeanDefinitionPostProcessor.java @@ -43,6 +43,6 @@ public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor { * @param beanType the actual type of the managed bean instance * @param beanName the name of the bean */ - void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName); + void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName); } diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java index 3e8784b1817..b9b8b8caa4f 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java @@ -33,6 +33,8 @@ import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.SmartFactoryBean; import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.DefaultEnvironment; import org.springframework.util.StringUtils; /** @@ -59,6 +61,9 @@ public class StaticListableBeanFactory implements ListableBeanFactory { /** Map from bean name to bean instance */ private final Map beans = new HashMap(); + /** TODO SPR-7508: document */ + private ConfigurableEnvironment environment = new DefaultEnvironment(); + /** * Add a new singleton bean. diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/AbstractSingleBeanDefinitionParser.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/AbstractSingleBeanDefinitionParser.java index b7a72c099de..1c32c4f22de 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/AbstractSingleBeanDefinitionParser.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/AbstractSingleBeanDefinitionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2010 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. @@ -63,7 +63,7 @@ public abstract class AbstractSingleBeanDefinitionParser extends AbstractBeanDef if (parentName != null) { builder.getRawBeanDefinition().setParentName(parentName); } - Class beanClass = getBeanClass(element); + Class beanClass = getBeanClass(element); if (beanClass != null) { builder.getRawBeanDefinition().setBeanClass(beanClass); } @@ -111,7 +111,7 @@ public abstract class AbstractSingleBeanDefinitionParser extends AbstractBeanDef * the supplied Element, or null if none * @see #getBeanClassName */ - protected Class getBeanClass(Element element) { + protected Class getBeanClass(Element element) { return null; } diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParser.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParser.java index aab07a52d51..93ecbb44bb5 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParser.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2006 the original author or authors. + * Copyright 2002-2010 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. @@ -42,7 +42,7 @@ public interface BeanDefinitionParser { /** * Parse the specified {@link Element} and register the resulting * {@link BeanDefinition BeanDefinition(s)} with the - * {@link org.springframework.beans.factory.xml.ParserContext#getRegistry()} BeanDefinitionRegistry} + * {@link org.springframework.beans.factory.xml.ParserContext#getRegistry() BeanDefinitionRegistry} * embedded in the supplied {@link ParserContext}. *

Implementations must return the primary {@link BeanDefinition} that results * from the parse if they will ever be used in a nested fashion (for example as @@ -50,7 +50,8 @@ public interface BeanDefinitionParser { * null if they will not be used in a nested fashion. * @param element the element that is to be parsed into one or more {@link BeanDefinition BeanDefinitions} * @param parserContext the object encapsulating the current state of the parsing process; - * provides access to a {@link org.springframework.beans.factory.support.BeanDefinitionRegistry} + * provides access to a {@link org.springframework.beans.factory.support.BeanDefinitionRegistry + * BeanDefinitionRegistry}. * @return the primary {@link BeanDefinition} */ BeanDefinition parse(Element element, ParserContext parserContext); diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParserDelegate.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParserDelegate.java index bf96dd93518..de9123c2e3f 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParserDelegate.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParserDelegate.java @@ -58,6 +58,7 @@ import org.springframework.beans.factory.support.ManagedProperties; import org.springframework.beans.factory.support.ManagedSet; import org.springframework.beans.factory.support.MethodOverrides; import org.springframework.beans.factory.support.ReplaceOverride; +import org.springframework.core.env.Environment; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; @@ -92,10 +93,14 @@ public class BeanDefinitionParserDelegate { */ public static final String TRUE_VALUE = "true"; + public static final String FALSE_VALUE = "false"; + public static final String DEFAULT_VALUE = "default"; public static final String DESCRIPTION_ELEMENT = "description"; + public static final String AUTOWIRE_NO_VALUE = "no"; + public static final String AUTOWIRE_BY_NAME_VALUE = "byName"; public static final String AUTOWIRE_BY_TYPE_VALUE = "byType"; @@ -239,19 +244,25 @@ public class BeanDefinitionParserDelegate { private final ParseState parseState = new ParseState(); + private Environment environment; + /** - * Stores all used bean names so we can enforce uniqueness on a per file basis. + * Stores all used bean names so we can enforce uniqueness on a per + * beans-element basis. Duplicate bean ids/names may not exist within the + * same level of beans element nesting, but may be duplicated across levels. */ private final Set usedNames = new HashSet(); /** * Create a new BeanDefinitionParserDelegate associated with the - * supplied {@link XmlReaderContext}. + * supplied {@link XmlReaderContext} and {@link Environment}. */ - public BeanDefinitionParserDelegate(XmlReaderContext readerContext) { + public BeanDefinitionParserDelegate(XmlReaderContext readerContext, Environment environment) { Assert.notNull(readerContext, "XmlReaderContext must not be null"); + Assert.notNull(readerContext, "Environment must not be null"); this.readerContext = readerContext; + this.environment = environment; } /** @@ -261,6 +272,12 @@ public class BeanDefinitionParserDelegate { return this.readerContext; } + /** + * Get the {@link Environment} associated with this helper instance. + */ + public final Environment getEnvironment() { + return this.environment; + } /** * Invoke the {@link org.springframework.beans.factory.parsing.SourceExtractor} to pull the @@ -294,33 +311,69 @@ public class BeanDefinitionParserDelegate { /** * Initialize the default lazy-init, autowire, dependency check settings, - * init-method, destroy-method and merge settings. - * @see #populateDefaults(DocumentDefaultsDefinition, org.w3c.dom.Element) + * init-method, destroy-method and merge settings. Support nested 'beans' + * element use cases by falling back to parent in case the + * defaults are not explicitly set locally. + * @see #populateDefaults(DocumentDefaultsDefinition, DocumentDefaultsDefinition, org.w3c.dom.Element) * @see #getDefaults() */ - public void initDefaults(Element root) { - populateDefaults(this.defaults, root); + public void initDefaults(Element root, BeanDefinitionParserDelegate parent) { + populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root); this.readerContext.fireDefaultsRegistered(this.defaults); } /** * Populate the given DocumentDefaultsDefinition instance with the default lazy-init, * autowire, dependency check settings, init-method, destroy-method and merge settings. + * Support nested 'beans' element use cases by falling back to + * parentDefaults in case the defaults are not explicitly set + * locally. + * @param defaults the defaults to populate + * @param defaults the parent BeanDefinitionParserDelegate (if any) defaults to fall back to + * @param root the root element of the current bean definition document (or nested beans element) */ - protected void populateDefaults(DocumentDefaultsDefinition defaults, Element root) { - defaults.setLazyInit(root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE)); - defaults.setMerge(root.getAttribute(DEFAULT_MERGE_ATTRIBUTE)); - defaults.setAutowire(root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE)); + protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) { + String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE); + if (DEFAULT_VALUE.equals(lazyInit)) { + lazyInit = parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE; + } + defaults.setLazyInit(lazyInit); + + String merge = root.getAttribute(DEFAULT_MERGE_ATTRIBUTE); + if (DEFAULT_VALUE.equals(merge)) { + merge = parentDefaults != null ? parentDefaults.getMerge() : FALSE_VALUE; + } + defaults.setMerge(merge); + + String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE); + if (DEFAULT_VALUE.equals(autowire)) { + autowire = parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE; + } + defaults.setAutowire(autowire); + + // don't fall back to parentDefaults for dependency-check as it's no + // longer supported in as of 3.0. Therefore, no nested + // would ever need to fall back to it. defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE)); + if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) { defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)); + } else if (parentDefaults != null) { + defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates()); } + if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) { defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)); + } else if (parentDefaults != null) { + defaults.setInitMethod(parentDefaults.getInitMethod()); } + if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) { defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)); + } else if (parentDefaults != null) { + defaults.setDestroyMethod(parentDefaults.getDestroyMethod()); } + defaults.setSource(this.readerContext.extractSource(root)); } @@ -431,7 +484,8 @@ public class BeanDefinitionParserDelegate { } /** - * Validate that the specified bean name and aliases have not been used already. + * Validate that the specified bean name and aliases have not been used already + * within the current level of beans element nesting. */ protected void checkNameUniqueness(String beanName, List aliases, Element beanElement) { String foundName = null; @@ -443,7 +497,7 @@ public class BeanDefinitionParserDelegate { foundName = (String) CollectionUtils.findFirstMatch(this.usedNames, aliases); } if (foundName != null) { - error("Bean name '" + foundName + "' is already used in this file", beanElement); + error("Bean name '" + foundName + "' is already used in this element", beanElement); } this.usedNames.add(beanName); diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/DefaultBeanDefinitionDocumentReader.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/DefaultBeanDefinitionDocumentReader.java index e5447ada681..1b6ed450d1a 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/DefaultBeanDefinitionDocumentReader.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/DefaultBeanDefinitionDocumentReader.java @@ -16,6 +16,9 @@ package org.springframework.beans.factory.xml; +import static org.springframework.util.StringUtils.commaDelimitedListToStringArray; +import static org.springframework.util.StringUtils.trimAllWhitespace; + import java.io.IOException; import java.net.URISyntaxException; import java.util.LinkedHashSet; @@ -32,11 +35,11 @@ import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; +import org.springframework.core.env.Environment; import org.springframework.core.io.Resource; import org.springframework.core.io.support.ResourcePatternUtils; import org.springframework.util.ResourceUtils; import org.springframework.util.StringUtils; -import org.springframework.util.SystemPropertyUtils; /** * Default implementation of the {@link BeanDefinitionDocumentReader} interface. @@ -59,6 +62,8 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume public static final String BEAN_ELEMENT = BeanDefinitionParserDelegate.BEAN_ELEMENT; + public static final String NESTED_BEANS_ELEMENT = "beans"; + public static final String ALIAS_ELEMENT = "alias"; public static final String NAME_ATTRIBUTE = "name"; @@ -69,14 +74,29 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume public static final String RESOURCE_ATTRIBUTE = "resource"; + /** @see org.springframework.context.annotation.Profile */ + public static final String PROFILE_ATTRIBUTE = "profile"; + protected final Log logger = LogFactory.getLog(getClass()); private XmlReaderContext readerContext; + private Environment environment; + + private BeanDefinitionParserDelegate delegate; + /** - * Parses bean definitions according to the "spring-beans" DTD. + * TODO SPR-7508: document + * @param environment + */ + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + /** + * Parses bean definitions according to the "spring-beans" DTD. TODO SPR-7508 XSD *

Opens a DOM Document; then initializes the default settings * specified at <beans> level; then parses * the contained bean definitions. @@ -87,16 +107,49 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); - BeanDefinitionParserDelegate delegate = createHelper(readerContext, root); - - preProcessXml(root); - parseBeanDefinitions(root, delegate); - postProcessXml(root); + doRegisterBeanDefinitions(root); } - protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext, Element root) { - BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext); - delegate.initDefaults(root); + protected void doRegisterBeanDefinitions(Element root) { + String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); + boolean isCandidate = false; + if (profileSpec == null || profileSpec.equals("")) { + isCandidate = true; + } else { + String[] profiles = commaDelimitedListToStringArray(trimAllWhitespace(profileSpec)); + for (String profile : profiles) { + if (this.environment.getActiveProfiles().contains(profile)) { + isCandidate = true; + break; + } + } + } + + if (!isCandidate) { + // TODO SPR-7508 logging + // logger.debug(format("XML is targeted for environment [%s], but current environment is [%s]. Skipping", targetEnvironment, environment == null ? null : environment.getName())); + return; + } + + // any nested elements will cause recursion in this method. in + // order to propagate and preserve default-* attributes correctly, + // keep track of the current (parent) delegate, which may be null. Create + // the new (child) delegate with a reference to the parent for fallback purposes, + // then ultimately reset this.delegate back to its original (parent) reference. + // this behavior emulates a stack of delegates without actually necessitating one. + BeanDefinitionParserDelegate parent = this.delegate; + this.delegate = createHelper(readerContext, root, parent); + + preProcessXml(root); + parseBeanDefinitions(root, this.delegate); + postProcessXml(root); + + this.delegate = parent; + } + + protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) { + BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext, environment); + delegate.initDefaults(root, parentDelegate); return delegate; } @@ -152,6 +205,10 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } + else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { + // recurse + doRegisterBeanDefinitions(ele); + } } /** @@ -166,7 +223,7 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume } // Resolve system properties: e.g. "${user.dir}" - location = SystemPropertyUtils.resolvePlaceholders(location); + location = environment.resolveRequiredPlaceholders(location); Set actualResources = new LinkedHashSet(4); diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReader.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReader.java index fb7f12c6292..baf2ccc4e8e 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReader.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/XmlBeanDefinitionReader.java @@ -65,6 +65,7 @@ import org.springframework.util.xml.XmlValidationModeDetector; * * @author Juergen Hoeller * @author Rob Harrop + * @author Chris Beams * @since 26.11.2003 * @see #setDocumentReaderClass * @see BeanDefinitionDocumentReader @@ -103,7 +104,7 @@ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { private boolean namespaceAware = false; - private Class documentReaderClass = DefaultBeanDefinitionDocumentReader.class; + private Class documentReaderClass = DefaultBeanDefinitionDocumentReader.class; private ProblemReporter problemReporter = new FailFastProblemReporter(); @@ -134,7 +135,6 @@ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { super(registry); } - /** * Set whether to use XML validation. Default is true. *

This method switches namespace awareness on if validation is turned off, @@ -283,7 +283,7 @@ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { *

The default is {@link DefaultBeanDefinitionDocumentReader}. * @param documentReaderClass the desired BeanDefinitionDocumentReader implementation class */ - public void setDocumentReaderClass(Class documentReaderClass) { + public void setDocumentReaderClass(Class documentReaderClass) { if (documentReaderClass == null || !BeanDefinitionDocumentReader.class.isAssignableFrom(documentReaderClass)) { throw new IllegalArgumentException( "documentReaderClass must be an implementation of the BeanDefinitionDocumentReader interface"); @@ -487,8 +487,12 @@ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { * @see BeanDefinitionDocumentReader#registerBeanDefinitions */ public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { - // Read document based on new BeanDefinitionDocumentReader SPI. + // Read document based on new BeanDefinitionDocumentReader SPI. // TODO SPR-7508: polish - remove comment BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); + // TODO SPR-7508: remove ugly cast + if (documentReader instanceof DefaultBeanDefinitionDocumentReader) { + ((DefaultBeanDefinitionDocumentReader)documentReader).setEnvironment(this.getEnvironment()); + } int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; @@ -500,7 +504,6 @@ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { *

The default implementation instantiates the specified "documentReaderClass". * @see #setDocumentReaderClass */ - @SuppressWarnings("unchecked") protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() { return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass)); } diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/XmlBeanFactory.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/XmlBeanFactory.java index d5c42c719d1..4abaa002a6f 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/XmlBeanFactory.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/XmlBeanFactory.java @@ -19,6 +19,7 @@ package org.springframework.beans.factory.xml; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.io.Resource; /** @@ -34,7 +35,7 @@ import org.springframework.core.io.Resource; *

This class registers each bean definition with the {@link DefaultListableBeanFactory} * superclass, and relies on the latter's implementation of the {@link BeanFactory} interface. * It supports singletons, prototypes, and references to either of these kinds of bean. - * See "spring-beans-2.0.dtd" for details on options and configuration style. + * See "spring-beans-2.0.dtd" for details on options and configuration style. // TODO SPR-7508 polish - s/dtd/xsd/ * *

For advanced needs, consider using a {@link DefaultListableBeanFactory} with * an {@link XmlBeanDefinitionReader}. The latter allows for reading from multiple XML @@ -42,10 +43,14 @@ import org.springframework.core.io.Resource; * * @author Rod Johnson * @author Juergen Hoeller + * @author Chris Beams * @since 15 April 2001 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory * @see XmlBeanDefinitionReader + * @deprecated as of Spring 3.1 in favor of {@link DefaultListableBeanFactory} and + * {@link XmlBeanDefinitionReader} */ +@Deprecated public class XmlBeanFactory extends DefaultListableBeanFactory { private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this); @@ -58,7 +63,7 @@ public class XmlBeanFactory extends DefaultListableBeanFactory { * @throws BeansException in case of loading or parsing errors */ public XmlBeanFactory(Resource resource) throws BeansException { - this(resource, null); + this(resource, (BeanFactory)null); } /** diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/support/ResourceEditorRegistrar.java b/org.springframework.beans/src/main/java/org/springframework/beans/support/ResourceEditorRegistrar.java index 3c61d853506..abb6d20551e 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/support/ResourceEditorRegistrar.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/support/ResourceEditorRegistrar.java @@ -34,6 +34,8 @@ import org.springframework.beans.propertyeditors.InputSourceEditor; import org.springframework.beans.propertyeditors.InputStreamEditor; import org.springframework.beans.propertyeditors.URIEditor; import org.springframework.beans.propertyeditors.URLEditor; +import org.springframework.core.env.DefaultEnvironment; +import org.springframework.core.env.Environment; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceEditor; import org.springframework.core.io.ResourceLoader; @@ -53,9 +55,26 @@ import org.springframework.core.io.support.ResourcePatternResolver; */ public class ResourceEditorRegistrar implements PropertyEditorRegistrar { + private final Environment environment; + private final ResourceLoader resourceLoader; + /** + * Create a new ResourceEditorRegistrar for the given {@link ResourceLoader} + * using a {@link DefaultEnvironment}. + * @param resourceLoader the ResourceLoader (or ResourcePatternResolver) + * to create editors for (usually an ApplicationContext) + * @see org.springframework.core.io.support.ResourcePatternResolver + * @see org.springframework.context.ApplicationContext + * @deprecated as of Spring 3.1 in favor of + * {@link ResourceEditorRegistrar#ResourceEditorRegistrar(ResourceLoader, Environment)} + */ + @Deprecated + public ResourceEditorRegistrar(ResourceLoader resourceLoader) { + this(resourceLoader, new DefaultEnvironment()); + } + /** * Create a new ResourceEditorRegistrar for the given ResourceLoader * @param resourceLoader the ResourceLoader (or ResourcePatternResolver) @@ -63,8 +82,9 @@ public class ResourceEditorRegistrar implements PropertyEditorRegistrar { * @see org.springframework.core.io.support.ResourcePatternResolver * @see org.springframework.context.ApplicationContext */ - public ResourceEditorRegistrar(ResourceLoader resourceLoader) { + public ResourceEditorRegistrar(ResourceLoader resourceLoader, Environment environment) { this.resourceLoader = resourceLoader; + this.environment = environment; } @@ -82,7 +102,7 @@ public class ResourceEditorRegistrar implements PropertyEditorRegistrar { * @see org.springframework.core.io.support.ResourceArrayPropertyEditor */ public void registerCustomEditors(PropertyEditorRegistry registry) { - ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader); + ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.environment); doRegisterEditor(registry, Resource.class, baseEditor); doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor)); doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor)); @@ -96,7 +116,7 @@ public class ResourceEditorRegistrar implements PropertyEditorRegistrar { if (this.resourceLoader instanceof ResourcePatternResolver) { doRegisterEditor(registry, Resource[].class, - new ResourceArrayPropertyEditor((ResourcePatternResolver) this.resourceLoader)); + new ResourceArrayPropertyEditor((ResourcePatternResolver) this.resourceLoader, this.environment)); } } diff --git a/org.springframework.beans/src/main/resources/META-INF/spring.schemas b/org.springframework.beans/src/main/resources/META-INF/spring.schemas index e843e676fdb..a0d82637fbe 100644 --- a/org.springframework.beans/src/main/resources/META-INF/spring.schemas +++ b/org.springframework.beans/src/main/resources/META-INF/spring.schemas @@ -1,12 +1,15 @@ http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd http\://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsd http\://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd -http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd +http\://www.springframework.org/schema/beans/spring-beans-3.1.xsd=org/springframework/beans/factory/xml/spring-beans-3.1.xsd +http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-3.1.xsd http\://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd http\://www.springframework.org/schema/tool/spring-tool-2.5.xsd=org/springframework/beans/factory/xml/spring-tool-2.5.xsd http\://www.springframework.org/schema/tool/spring-tool-3.0.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd -http\://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd +http\://www.springframework.org/schema/tool/spring-tool-3.1.xsd=org/springframework/beans/factory/xml/spring-tool-3.1.xsd +http\://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-3.1.xsd http\://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd http\://www.springframework.org/schema/util/spring-util-2.5.xsd=org/springframework/beans/factory/xml/spring-util-2.5.xsd http\://www.springframework.org/schema/util/spring-util-3.0.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd -http\://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd +http\://www.springframework.org/schema/util/spring-util-3.1.xsd=org/springframework/beans/factory/xml/spring-util-3.1.xsd +http\://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-3.1.xsd diff --git a/org.springframework.beans/src/main/resources/org/springframework/beans/factory/xml/spring-beans-3.1.xsd b/org.springframework.beans/src/main/resources/org/springframework/beans/factory/xml/spring-beans-3.1.xsd new file mode 100644 index 00000000000..5fa65f6bbd7 --- /dev/null +++ b/org.springframework.beans/src/main/resources/org/springframework/beans/factory/xml/spring-beans-3.1.xsd @@ -0,0 +1,1165 @@ + + + + + + + + + + + + + + + + + + element. + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + element (or "ref" + attribute). We recommend this in most cases as it makes documentation + more explicit. + + Note that this default mode also allows for annotation-driven autowiring, + if activated. "no" refers to externally driven autowiring only, not + affecting any autowiring demands that the bean class itself expresses. + + 2. "byName" + Autowiring by property name. If a bean of class Cat exposes a "dog" + property, Spring will try to set this to the value of the bean "dog" + in the current container. If there is no matching bean by name, nothing + special happens. + + 3. "byType" + Autowiring if there is exactly one bean of the property type in the + container. If there is more than one, a fatal error is raised, and + you cannot use byType autowiring for that bean. If there is none, + nothing special happens. + + 4. "constructor" + Analogous to "byType" for constructor arguments. If there is not exactly + one bean of the constructor argument type in the bean factory, a fatal + error is raised. + + Note that explicit dependencies, i.e. "property" and "constructor-arg" + elements, always override autowiring. + + Note: This attribute will not be inherited by child bean definitions. + Hence, it needs to be specified per concrete bean definition. + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + " element. + ]]> + + + + + ..." element. + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ". + ]]> + + + + + ..." element. + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ". + ]]> + + + + + ..." + element. + ]]> + + + + + ". + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.beans/src/main/resources/org/springframework/beans/factory/xml/spring-tool-3.1.xsd b/org.springframework.beans/src/main/resources/org/springframework/beans/factory/xml/spring-tool-3.1.xsd new file mode 100644 index 00000000000..9d84906adea --- /dev/null +++ b/org.springframework.beans/src/main/resources/org/springframework/beans/factory/xml/spring-tool-3.1.xsd @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.beans/src/main/resources/org/springframework/beans/factory/xml/spring-util-3.1.xsd b/org.springframework.beans/src/main/resources/org/springframework/beans/factory/xml/spring-util-3.1.xsd new file mode 100644 index 00000000000..9b5774a46c4 --- /dev/null +++ b/org.springframework.beans/src/main/resources/org/springframework/beans/factory/xml/spring-util-3.1.xsd @@ -0,0 +1,212 @@ + + + + + + + + + + + Reference a public, static field on a type and expose its value as + a bean. For example <util:constant static-field="java.lang.Integer.MAX_VALUE"/>. + + + + + + + + + + + + Reference a property on a bean (or as a nested value) and expose its values as + a bean. For example <util:property-path path="order.customer.name"/>. + + + + + + + + + + + + Builds a List instance of the specified type, populated with the specified content. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Builds a Set instance of the specified type, populated with the specified content. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Builds a Map instance of the specified type, populated with the specified content. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Loads a Properties instance from the resource location specified by the 'location' attribute. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurerTests.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurerTests.java index 108a38b2a59..bbbd1eaacee 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurerTests.java +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurerTests.java @@ -1,44 +1,281 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.beans.factory.config; import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.assertThat; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; +import static org.springframework.beans.factory.support.BeanDefinitionReaderUtils.registerWithGeneratedName; +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.Map; +import java.util.Properties; + +import org.junit.After; +import org.junit.Before; import org.junit.Test; +import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.core.io.ByteArrayResource; import test.beans.TestBean; + /** - * Tests cornering SPR-7547. + * Unit tests for {@link EnvironmentAwarePropertyPlaceholderConfigurer}. * + * @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"; + private static final String P1_SYSTEM_ENV_VAL = "p1SystemEnvVal"; + + private DefaultListableBeanFactory bf; + private AbstractPropertyPlaceholderConfigurer ppc; + private Properties ppcProperties; + + private AbstractBeanDefinition p1BeanDef; + + @Before + public void setUp() { + p1BeanDef = rootBeanDefinition(TestBean.class) + .addPropertyValue("name", "${"+P1+"}") + .getBeanDefinition(); + + bf = new DefaultListableBeanFactory(); + + ppcProperties = new Properties(); + ppcProperties.setProperty(P1, P1_LOCAL_PROPS_VAL); + System.setProperty(P1, P1_SYSTEM_PROPS_VAL); + getModifiableSystemEnvironment().put(P1, P1_SYSTEM_ENV_VAL); + ppc = new PropertyPlaceholderConfigurer(); + ppc.setProperties(ppcProperties); + + } + + @After + public void tearDown() { + System.clearProperty(P1); + getModifiableSystemEnvironment().remove(P1); + } + + + // ------------------------------------------------------------------------- + // Tests to ensure backward-compatibility for Environment refactoring + // ------------------------------------------------------------------------- + + @Test + public void resolveFromSystemProperties() { + getModifiableSystemEnvironment().put("otherKey", "systemValue"); + p1BeanDef = rootBeanDefinition(TestBean.class) + .addPropertyValue("name", "${"+P1+"}") + .addPropertyValue("sex", "${otherKey}") + .getBeanDefinition(); + registerWithGeneratedName(p1BeanDef, bf); + ppc.postProcessBeanFactory(bf); + TestBean bean = bf.getBean(TestBean.class); + assertThat(bean.getName(), equalTo(P1_LOCAL_PROPS_VAL)); + assertThat(bean.getSex(), equalTo("systemValue")); + getModifiableSystemEnvironment().remove("otherKey"); + } + + @Test + public void resolveFromLocalProperties() { + tearDown(); // eliminate entries from system props/environment + registerWithGeneratedName(p1BeanDef, bf); + ppc.postProcessBeanFactory(bf); + TestBean bean = bf.getBean(TestBean.class); + assertThat(bean.getName(), equalTo(P1_LOCAL_PROPS_VAL)); + } + + @Test + public void setSystemPropertiesMode_defaultIsFallback() { + registerWithGeneratedName(p1BeanDef, bf); + ppc.postProcessBeanFactory(bf); + TestBean bean = bf.getBean(TestBean.class); + assertThat(bean.getName(), equalTo(P1_LOCAL_PROPS_VAL)); + } + + /* + @Test + public void setSystemSystemPropertiesMode_toOverride_andResolveFromSystemProperties() { + registerWithGeneratedName(p1BeanDef, bf); + ppc.setSystemPropertiesMode(PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_OVERRIDE); + ppc.postProcessBeanFactory(bf); + TestBean bean = bf.getBean(TestBean.class); + assertThat(bean.getName(), equalTo(P1_SYSTEM_PROPS_VAL)); + } + + @Test + public void setSystemSystemPropertiesMode_toOverride_andResolveFromSystemEnvironment() { + registerWithGeneratedName(p1BeanDef, bf); + System.clearProperty(P1); // will now fall all the way back to system environment + ppc.setSystemPropertiesMode(PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_OVERRIDE); + ppc.postProcessBeanFactory(bf); + TestBean bean = bf.getBean(TestBean.class); + assertThat(bean.getName(), equalTo(P1_SYSTEM_ENV_VAL)); + } + + @Test + public void setSystemSystemPropertiesMode_toOverride_andSetSearchSystemEnvironment_toFalse() { + registerWithGeneratedName(p1BeanDef, bf); + System.clearProperty(P1); // will now fall all the way back to system environment + ppc.setSearchSystemEnvironment(false); + ppc.setSystemPropertiesMode(PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_OVERRIDE); + ppc.postProcessBeanFactory(bf); + TestBean bean = bf.getBean(TestBean.class); + assertThat(bean.getName(), equalTo(P1_LOCAL_PROPS_VAL)); // has to resort to local props + } + */ /** - * Prior to the fix for SPR-7547, the following would throw - * IllegalStateException because the PropertiesLoaderSupport base class - * assumed ByteArrayResource implements Resource.getFilename(). It does - * not, and AbstractResource.getFilename() is called instead, raising the - * exception. The following now works, as getFilename() is called in a - * try/catch to check whether the resource is actually file-based or not. - * - * See SPR-7552, which suggests paths to address the root issue rather than - * just patching the problem. + * Creates a scenario in which two PPCs are configured, each with different + * settings regarding resolving properties from the environment. */ @Test - public void repro() { + public void twoPlacholderConfigurers_withConflictingSettings() { + String P2 = "p2"; + String P2_LOCAL_PROPS_VAL = "p2LocalPropsVal"; + String P2_SYSTEM_PROPS_VAL = "p2SystemPropsVal"; + String P2_SYSTEM_ENV_VAL = "p2SystemEnvVal"; + + AbstractBeanDefinition p2BeanDef = rootBeanDefinition(TestBean.class) + .addPropertyValue("name", "${"+P1+"}") + .addPropertyValue("country", "${"+P2+"}") + .getBeanDefinition(); + + bf.registerBeanDefinition("p1Bean", p1BeanDef); + bf.registerBeanDefinition("p2Bean", p2BeanDef); + + ppc.setIgnoreUnresolvablePlaceholders(true); + ppc.postProcessBeanFactory(bf); + + System.setProperty(P2, P2_SYSTEM_PROPS_VAL); + getModifiableSystemEnvironment().put(P2, P2_SYSTEM_ENV_VAL); + Properties ppc2Properties = new Properties(); + ppc2Properties.put(P2, P2_LOCAL_PROPS_VAL); + + PropertyPlaceholderConfigurer ppc2 = new PropertyPlaceholderConfigurer(); + ppc2.setSystemPropertiesMode(PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_OVERRIDE); + ppc2.setProperties(ppc2Properties); + + ppc2Properties = new Properties(); + ppc2Properties.setProperty(P2, P2_LOCAL_PROPS_VAL); + ppc2.postProcessBeanFactory(bf); + + TestBean p1Bean = bf.getBean("p1Bean", TestBean.class); + assertThat(p1Bean.getName(), equalTo(P1_LOCAL_PROPS_VAL)); + + TestBean p2Bean = bf.getBean("p2Bean", TestBean.class); + assertThat(p2Bean.getName(), equalTo(P1_LOCAL_PROPS_VAL)); + assertThat(p2Bean.getCountry(), equalTo(P2_SYSTEM_PROPS_VAL)); + + System.clearProperty(P2); + getModifiableSystemEnvironment().remove(P2); + } + + @Test + public void customPlaceholderPrefixAndSuffix() { + PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); + ppc.setPlaceholderPrefix("@<"); + ppc.setPlaceholderSuffix(">"); + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); bf.registerBeanDefinition("testBean", rootBeanDefinition(TestBean.class) - .addPropertyValue("name", "${my.name}").getBeanDefinition()); - PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); - ppc.setLocation(new ByteArrayResource("my.name=Inigo Montoya".getBytes())); - ppc.postProcessBeanFactory(bf); + .addPropertyValue("name", "@") + .addPropertyValue("sex", "${key2}") + .getBeanDefinition()); - TestBean testBean = bf.getBean(TestBean.class); - assertThat(testBean.getName(), equalTo("Inigo Montoya")); + System.setProperty("key1", "systemKey1Value"); + System.setProperty("key2", "systemKey2Value"); + ppc.postProcessBeanFactory(bf); + System.clearProperty("key1"); + System.clearProperty("key2"); + + assertThat(bf.getBean(TestBean.class).getName(), is("systemKey1Value")); + assertThat(bf.getBean(TestBean.class).getSex(), is("${key2}")); + } + + @Test + public void nullValueIsPreserved() { + PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); + ppc.setNullValue("customNull"); + getModifiableSystemEnvironment().put("my.name", "customNull"); + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerBeanDefinition("testBean", rootBeanDefinition(TestBean.class) + .addPropertyValue("name", "${my.name}") + .getBeanDefinition()); + ppc.postProcessBeanFactory(bf); + assertThat(bf.getBean(TestBean.class).getName(), nullValue()); + getModifiableSystemEnvironment().remove("my.name"); + } + + + // ------------------------------------------------------------------------- + // Tests for functionality not possible prior to Environment refactoring + // ------------------------------------------------------------------------- + + /** + * Tests that properties against a BeanFactory's Environment are used by + * PropertyPlaceholderConfigurer during placeholder resolution. + @Test @SuppressWarnings({ "unchecked", "rawtypes", "serial" }) + public void replacePlaceholdersFromBeanFactoryEnvironmentPropertySources() { + System.setProperty("key1", "systemValue"); + + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.getEnvironment().addPropertySource("psCustom", new HashMap() {{ put("key1", "customValue"); }}); + bf.registerBeanDefinition("testBean", + rootBeanDefinition(TestBean.class).addPropertyValue("name", "${key1}").getBeanDefinition()); + + new PropertyPlaceholderConfigurer().postProcessBeanFactory(bf); + assertThat(bf.getBean(TestBean.class).getName(), is("customValue")); + + System.clearProperty("key1"); + } + */ + + + // ------------------------------------------------------------------------- + // Utilities + // ------------------------------------------------------------------------- + + // TODO SPR-7508: duplicated from EnvironmentPropertyResolutionSearchTests + @SuppressWarnings("unchecked") + private static Map getModifiableSystemEnvironment() { + Class[] classes = Collections.class.getDeclaredClasses(); + Map env = System.getenv(); + for (Class cl : classes) { + if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) { + try { + Field field = cl.getDeclaredField("m"); + field.setAccessible(true); + Object obj = field.get(env); + return (Map) obj; + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + } + throw new IllegalStateException(); } } diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/PropertyResourceConfigurerTests.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/PropertyResourceConfigurerTests.java index d4e59c3875d..ca4d5afbefb 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/PropertyResourceConfigurerTests.java +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/PropertyResourceConfigurerTests.java @@ -16,6 +16,14 @@ package org.springframework.beans.factory.config; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition; +import static test.util.TestResourceUtils.qualifiedResource; + import java.util.Collections; import java.util.List; import java.util.Map; @@ -23,18 +31,12 @@ import java.util.Properties; import java.util.Set; import java.util.prefs.Preferences; -import static org.junit.Assert.*; import org.junit.Before; 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.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.BeanInitializationException; 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.DefaultListableBeanFactory; import org.springframework.beans.factory.support.ManagedList; @@ -43,11 +45,15 @@ import org.springframework.beans.factory.support.ManagedSet; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.core.io.Resource; +import test.beans.IndexedTestBean; +import test.beans.TestBean; + /** * Unit tests for various {@link PropertyResourceConfigurer} implementations including: * {@link PropertyPlaceholderConfigurer}, {@link PropertyOverrideConfigurer} and * {@link PreferencesPlaceholderConfigurer}. * + * @see PropertyPlaceholderConfigurerTests * @since 02.10.2003 * @author Juergen Hoeller * @author Chris Beams @@ -794,6 +800,39 @@ public final class PropertyResourceConfigurerTests { Preferences.systemRoot().node("mySystemPath/mypath").remove("myName"); } + /* TODO SPR-7508: uncomment after EnvironmentAwarePropertyPlaceholderConfigurer implementation + @Test + public void testPreferencesPlaceholderConfigurerWithCustomPropertiesInEnvironment() { + factory.registerBeanDefinition("tb", + genericBeanDefinition(TestBean.class) + .addPropertyValue("name", "${mypath/myName}") + .addPropertyValue("age", "${myAge}") + .addPropertyValue("touchy", "${myotherpath/myTouchy}") + .getBeanDefinition()); + + Properties props = new Properties(); + props.put("myAge", "99"); + factory.getEnvironment().getPropertySources().add(new PropertiesPropertySource("localProps", props)); + + PreferencesPlaceholderConfigurer ppc = new PreferencesPlaceholderConfigurer(); + ppc.setSystemTreePath("mySystemPath"); + ppc.setUserTreePath("myUserPath"); + Preferences.systemRoot().node("mySystemPath").node("mypath").put("myName", "myNameValue"); + Preferences.systemRoot().node("mySystemPath/myotherpath").put("myTouchy", "myTouchyValue"); + Preferences.userRoot().node("myUserPath/myotherpath").put("myTouchy", "myOtherTouchyValue"); + ppc.afterPropertiesSet(); + ppc.postProcessBeanFactory(factory); + + TestBean tb = (TestBean) factory.getBean("tb"); + assertEquals("myNameValue", tb.getName()); + assertEquals(99, tb.getAge()); + assertEquals("myOtherTouchyValue", tb.getTouchy()); + Preferences.userRoot().node("myUserPath/myotherpath").remove("myTouchy"); + Preferences.systemRoot().node("mySystemPath/myotherpath").remove("myTouchy"); + Preferences.systemRoot().node("mySystemPath/mypath").remove("myName"); + } + */ + private static class ConvertingOverrideConfigurer extends PropertyOverrideConfigurer { diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/DuplicateBeanIdTests-multiLevel-context.xml b/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/DuplicateBeanIdTests-multiLevel-context.xml new file mode 100644 index 00000000000..b897d98858a --- /dev/null +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/DuplicateBeanIdTests-multiLevel-context.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/DuplicateBeanIdTests-sameLevel-context.xml b/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/DuplicateBeanIdTests-sameLevel-context.xml new file mode 100644 index 00000000000..e8bf2b4469a --- /dev/null +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/DuplicateBeanIdTests-sameLevel-context.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/DuplicateBeanIdTests.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/DuplicateBeanIdTests.java new file mode 100644 index 00000000000..1c9e484182e --- /dev/null +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/DuplicateBeanIdTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +import org.junit.Test; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.core.io.ClassPathResource; + +import test.beans.TestBean; + + +/** + * With Spring 3.1, bean id attributes (and all other id attributes across the + * core schemas) are no longer typed as xsd:id, but as xsd:string. This allows + * for using the same bean id within nested elements. + * + * Duplicate ids *within the same level of nesting* will still be treated as an + * error through the ProblemReporter, as this could never be an intended/valid + * situation. + * + * @author Chris Beams + * @since 3.1 + * @see org.springframework.beans.factory.xml.XmlBeanFactoryTests#testWithDuplicateName + * @see org.springframework.beans.factory.xml.XmlBeanFactoryTests#testWithDuplicateNameInAlias + */ +public class DuplicateBeanIdTests { + + @Test + public void duplicateBeanIdsWithinSameNestingLevelRaisesError() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(bf); + try { + reader.loadBeanDefinitions(new ClassPathResource("DuplicateBeanIdTests-sameLevel-context.xml", this.getClass())); + fail("expected parsing exception due to duplicate ids in same nesting level"); + } catch (Exception ex) { + // expected + } + } + + @Test + public void duplicateBeanIdsAcrossNestingLevels() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(bf); + reader.loadBeanDefinitions(new ClassPathResource("DuplicateBeanIdTests-multiLevel-context.xml", this.getClass())); + TestBean testBean = bf.getBean(TestBean.class); // there should be only one + assertThat(testBean.getName(), equalTo("nested")); + } +} diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/EnvironmentBeansTests.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/EnvironmentBeansTests.java new file mode 100644 index 00000000000..7d4a0f00b67 --- /dev/null +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/EnvironmentBeansTests.java @@ -0,0 +1,113 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import static org.hamcrest.CoreMatchers.not; +import static org.junit.Assert.assertThat; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.junit.Test; +import org.junit.internal.matchers.TypeSafeMatcher; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.core.env.DefaultEnvironment; +import org.springframework.core.io.ClassPathResource; + +/** + * TODO SPR-7508: document + * + * @author Chris Beams + */ +public class EnvironmentBeansTests { + + private static final String PROD_ELIGIBLE_XML = "environmentBeans-prodProfile.xml"; + private static final String DEV_ELIGIBLE_XML = "environmentBeans-devProfile.xml"; + private static final String ALL_ELIGIBLE_XML = "environmentBeans-noProfile.xml"; + private static final String MULTI_ELIGIBLE_XML = "environmentBeans-multiProfile.xml"; + private static final String UNKOWN_ELIGIBLE_XML = "environmentBeans-unknownProfile.xml"; + + private static final String PROD_ACTIVE = "prod"; + private static final String DEV_ACTIVE = "dev"; + private static final String NULL_ACTIVE = null; + private static final String UNKNOWN_ACTIVE = "unknown"; + private static final String[] NONE_ACTIVE = new String[0]; + private static final String[] MULTI_ACTIVE = new String[] { PROD_ACTIVE, DEV_ACTIVE }; + + private static final String TARGET_BEAN = "foo"; + + @Test + public void test() { + assertThat(beanFactoryFor(PROD_ELIGIBLE_XML, NONE_ACTIVE), not(containsTargetBean())); + assertThat(beanFactoryFor(PROD_ELIGIBLE_XML, NULL_ACTIVE), not(containsTargetBean())); + assertThat(beanFactoryFor(PROD_ELIGIBLE_XML, DEV_ACTIVE), not(containsTargetBean())); + assertThat(beanFactoryFor(PROD_ELIGIBLE_XML, PROD_ACTIVE), containsTargetBean()); + assertThat(beanFactoryFor(PROD_ELIGIBLE_XML, MULTI_ACTIVE), containsTargetBean()); + + assertThat(beanFactoryFor(DEV_ELIGIBLE_XML, NONE_ACTIVE), not(containsTargetBean())); + assertThat(beanFactoryFor(DEV_ELIGIBLE_XML, NULL_ACTIVE), not(containsTargetBean())); + assertThat(beanFactoryFor(DEV_ELIGIBLE_XML, PROD_ACTIVE), not(containsTargetBean())); + assertThat(beanFactoryFor(DEV_ELIGIBLE_XML, DEV_ACTIVE), containsTargetBean()); + assertThat(beanFactoryFor(DEV_ELIGIBLE_XML, MULTI_ACTIVE), containsTargetBean()); + + assertThat(beanFactoryFor(ALL_ELIGIBLE_XML, NONE_ACTIVE), containsTargetBean()); + assertThat(beanFactoryFor(ALL_ELIGIBLE_XML, NULL_ACTIVE), containsTargetBean()); + assertThat(beanFactoryFor(ALL_ELIGIBLE_XML, DEV_ACTIVE), containsTargetBean()); + assertThat(beanFactoryFor(ALL_ELIGIBLE_XML, PROD_ACTIVE), containsTargetBean()); + assertThat(beanFactoryFor(ALL_ELIGIBLE_XML, MULTI_ACTIVE), containsTargetBean()); + + assertThat(beanFactoryFor(MULTI_ELIGIBLE_XML, NONE_ACTIVE), not(containsTargetBean())); + assertThat(beanFactoryFor(MULTI_ELIGIBLE_XML, NULL_ACTIVE), not(containsTargetBean())); + assertThat(beanFactoryFor(MULTI_ELIGIBLE_XML, UNKNOWN_ACTIVE), not(containsTargetBean())); + assertThat(beanFactoryFor(MULTI_ELIGIBLE_XML, DEV_ACTIVE), containsTargetBean()); + assertThat(beanFactoryFor(MULTI_ELIGIBLE_XML, PROD_ACTIVE), containsTargetBean()); + assertThat(beanFactoryFor(MULTI_ELIGIBLE_XML, MULTI_ACTIVE), containsTargetBean()); + + assertThat(beanFactoryFor(UNKOWN_ELIGIBLE_XML, MULTI_ACTIVE), not(containsTargetBean())); + } + + private BeanDefinitionRegistry beanFactoryFor(String xmlName, String... activeProfileNames) { + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); + DefaultEnvironment env = new DefaultEnvironment(); + env.setActiveProfiles(activeProfileNames); + reader.setEnvironment(env); + reader.loadBeanDefinitions(new ClassPathResource(xmlName, getClass())); + return beanFactory; + } + + + private static Matcher containsBeanDefinition(final String beanName) { + return new TypeSafeMatcher() { + + public void describeTo(Description desc) { + desc.appendText("a BeanDefinitionRegistry containing bean named ") + .appendValue(beanName); + } + + @Override + public boolean matchesSafely(BeanDefinitionRegistry beanFactory) { + return beanFactory.containsBeanDefinition(beanName); + } + + }; + } + + private static Matcher containsTargetBean() { + return containsBeanDefinition(TARGET_BEAN); + } +} diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests.java new file mode 100644 index 00000000000..93cc77b27b9 --- /dev/null +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests.java @@ -0,0 +1,148 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.xml; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.Matchers.hasItems; +import static org.junit.Assert.assertThat; + +import org.junit.Test; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.core.io.ClassPathResource; + +import test.beans.TestBean; + +/** + * Tests for propagating enclosing beans element defaults to nested beans elements. + * + * @author Chris Beams + */ +public class NestedBeansElementAttributeRecursionTests { + + @Test + public void defaultLazyInit() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + new XmlBeanDefinitionReader(bf).loadBeanDefinitions( + new ClassPathResource("NestedBeansElementAttributeRecursionTests-lazy-context.xml", this.getClass())); + + BeanDefinition foo = bf.getBeanDefinition("foo"); + BeanDefinition bar = bf.getBeanDefinition("bar"); + BeanDefinition baz = bf.getBeanDefinition("baz"); + BeanDefinition biz = bf.getBeanDefinition("biz"); + BeanDefinition buz = bf.getBeanDefinition("buz"); + + assertThat(foo.isLazyInit(), is(false)); + assertThat(bar.isLazyInit(), is(true)); + assertThat(baz.isLazyInit(), is(false)); + assertThat(biz.isLazyInit(), is(true)); + assertThat(buz.isLazyInit(), is(true)); + } + + @Test + @SuppressWarnings("unchecked") + public void defaultMerge() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + new XmlBeanDefinitionReader(bf).loadBeanDefinitions( + new ClassPathResource("NestedBeansElementAttributeRecursionTests-merge-context.xml", this.getClass())); + + TestBean topLevel = bf.getBean("topLevelConcreteTestBean", TestBean.class); + // has the concrete child bean values + assertThat(topLevel.getSomeList(), hasItems("charlie", "delta")); + // but does not merge the parent values + assertThat(topLevel.getSomeList(), not(hasItems("alpha", "bravo"))); + + TestBean firstLevel = bf.getBean("firstLevelNestedTestBean", TestBean.class); + // merges all values + assertThat(firstLevel.getSomeList(), + hasItems("charlie", "delta", "echo", "foxtrot")); + + TestBean secondLevel = bf.getBean("secondLevelNestedTestBean", TestBean.class); + // merges all values + assertThat(secondLevel.getSomeList(), + hasItems("charlie", "delta", "echo", "foxtrot", "golf", "hotel")); + } + + @Test + public void defaultAutowireCandidates() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + new XmlBeanDefinitionReader(bf).loadBeanDefinitions( + new ClassPathResource("NestedBeansElementAttributeRecursionTests-autowire-candidates-context.xml", this.getClass())); + + assertThat(bf.getBeanDefinition("fooService").isAutowireCandidate(), is(true)); + assertThat(bf.getBeanDefinition("fooRepository").isAutowireCandidate(), is(true)); + assertThat(bf.getBeanDefinition("other").isAutowireCandidate(), is(false)); + + assertThat(bf.getBeanDefinition("barService").isAutowireCandidate(), is(true)); + assertThat(bf.getBeanDefinition("fooController").isAutowireCandidate(), is(false)); + + assertThat(bf.getBeanDefinition("bizRepository").isAutowireCandidate(), is(true)); + assertThat(bf.getBeanDefinition("bizService").isAutowireCandidate(), is(false)); + + assertThat(bf.getBeanDefinition("bazService").isAutowireCandidate(), is(true)); + assertThat(bf.getBeanDefinition("random").isAutowireCandidate(), is(false)); + assertThat(bf.getBeanDefinition("fooComponent").isAutowireCandidate(), is(false)); + assertThat(bf.getBeanDefinition("fRepository").isAutowireCandidate(), is(false)); + + assertThat(bf.getBeanDefinition("aComponent").isAutowireCandidate(), is(true)); + assertThat(bf.getBeanDefinition("someService").isAutowireCandidate(), is(false)); + } + + @Test + public void initMethod() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + new XmlBeanDefinitionReader(bf).loadBeanDefinitions( + new ClassPathResource("NestedBeansElementAttributeRecursionTests-init-destroy-context.xml", this.getClass())); + + InitDestroyBean beanA = bf.getBean("beanA", InitDestroyBean.class); + InitDestroyBean beanB = bf.getBean("beanB", InitDestroyBean.class); + InitDestroyBean beanC = bf.getBean("beanC", InitDestroyBean.class); + InitDestroyBean beanD = bf.getBean("beanD", InitDestroyBean.class); + + assertThat(beanA.initMethod1Called, is(true)); + assertThat(beanB.initMethod2Called, is(true)); + assertThat(beanC.initMethod3Called, is(true)); + assertThat(beanD.initMethod2Called, is(true)); + + bf.destroySingletons(); + + assertThat(beanA.destroyMethod1Called, is(true)); + assertThat(beanB.destroyMethod2Called, is(true)); + assertThat(beanC.destroyMethod3Called, is(true)); + assertThat(beanD.destroyMethod2Called, is(true)); + } + +} + +class InitDestroyBean { + boolean initMethod1Called; + boolean initMethod2Called; + boolean initMethod3Called; + + boolean destroyMethod1Called; + boolean destroyMethod2Called; + boolean destroyMethod3Called; + + void initMethod1() { this.initMethod1Called = true; } + void initMethod2() { this.initMethod2Called = true; } + void initMethod3() { this.initMethod3Called = true; } + + void destroyMethod1() { this.destroyMethod1Called = true; } + void destroyMethod2() { this.destroyMethod2Called = true; } + void destroyMethod3() { this.destroyMethod3Called = true; } +} diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/NestedBeansElementTests.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/NestedBeansElementTests.java new file mode 100644 index 00000000000..288025eca2b --- /dev/null +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/NestedBeansElementTests.java @@ -0,0 +1,49 @@ +package org.springframework.beans.factory.xml; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertThat; + +import org.junit.Test; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.DefaultEnvironment; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +/** + * Tests for new nested beans element support in Spring XML + * + * @author Chris Beams + */ +public class NestedBeansElementTests { + private final Resource XML = + new ClassPathResource("NestedBeansElementTests-context.xml", this.getClass()); + + @Test + public void getBean_withoutActiveProfile() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + new XmlBeanDefinitionReader(bf).loadBeanDefinitions(XML); + + Object foo = bf.getBean("foo"); + assertThat(foo, instanceOf(String.class)); + } + + @Test + public void getBean_withActiveProfile() { + ConfigurableEnvironment env = new DefaultEnvironment(); + env.setActiveProfiles("dev"); + + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(bf); + reader.setEnvironment(env); + reader.loadBeanDefinitions(XML); + + bf.getBean("devOnlyBean"); // should not throw NSBDE + + Object foo = bf.getBean("foo"); + assertThat(foo, instanceOf(Integer.class)); + + bf.getBean("devOnlyBean"); + } + +} diff --git a/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-autowire-candidates-context.xml b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-autowire-candidates-context.xml new file mode 100644 index 00000000000..d6be7a4426f --- /dev/null +++ b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-autowire-candidates-context.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-autowire-context.xml b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-autowire-context.xml new file mode 100644 index 00000000000..49e415572c8 --- /dev/null +++ b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-autowire-context.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + diff --git a/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-init-destroy-context.xml b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-init-destroy-context.xml new file mode 100644 index 00000000000..90c5495d7c6 --- /dev/null +++ b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-init-destroy-context.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff --git a/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-lazy-context.xml b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-lazy-context.xml new file mode 100644 index 00000000000..3c3df4abf08 --- /dev/null +++ b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-lazy-context.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-merge-context.xml b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-merge-context.xml new file mode 100644 index 00000000000..12dbc607928 --- /dev/null +++ b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementAttributeRecursionTests-merge-context.xml @@ -0,0 +1,47 @@ + + + + + + + alpha + bravo + + + + + + + + charlie + delta + + + + + + + + + echo + foxtrot + + + + + + + + + golf + hotel + + + + + + diff --git a/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementTests-context.xml b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementTests-context.xml new file mode 100644 index 00000000000..5500aeedaee --- /dev/null +++ b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/NestedBeansElementTests-context.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + diff --git a/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/environmentBeans-devProfile.xml b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/environmentBeans-devProfile.xml new file mode 100644 index 00000000000..8ae82bc8cf6 --- /dev/null +++ b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/environmentBeans-devProfile.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/environmentBeans-multiProfile.xml b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/environmentBeans-multiProfile.xml new file mode 100644 index 00000000000..dac5fb92449 --- /dev/null +++ b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/environmentBeans-multiProfile.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/environmentBeans-noProfile.xml b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/environmentBeans-noProfile.xml new file mode 100644 index 00000000000..656ea3aceb1 --- /dev/null +++ b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/environmentBeans-noProfile.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/environmentBeans-prodProfile.xml b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/environmentBeans-prodProfile.xml new file mode 100644 index 00000000000..aba52d7066f --- /dev/null +++ b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/environmentBeans-prodProfile.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/environmentBeans-unknownProfile.xml b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/environmentBeans-unknownProfile.xml new file mode 100644 index 00000000000..922ba290485 --- /dev/null +++ b/org.springframework.beans/src/test/resources/org/springframework/beans/factory/xml/environmentBeans-unknownProfile.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/org.springframework.context.support/.settings/org.eclipse.jdt.core.prefs b/org.springframework.context.support/.settings/org.eclipse.jdt.core.prefs index a15f738edcd..4655eeb423f 100644 --- a/org.springframework.context.support/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.context.support/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ #Wed Jul 15 00:01:30 PDT 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/org.springframework.context.support/pom.xml b/org.springframework.context.support/pom.xml index 69d83ab1025..6588fe19c70 100644 --- a/org.springframework.context.support/pom.xml +++ b/org.springframework.context.support/pom.xml @@ -4,12 +4,12 @@ org.springframework spring-context-support jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.context/.settings/org.eclipse.jdt.core.prefs b/org.springframework.context/.settings/org.eclipse.jdt.core.prefs index 5a5d4fe0932..7cff560e8e1 100644 --- a/org.springframework.context/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.context/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ -#Wed Jul 15 00:01:31 PDT 2009 +#Mon Sep 06 21:53:54 CEST 2010 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/org.springframework.context/.springBeans b/org.springframework.context/.springBeans index f7eccf735e6..84849427f41 100644 --- a/org.springframework.context/.springBeans +++ b/org.springframework.context/.springBeans @@ -1,7 +1,7 @@ 1 - + @@ -11,7 +11,6 @@ src/test/java/org/springframework/context/annotation/configuration/SecondLevelSubConfig-context.xml src/test/java/org/springframework/context/annotation/configuration/ImportXmlWithAopNamespace-context.xml src/test/java/org/springframework/context/annotation/Spr6602Tests-context.xml - src/test/java/org/springframework/beans/factory/FactoryBeanLookupTests-context.xml diff --git a/org.springframework.context/pom.xml b/org.springframework.context/pom.xml index 36868ab827e..82e2d36f0fc 100644 --- a/org.springframework.context/pom.xml +++ b/org.springframework.context/pom.xml @@ -6,12 +6,12 @@ org.springframework spring-context jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.context/src/main/java/org/springframework/context/ApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/ApplicationContext.java index df117fd5508..44fe37f31aa 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/ApplicationContext.java +++ b/org.springframework.context/src/main/java/org/springframework/context/ApplicationContext.java @@ -19,6 +19,7 @@ package org.springframework.context; import org.springframework.beans.factory.HierarchicalBeanFactory; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.core.env.EnvironmentCapable; import org.springframework.core.io.support.ResourcePatternResolver; /** @@ -53,7 +54,7 @@ import org.springframework.core.io.support.ResourcePatternResolver; * @see org.springframework.beans.factory.BeanFactory * @see org.springframework.core.io.ResourceLoader */ -public interface ApplicationContext extends ListableBeanFactory, HierarchicalBeanFactory, +public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver { /** diff --git a/org.springframework.context/src/main/java/org/springframework/context/ConfigurableApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/ConfigurableApplicationContext.java index ad56ae9a256..08fa69d06ab 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/ConfigurableApplicationContext.java +++ b/org.springframework.context/src/main/java/org/springframework/context/ConfigurableApplicationContext.java @@ -19,6 +19,8 @@ package org.springframework.context; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; /** * SPI interface to be implemented by most if not all application contexts. @@ -31,6 +33,7 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; * methods should only be used by startup and shutdown code. * * @author Juergen Hoeller + * @author Chris Beams * @since 03.11.2003 */ public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle { @@ -59,6 +62,11 @@ public interface ConfigurableApplicationContext extends ApplicationContext, Life */ String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver"; + /** + * Name of the {@link Environment} bean in the factory. + */ + String ENVIRONMENT_BEAN_NAME = "environment"; + /** * Name of the System properties bean in the factory. * @see java.lang.System#getProperties() @@ -87,6 +95,16 @@ public interface ConfigurableApplicationContext extends ApplicationContext, Life */ void setParent(ApplicationContext parent); + /** + * TODO SPR-7508: document + */ + ConfigurableEnvironment getEnvironment(); + + /** + * TODO SPR-7508: document + */ + void setEnvironment(ConfigurableEnvironment environment); + /** * Add a new BeanFactoryPostProcessor that will get applied to the internal * bean factory of this application context on refresh, before any of the @@ -105,7 +123,7 @@ public interface ConfigurableApplicationContext extends ApplicationContext, Life * @see org.springframework.context.event.ContextRefreshedEvent * @see org.springframework.context.event.ContextClosedEvent */ - void addApplicationListener(ApplicationListener listener); + void addApplicationListener(ApplicationListener listener); /** * Load or refresh the persistent representation of the configuration, diff --git a/org.springframework.context/src/main/java/org/springframework/context/EnvironmentAware.java b/org.springframework.context/src/main/java/org/springframework/context/EnvironmentAware.java new file mode 100644 index 00000000000..7ec52896b4c --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/context/EnvironmentAware.java @@ -0,0 +1,30 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context; + +import org.springframework.core.env.Environment; + +/** + * TODO SPR-7515: document + * + * @author Chris Beams + */ +public interface EnvironmentAware { + + void setEnvironment(Environment environment); + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java index 3d8c76137bc..47e4ff256c6 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java @@ -24,6 +24,9 @@ import org.springframework.beans.factory.support.AutowireCandidateQualifier; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; +import org.springframework.core.env.DefaultEnvironment; +import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotationMetadata; /** * Convenient adapter for programmatic registration of annotated bean classes. @@ -31,6 +34,7 @@ import org.springframework.beans.factory.support.BeanNameGenerator; * the same resolution of annotations but for explicitly registered classes only. * * @author Juergen Hoeller + * @author Chris Beams * @since 3.0 * @see AnnotationConfigApplicationContext#register */ @@ -38,6 +42,8 @@ public class AnnotatedBeanDefinitionReader { private final BeanDefinitionRegistry registry; + private Environment environment = new DefaultEnvironment(); + private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator(); private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver(); @@ -61,9 +67,17 @@ public class AnnotatedBeanDefinitionReader { return this.registry; } + /** + * Set the Environment to use when registering classes. + *

The default is a {@link DefaultEnvironment}. + */ + public void setEnvironment(Environment environment) { + this.environment = environment; + } + /** * Set the BeanNameGenerator to use for detected bean classes. - *

Default is a {@link AnnotationBeanNameGenerator}. + *

The default is a {@link AnnotationBeanNameGenerator}. */ public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) { this.beanNameGenerator = (beanNameGenerator != null ? beanNameGenerator : new AnnotationBeanNameGenerator()); @@ -92,8 +106,45 @@ public class AnnotatedBeanDefinitionReader { registerBean(annotatedClass, null, qualifiers); } + private boolean hasEligibleProfile(AnnotationMetadata metadata) { + boolean hasEligibleProfile = false; + if (!metadata.hasAnnotation(Profile.class.getName())) { + hasEligibleProfile = true; + } else { + for (String profile : (String[])metadata.getAnnotationAttributes(Profile.class.getName()).get(Profile.CANDIDATE_PROFILES_ATTRIB_NAME)) { + if (this.environment.getActiveProfiles().contains(profile)) { + hasEligibleProfile = true; + break; + } + } + } + return hasEligibleProfile; + } + public void registerBean(Class annotatedClass, String name, Class... qualifiers) { AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass); + if (!hasEligibleProfile(abd.getMetadata())) { + // TODO SPR-7508: log that this bean is being rejected on profile mismatch + return; + } + /* + if (metadata.hasAnnotation(Profile.class.getName())) { + if (this.environment == null) { + return; + } + Map profileAttribs = metadata.getAnnotationAttributes(Profile.class.getName()); + String[] names = (String[]) profileAttribs.get(Profile.CANDIDATE_PROFILES_ATTRIB_NAME); + boolean go=false; + for (String pName : names) { + if (this.environment.getActiveProfiles().contains(pName)) { + go = true; + } + } + if (!go) { + return; + } + } + */ ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java index ebf1eee38fb..bf696d13b87 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java @@ -16,8 +16,11 @@ package org.springframework.context.annotation; +import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.context.support.GenericApplicationContext; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; /** * Standalone application context, accepting annotated classes as input - in particular @@ -46,6 +49,9 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex private final ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this); + { // TODO: rework this, it's a bit confusing + this.setEnvironment(this.getEnvironment()); + } /** * Create a new AnnotationConfigApplicationContext that needs to be populated @@ -75,6 +81,15 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex refresh(); } + /** + * TODO SPR-7508: document + */ + @Override + public void setEnvironment(ConfigurableEnvironment environment) { + super.setEnvironment(environment); + this.reader.setEnvironment(environment); + this.scanner.setEnvironment(environment); + } /** * Set the BeanNameGenerator to use for detected bean classes. @@ -94,7 +109,6 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex this.scanner.setScopeMetadataResolver(scopeMetadataResolver); } - /** * Register an annotated class to be processed. Allows for programmatically * building a {@link AnnotationConfigApplicationContext}. Note that diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java index db2801e1c36..84b9fad86be 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java @@ -39,7 +39,7 @@ import org.springframework.util.ClassUtils; * @author Chris Beams * @since 2.5 * @see CommonAnnotationBeanPostProcessor - * @see org.springframework.context.annotation.support.ConfigurationClassPostProcessor; + * @see org.springframework.context.annotation.ConfigurationClassPostProcessor * @see org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor * @see org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor * @see org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/Bean.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/Bean.java index e2728d569b5..de79ccbb16a 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/Bean.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/Bean.java @@ -101,7 +101,7 @@ public @interface Bean { *

Note: Only invoked on beans whose lifecycle is under the full control of the * factory, which is always the case for singletons but not guaranteed * for any other scope. - * @see {@link org.springframework.context.ConfigurableApplicationContext#close()} + * @see org.springframework.context.ConfigurableApplicationContext#close() */ String destroyMethod() default ""; diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java index da23b12a3e7..4f780ef343b 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java @@ -27,6 +27,7 @@ import org.springframework.beans.factory.support.BeanDefinitionDefaults; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; +import org.springframework.core.env.EnvironmentCapable; import org.springframework.core.io.ResourceLoader; import org.springframework.util.Assert; import org.springframework.util.PatternMatchUtils; @@ -48,6 +49,7 @@ import org.springframework.util.PatternMatchUtils; * * @author Mark Fisher * @author Juergen Hoeller + * @author Chris Beams * @since 2.5 * @see AnnotationConfigApplicationContext#scan * @see org.springframework.stereotype.Component @@ -87,6 +89,10 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo * {@link org.springframework.context.ApplicationContext} implementations. *

If given a plain BeanDefinitionRegistry, the default ResourceLoader will be a * {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}. + *

If the the passed-in bean factory also implements {@link EnvironmentCapable} its + * environment will be used by this reader. Otherwise, the reader will initialize and + * use a {@link DefaultEnvironment}. All ApplicationContext implementations are + * EnvironmentCapable, while normal BeanFactory implementations are not. * @param registry the BeanFactory to load bean definitions into, * in the form of a BeanDefinitionRegistry * @param useDefaultFilters whether to include the default filters for the @@ -96,6 +102,7 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo * {@link org.springframework.stereotype.Controller @Controller} stereotype * annotations. * @see #setResourceLoader + * @see #setEnvironment */ public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) { super(useDefaultFilters); @@ -107,6 +114,11 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo if (this.registry instanceof ResourceLoader) { setResourceLoader((ResourceLoader) this.registry); } + + // Inherit Environment if possible + if (this.registry instanceof EnvironmentCapable) { + setEnvironment(((EnvironmentCapable) this.registry).getEnvironment()); + } } diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java index f10cadb9cdd..850fe621a7c 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java @@ -25,11 +25,13 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.ResourceLoaderAware; +import org.springframework.core.env.DefaultEnvironment; +import org.springframework.core.env.Environment; +import org.springframework.core.env.EnvironmentCapable; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; @@ -46,7 +48,6 @@ import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; -import org.springframework.util.SystemPropertyUtils; /** * A component provider that scans the classpath from a base package. It then @@ -59,18 +60,21 @@ import org.springframework.util.SystemPropertyUtils; * @author Mark Fisher * @author Juergen Hoeller * @author Ramnivas Laddad + * @author Chris Beams * @since 2.5 * @see org.springframework.core.type.classreading.MetadataReaderFactory * @see org.springframework.core.type.AnnotationMetadata * @see ScannedGenericBeanDefinition */ -public class ClassPathScanningCandidateComponentProvider implements ResourceLoaderAware { +public class ClassPathScanningCandidateComponentProvider implements EnvironmentCapable, ResourceLoaderAware { private static final String DEFAULT_RESOURCE_PATTERN = "**/*.class"; protected final Log logger = LogFactory.getLog(getClass()); + private Environment environment = new DefaultEnvironment(); + private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver); @@ -110,6 +114,20 @@ public class ClassPathScanningCandidateComponentProvider implements ResourceLoad this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader); } + /** + * TODO SPR-7508: document + */ + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + /** + * TODO SPR-7508: document + */ + public Environment getEnvironment() { + return this.environment; + } + /** * Return the ResourceLoader that this component provider uses. */ @@ -261,7 +279,7 @@ public class ClassPathScanningCandidateComponentProvider implements ResourceLoad * @return the pattern specification to be used for package searching */ protected String resolveBasePackage(String basePackage) { - return ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage)); + return ClassUtils.convertClassNameToResourcePath(environment.resolveRequiredPlaceholders(basePackage)); } /** @@ -278,12 +296,28 @@ public class ClassPathScanningCandidateComponentProvider implements ResourceLoad } for (TypeFilter tf : this.includeFilters) { if (tf.match(metadataReader, this.metadataReaderFactory)) { - return true; + return hasEligibleProfile(metadataReader); } } return false; } + private boolean hasEligibleProfile(MetadataReader metadataReader) { + boolean hasEligibleProfile = false; + if (!metadataReader.getAnnotationMetadata().hasAnnotation(Profile.class.getName())) { + hasEligibleProfile = true; + } else { + for (String profile : (String[])metadataReader.getAnnotationMetadata().getAnnotationAttributes(Profile.class.getName()).get(Profile.CANDIDATE_PROFILES_ATTRIB_NAME)) { + if (this.environment.getActiveProfiles().contains(profile)) { + hasEligibleProfile = true; + break; + } + } + } + return hasEligibleProfile; + } + + /** * Determine whether the given bean definition qualifies as candidate. *

The default implementation checks whether the class is concrete diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScan.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScan.java new file mode 100644 index 00000000000..9acfd337ad8 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScan.java @@ -0,0 +1,75 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.beans.factory.support.BeanNameGenerator; + + +/** + * Configures component scanning directives for use with {@link Configuration} + * classes. Provides support parallel with Spring XML's + * <context:component-scan> element. + * + * TODO SPR-7508: complete documentation. + * + * @author Chris Beams + * @since 3.1 + * @see FilterType + * @see Configuration + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface ComponentScan { + + /** base packages to scan */ + String[] value() default {}; + + Class[] packageOf() default Void.class; + + Class nameGenerator() default AnnotationBeanNameGenerator.class; + + Class scopeResolver() default AnnotationScopeMetadataResolver.class; + + String resourcePattern() default "**/*.class"; + + ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT; + + boolean useDefaultFilters() default true; + + IncludeFilter[] includeFilters() default {}; + + ExcludeFilter[] excludeFilters() default {}; + + + @Retention(RetentionPolicy.SOURCE) + @interface IncludeFilter { + FilterType type() default FilterType.ANNOTATION; + Class value(); + } + + @Retention(RetentionPolicy.SOURCE) + @interface ExcludeFilter { + FilterType type() default FilterType.ANNOTATION; + Class value(); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java index a6dee3590ae..ee1a4920224 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java @@ -98,6 +98,7 @@ public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser { // Delegate bean definition registration to scanner class. ClassPathBeanDefinitionScanner scanner = createScanner(readerContext, useDefaultFilters); scanner.setResourceLoader(readerContext.getResourceLoader()); + scanner.setEnvironment(parserContext.getDelegate().getEnvironment()); scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults()); scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns()); diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/Configuration.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/Configuration.java index 08ea04ebeee..a277ff9efe2 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/Configuration.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/Configuration.java @@ -57,6 +57,7 @@ import org.springframework.stereotype.Component; * @see Bean * @see ConfigurationClassPostProcessor * @see AnnotationConfigApplicationContext + * @see org.springframework.context.annotation.Profile */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java index ce069f4d4e8..9aae2ecf32e 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java @@ -105,7 +105,6 @@ final class ConfigurationClass { return this.importedResources; } - public void validate(ProblemReporter problemReporter) { // An @Bean method may only be overloaded through inheritance. No single // @Configuration class may declare two @Bean methods with the same name. diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java index 4457dc2bb1e..31c623f6ec2 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java @@ -27,6 +27,7 @@ import java.util.Stack; import org.springframework.beans.factory.parsing.Location; import org.springframework.beans.factory.parsing.Problem; import org.springframework.beans.factory.parsing.ProblemReporter; +import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.MethodMetadata; import org.springframework.core.type.StandardAnnotationMetadata; @@ -63,14 +64,18 @@ class ConfigurationClassParser { private final Set configurationClasses = new LinkedHashSet(); + private final Environment environment; + /** * Create a new {@link ConfigurationClassParser} instance that will be used * to populate the set of configuration classes. */ - public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory, ProblemReporter problemReporter) { + public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory, + ProblemReporter problemReporter, Environment environment) { this.metadataReaderFactory = metadataReaderFactory; this.problemReporter = problemReporter; + this.environment = environment; } @@ -95,8 +100,28 @@ class ConfigurationClassParser { processConfigurationClass(new ConfigurationClass(clazz, beanName)); } - protected void processConfigurationClass(ConfigurationClass configClass) throws IOException { + boolean hasEligibleProfile = false; + if (this.environment == null) { + hasEligibleProfile = true; + } else { + if (!configClass.getMetadata().hasAnnotation(Profile.class.getName())) { + hasEligibleProfile = true; + } else { + for (String profile : (String[])configClass.getMetadata().getAnnotationAttributes(Profile.class.getName()).get(Profile.CANDIDATE_PROFILES_ATTRIB_NAME)) { + if (this.environment.getActiveProfiles().contains(profile)) { + hasEligibleProfile = true; + break; + } + } + } + } + if (!hasEligibleProfile) { + //logger.debug("TODO SPR-7508: issue debug statement that this class is being excluded"); + // make sure XML has a symmetrical statement as well + return; + } + AnnotationMetadata metadata = configClass.getMetadata(); while (metadata != null) { doProcessConfigurationClass(configClass, metadata); @@ -120,6 +145,7 @@ class ConfigurationClassParser { // Let's remove the old one and go with the new one. this.configurationClasses.remove(configClass); } + this.configurationClasses.add(configClass); } diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java index 1f9c45d0e19..e26c3667c36 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java @@ -16,6 +16,7 @@ package org.springframework.context.annotation; +import java.awt.dnd.Autoscroll; import java.io.IOException; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -38,7 +39,9 @@ import org.springframework.beans.factory.parsing.SourceExtractor; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; +import org.springframework.context.EnvironmentAware; import org.springframework.core.Ordered; +import org.springframework.core.env.Environment; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.util.Assert; @@ -61,7 +64,8 @@ import org.springframework.util.ClassUtils; * @author Juergen Hoeller * @since 3.0 */ -public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, BeanClassLoaderAware { +public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, + BeanClassLoaderAware, EnvironmentAware { /** Whether the CGLIB2 library is present on the classpath */ private static final boolean cglibAvailable = ClassUtils.isPresent( @@ -84,6 +88,8 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo private boolean postProcessBeanFactoryCalled = false; + private Environment environment; + /** * Set the {@link SourceExtractor} to use for generated bean definitions @@ -121,8 +127,12 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo } } + public void setEnvironment(Environment environment) { + this.environment = environment; + } + public int getOrder() { - return Ordered.HIGHEST_PRECEDENCE; + return Ordered.HIGHEST_PRECEDENCE + 1; // make room for AutoScanningBeanDefinitionRegistrar } @@ -180,7 +190,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo } // Populate a new configuration model by parsing each @Configuration classes - ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter); + ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment); for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/FilterType.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/FilterType.java index 6b63b9a0c33..9ed1b899434 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/FilterType.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/FilterType.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2010 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,19 +16,39 @@ package org.springframework.context.annotation; +import org.springframework.core.type.filter.AssignableTypeFilter; + + /** - * Enumeration of the valid type filters to be added for annotation-driven configuration. + * Enumeration of the type filters that may be used in conjunction with + * {@link ComponentScan @ComponentScan}. * * @author Mark Fisher * @author Juergen Hoeller + * @author Chris Beams * @since 2.5 + * @see ComponentScan + * @see ComponentScan.IncludeFilter + * @see ComponentScan.ExcludeFilter + * @see org.springframework.core.type.filter.TypeFilter */ public enum FilterType { + /** + * Filter candidates marked with a given annotation. + * @see org.springframework.core.type.filter.AnnotationTypeFilter + */ ANNOTATION, + + /** + * Filter candidates assignable to a given type. + * @see AssignableTypeFilter + */ ASSIGNABLE_TYPE, - ASPECTJ_PATTERN, - REGEX_PATTERN, + + /** Filter candidates using a given custom + * {@link org.springframework.core.type.filter.TypeFilter} implementation + */ CUSTOM } diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/Profile.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/Profile.java new file mode 100644 index 00000000000..5d6cf21a63b --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/Profile.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.TYPE; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Chris Beams + * @since 3.1 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ + ANNOTATION_TYPE, // @Profile may be used as a meta-annotation + TYPE // In conjunction with @Component and its derivatives +}) +public @interface Profile { + + /** + * @see #value() + */ + static final String CANDIDATE_PROFILES_ATTRIB_NAME = "value"; + + /** + * TODO SPR-7508: document + */ + String[] value(); +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/config/PropertyPlaceholderBeanDefinitionParser.java b/org.springframework.context/src/main/java/org/springframework/context/config/PropertyPlaceholderBeanDefinitionParser.java index 234c1d01434..afbc1a12231 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/config/PropertyPlaceholderBeanDefinitionParser.java +++ b/org.springframework.context/src/main/java/org/springframework/context/config/PropertyPlaceholderBeanDefinitionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2010 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. @@ -20,6 +20,7 @@ import org.w3c.dom.Element; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.context.support.EnvironmentAwarePropertyPlaceholderConfigurer; import org.springframework.util.StringUtils; /** @@ -27,15 +28,24 @@ import org.springframework.util.StringUtils; * * @author Juergen Hoeller * @author Dave Syer + * @author Chris Beams * @since 2.5 */ class PropertyPlaceholderBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser { @Override - protected Class getBeanClass(Element element) { - return PropertyPlaceholderConfigurer.class; + protected Class getBeanClass(Element element) { + // as of Spring 3.1, the default for system-properties-mode is DELEGATE, + // meaning that the attribute should be disregarded entirely, instead + // deferring to the order of PropertySource objects in the enclosing + // application context's Environment object + if (!"DELEGATE".equals(element.getAttribute("system-properties-mode"))) { + return PropertyPlaceholderConfigurer.class; + } + + return EnvironmentAwarePropertyPlaceholderConfigurer.class; } - + @Override protected void doParse(Element element, BeanDefinitionBuilder builder) { @@ -44,9 +54,11 @@ class PropertyPlaceholderBeanDefinitionParser extends AbstractPropertyLoadingBea builder.addPropertyValue("ignoreUnresolvablePlaceholders", Boolean.valueOf(element.getAttribute("ignore-unresolvable"))); - String systemPropertiesModeName = element.getAttribute("system-properties-mode"); - if (StringUtils.hasLength(systemPropertiesModeName)) { - builder.addPropertyValue("systemPropertiesModeName", "SYSTEM_PROPERTIES_MODE_"+systemPropertiesModeName); + if (!"DELEGATE".equals(element.getAttribute("system-properties-mode"))) { + String systemPropertiesModeName = element.getAttribute("system-properties-mode"); + if (StringUtils.hasLength(systemPropertiesModeName)) { + builder.addPropertyValue("systemPropertiesModeName", "SYSTEM_PROPERTIES_MODE_"+systemPropertiesModeName); + } } } diff --git a/org.springframework.context/src/main/java/org/springframework/context/expression/EnvironmentAccessor.java b/org.springframework.context/src/main/java/org/springframework/context/expression/EnvironmentAccessor.java new file mode 100644 index 00000000000..0727a839c3e --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/context/expression/EnvironmentAccessor.java @@ -0,0 +1,68 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.expression; + +import org.springframework.core.env.Environment; +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypedValue; + +/** + * Read-only EL property accessor that knows how to retrieve keys + * of a Spring {@link Environment} instance. + * + * @author Chris Beams + * @since 3.1 + */ +public class EnvironmentAccessor implements PropertyAccessor { + + public Class[] getSpecificTargetClasses() { + return new Class[] { Environment.class }; + } + + /** + * Can read any {@link Environment}, thus always returns true. + * @return true + */ + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + return true; + } + + /** + * Access provided {@literal target} object by calling its {@link Environment#getProperty(String)} + * method with the provided {@literal name}. + */ + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { + return new TypedValue(((Environment)target).getProperty(name)); + } + + /** + * Read only. + * @return false + */ + public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { + return false; + } + + /** + * Read only. No-op. + */ + public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/expression/StandardBeanExpressionResolver.java b/org.springframework.context/src/main/java/org/springframework/context/expression/StandardBeanExpressionResolver.java index 568874ebf74..9fb19609528 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/expression/StandardBeanExpressionResolver.java +++ b/org.springframework.context/src/main/java/org/springframework/context/expression/StandardBeanExpressionResolver.java @@ -126,6 +126,7 @@ public class StandardBeanExpressionResolver implements BeanExpressionResolver { sec.addPropertyAccessor(new BeanExpressionContextAccessor()); sec.addPropertyAccessor(new BeanFactoryAccessor()); sec.addPropertyAccessor(new MapAccessor()); + sec.addPropertyAccessor(new EnvironmentAccessor()); sec.setBeanResolver(new BeanFactoryResolver(evalContext.getBeanFactory())); sec.setTypeLocator(new StandardTypeLocator(evalContext.getBeanFactory().getBeanClassLoader())); ConversionService conversionService = evalContext.getBeanFactory().getConversionService(); diff --git a/org.springframework.context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java index 10def3585fe..163f9945249 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java +++ b/org.springframework.context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java @@ -18,7 +18,6 @@ package org.springframework.context.support; import java.io.IOException; import java.lang.annotation.Annotation; -import java.security.AccessControlException; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -33,7 +32,6 @@ import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.DisposableBean; @@ -54,6 +52,7 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.EnvironmentAware; import org.springframework.context.HierarchicalMessageSource; import org.springframework.context.LifecycleProcessor; import org.springframework.context.MessageSource; @@ -73,6 +72,8 @@ import org.springframework.core.OrderComparator; import org.springframework.core.Ordered; import org.springframework.core.PriorityOrdered; import org.springframework.core.convert.ConversionService; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.DefaultEnvironment; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; @@ -203,7 +204,10 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader private ApplicationEventMulticaster applicationEventMulticaster; /** Statically specified listeners */ - private Set applicationListeners = new LinkedHashSet(); + private Set> applicationListeners = new LinkedHashSet>(); + + /** TODO SPR-7508: document */ + private ConfigurableEnvironment environment = new DefaultEnvironment(); /** @@ -271,6 +275,14 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader return this.parent; } + public ConfigurableEnvironment getEnvironment() { + return this.environment; + } + + public void setEnvironment(ConfigurableEnvironment environment) { + this.environment = environment; + } + /** * Return this context's internal bean factory as AutowireCapableBeanFactory, * if already available. @@ -363,6 +375,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader this.beanFactoryPostProcessors.add(beanFactoryPostProcessor); } + /** * Return the list of BeanFactoryPostProcessors that will get applied * to the internal BeanFactory. @@ -371,7 +384,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader return this.beanFactoryPostProcessors; } - public void addApplicationListener(ApplicationListener listener) { + public void addApplicationListener(ApplicationListener listener) { if (this.applicationEventMulticaster != null) { this.applicationEventMulticaster.addApplicationListener(listener); } @@ -383,7 +396,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader /** * Return the list of statically specified ApplicationListeners. */ - public Collection getApplicationListeners() { + public Collection> getApplicationListeners() { return this.applicationListeners; } @@ -481,7 +494,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader // Tell the internal bean factory to use the context's class loader etc. beanFactory.setBeanClassLoader(getClassLoader()); beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver()); - beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this)); + beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment())); // Configure the bean factory with context callbacks. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); @@ -489,6 +502,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); + beanFactory.ignoreDependencyInterface(EnvironmentAware.class); // BeanFactory interface not registered as resolvable type in a plain factory. // MessageSource registered (and found for autowiring) as a bean. @@ -505,54 +519,16 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader } // Register default environment beans. + if (!beanFactory.containsBean(ENVIRONMENT_BEAN_NAME)) { + beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); + } + if (!beanFactory.containsBean(SYSTEM_PROPERTIES_BEAN_NAME)) { - Map systemProperties; - try { - systemProperties = System.getProperties(); - } - catch (AccessControlException ex) { - systemProperties = new ReadOnlySystemAttributesMap() { - @Override - protected String getSystemAttribute(String propertyName) { - try { - return System.getProperty(propertyName); - } - catch (AccessControlException ex) { - if (logger.isInfoEnabled()) { - logger.info("Not allowed to obtain system property [" + propertyName + "]: " + - ex.getMessage()); - } - return null; - } - } - }; - } - beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, systemProperties); + beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { - Map systemEnvironment; - try { - systemEnvironment = System.getenv(); - } - catch (AccessControlException ex) { - systemEnvironment = new ReadOnlySystemAttributesMap() { - @Override - protected String getSystemAttribute(String variableName) { - try { - return System.getenv(variableName); - } - catch (AccessControlException ex) { - if (logger.isInfoEnabled()) { - logger.info("Not allowed to obtain system environment variable [" + variableName + "]: " + - ex.getMessage()); - } - return null; - } - } - }; - } - beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, systemEnvironment); + beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } } @@ -664,6 +640,15 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader } } + /** + * Common location for subclasses to call and receive registration of standard + * {@link BeanFactoryPostProcessor} bean definitions. + * + * @param registry subclass BeanDefinitionRegistry + */ + protected void registerStandardBeanFactoryPostProcessors(BeanDefinitionRegistry registry) { + } + /** * Instantiate and invoke all registered BeanPostProcessor beans, * respecting explicit order if given. @@ -848,7 +833,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader */ protected void registerListeners() { // Register statically specified listeners first. - for (ApplicationListener listener : getApplicationListeners()) { + for (ApplicationListener listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); } // Do not initialize FactoryBeans here: We need to leave all regular beans @@ -869,7 +854,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader * @deprecated as of Spring 3.0, in favor of {@link #addApplicationListener} */ @Deprecated - protected void addListener(ApplicationListener listener) { + protected void addListener(ApplicationListener listener) { getApplicationEventMulticaster().addApplicationListener(listener); } @@ -1099,7 +1084,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader return getBeanFactory().isPrototype(name); } - public boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException { + public boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException { return getBeanFactory().isTypeMatch(name, targetType); } @@ -1128,11 +1113,11 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader return getBeanFactory().getBeanDefinitionNames(); } - public String[] getBeanNamesForType(Class type) { + public String[] getBeanNamesForType(Class type) { return getBeanFactory().getBeanNamesForType(type); } - public String[] getBeanNamesForType(Class type, boolean includeNonSingletons, boolean allowEagerInit) { + public String[] getBeanNamesForType(Class type, boolean includeNonSingletons, boolean allowEagerInit) { return getBeanFactory().getBeanNamesForType(type, includeNonSingletons, allowEagerInit); } @@ -1347,7 +1332,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader private final Map singletonNames = new ConcurrentHashMap(); - public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) { + public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) { if (beanDefinition.isSingleton()) { this.singletonNames.put(beanName, Boolean.TRUE); } @@ -1363,7 +1348,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader Boolean flag = this.singletonNames.get(beanName); if (Boolean.TRUE.equals(flag)) { // singleton bean (top-level or inner): register on the fly - addApplicationListener((ApplicationListener) bean); + addApplicationListener((ApplicationListener) bean); } else if (flag == null) { if (logger.isWarnEnabled() && !containsBean(beanName)) { diff --git a/org.springframework.context/src/main/java/org/springframework/context/support/AbstractRefreshableApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/support/AbstractRefreshableApplicationContext.java index e0a02ec70b8..b0a7aa9c87a 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/support/AbstractRefreshableApplicationContext.java +++ b/org.springframework.context/src/main/java/org/springframework/context/support/AbstractRefreshableApplicationContext.java @@ -53,6 +53,7 @@ import org.springframework.core.LocalVariableTableParameterNameDiscoverer; * supports {@literal @Configuration}-annotated classes as a source of bean definitions. * * @author Juergen Hoeller + * @author Chris Beams * @since 1.1.3 * @see #loadBeanDefinitions * @see org.springframework.beans.factory.support.DefaultListableBeanFactory @@ -217,6 +218,7 @@ public abstract class AbstractRefreshableApplicationContext extends AbstractAppl } beanFactory.setParameterNameDiscoverer(new LocalVariableTableParameterNameDiscoverer()); beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver()); + registerStandardBeanFactoryPostProcessors(beanFactory); } /** diff --git a/org.springframework.context/src/main/java/org/springframework/context/support/AbstractRefreshableConfigApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/support/AbstractRefreshableConfigApplicationContext.java index 3dda2fe61bb..79a40093232 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/support/AbstractRefreshableConfigApplicationContext.java +++ b/org.springframework.context/src/main/java/org/springframework/context/support/AbstractRefreshableConfigApplicationContext.java @@ -117,9 +117,13 @@ public abstract class AbstractRefreshableConfigApplicationContext extends Abstra * system property values if necessary. Applied to config locations. * @param path the original file path * @return the resolved file path - * @see org.springframework.util.SystemPropertyUtils#resolvePlaceholders + * @see SystemPropertyUtils#resolveRequiredPlaceholders(String) */ protected String resolvePath(String path) { + // TODO SPR-7508: note that ARAC cannot delegate to its beanFactory's environment + // to call Environment.resolve[Required]Placeholders(String), as the bean factory + // has not yet been initialized. This amounts to one more reason not to use the ARAC + // hierarchy - it won't have early access to environment property resolution. return SystemPropertyUtils.resolvePlaceholders(path); } diff --git a/org.springframework.context/src/main/java/org/springframework/context/support/AbstractXmlApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/support/AbstractXmlApplicationContext.java index 51894a287fa..20c2734f764 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/support/AbstractXmlApplicationContext.java +++ b/org.springframework.context/src/main/java/org/springframework/context/support/AbstractXmlApplicationContext.java @@ -83,6 +83,7 @@ public abstract class AbstractXmlApplicationContext extends AbstractRefreshableC // Configure the bean definition reader with this context's // resource loading environment. + beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); diff --git a/org.springframework.context/src/main/java/org/springframework/context/support/ApplicationContextAwareProcessor.java b/org.springframework.context/src/main/java/org/springframework/context/support/ApplicationContextAwareProcessor.java index d40ca72323d..facb86ac515 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/support/ApplicationContextAwareProcessor.java +++ b/org.springframework.context/src/main/java/org/springframework/context/support/ApplicationContextAwareProcessor.java @@ -27,8 +27,10 @@ import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.EmbeddedValueResolverAware; +import org.springframework.context.EnvironmentAware; import org.springframework.context.MessageSourceAware; import org.springframework.context.ResourceLoaderAware; +import org.springframework.core.env.Environment; import org.springframework.util.StringValueResolver; /** @@ -37,18 +39,24 @@ import org.springframework.util.StringValueResolver; * implement the {@link ResourceLoaderAware}, {@link MessageSourceAware}, * {@link ApplicationEventPublisherAware} and/or * {@link ApplicationContextAware} interfaces. - * If all of them are implemented, they are satisfied in the given order. + * + *

Also delegates the ApplicationContext {@link Environment} instance + * to beans that implement {@link EnvironmentAware}. + * + *

Implemented interfaces are satisfied in order of their mention above. * *

Application contexts will automatically register this with their * underlying bean factory. Applications do not use this directly. * * @author Juergen Hoeller * @author Costin Leau + * @author Chris Beams * @since 10.10.2003 * @see org.springframework.context.ResourceLoaderAware * @see org.springframework.context.MessageSourceAware * @see org.springframework.context.ApplicationEventPublisherAware * @see org.springframework.context.ApplicationContextAware + * @see org.springframework.context.EnvironmentAware * @see org.springframework.context.support.AbstractApplicationContext#refresh() */ class ApplicationContextAwareProcessor implements BeanPostProcessor { @@ -105,6 +113,9 @@ class ApplicationContextAwareProcessor implements BeanPostProcessor { if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); } + if (bean instanceof EnvironmentAware) { + ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); + } } public Object postProcessAfterInitialization(Object bean, String beanName) { diff --git a/org.springframework.context/src/main/java/org/springframework/context/support/EnvironmentAwarePropertyPlaceholderConfigurer.java b/org.springframework.context/src/main/java/org/springframework/context/support/EnvironmentAwarePropertyPlaceholderConfigurer.java new file mode 100644 index 00000000000..ac9693a0f9f --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/context/support/EnvironmentAwarePropertyPlaceholderConfigurer.java @@ -0,0 +1,115 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.support; + +import java.util.LinkedList; +import java.util.Properties; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.AbstractPropertyPlaceholderConfigurer; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; +import org.springframework.context.EnvironmentAware; +import org.springframework.core.env.AbstractEnvironment; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; +import org.springframework.core.env.PropertiesPropertySource; +import org.springframework.core.env.PropertySource; +import org.springframework.util.Assert; +import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver; + + +/** + * TODO SPR-7508: document + * + * Local properties are added as a property source in any case. Precedence is based + * on the value of the {@link #setLocalOverride(boolean) localOverride} property. + * + * @author Chris Beams + * @since 3.1 + * @see PropertyPlaceholderConfigurer + * @see EnvironmentAwarePropertyOverrideConfigurer + */ +public class EnvironmentAwarePropertyPlaceholderConfigurer + extends AbstractPropertyPlaceholderConfigurer implements EnvironmentAware { + + private ConfigurableEnvironment environment; + private Environment wrappedEnvironment; + + public void setEnvironment(Environment environment) { + this.wrappedEnvironment = environment; + } + + @Override + protected PlaceholderResolver getPlaceholderResolver(Properties props) { + return new PlaceholderResolver() { + public String resolvePlaceholder(String placeholderName) { + return environment.getProperty(placeholderName); + } + }; + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + Assert.notNull(this.wrappedEnvironment, "Environment must not be null. Did you call setEnvironment()?"); + environment = new AbstractEnvironment() { }; + + LinkedList> propertySources = environment.getPropertySources(); + EnvironmentPropertySource environmentPropertySource = + new EnvironmentPropertySource("wrappedEnvironment", wrappedEnvironment); + + if (!this.localOverride) { + propertySources.add(environmentPropertySource); + } + + if (this.localProperties != null) { + int cx=0; + for (Properties localProps : this.localProperties) { + propertySources.add(new PropertiesPropertySource("localProperties"+cx++, localProps)); + } + } + + if (this.localOverride) { + propertySources.add(environmentPropertySource); + } + + super.postProcessBeanFactory(beanFactory); + } + + static class EnvironmentPropertySource extends PropertySource { + + public EnvironmentPropertySource(String name, Environment source) { + super(name, source); + } + + @Override + public boolean containsProperty(String key) { + return source.containsProperty(key); + } + + @Override + public String getProperty(String key) { + return source.getProperty(key); + } + + @Override + public int size() { + // TODO Auto-generated method stub + return source.getPropertyCount(); + } + } +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/support/GenericApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/support/GenericApplicationContext.java index ce38ecef471..ccd1323f51e 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/support/GenericApplicationContext.java +++ b/org.springframework.context/src/main/java/org/springframework/context/support/GenericApplicationContext.java @@ -28,6 +28,7 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; +import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.ResourcePatternResolver; @@ -78,6 +79,7 @@ import org.springframework.util.Assert; * from the {@link AbstractRefreshableApplicationContext} base class. * * @author Juergen Hoeller + * @author Chris Beams * @since 1.1.2 * @see #registerBeanDefinition * @see #refresh() @@ -102,6 +104,7 @@ public class GenericApplicationContext extends AbstractApplicationContext implem this.beanFactory = new DefaultListableBeanFactory(); this.beanFactory.setParameterNameDiscoverer(new LocalVariableTableParameterNameDiscoverer()); this.beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver()); + registerStandardBeanFactoryPostProcessors(this.beanFactory); } /** @@ -181,7 +184,7 @@ public class GenericApplicationContext extends AbstractApplicationContext implem * delegate all getResource calls to the given ResourceLoader. * If not set, default resource loading will apply. *

The main reason to specify a custom ResourceLoader is to resolve - * resource paths (withour URL prefix) in a specific fashion. + * resource paths (without URL prefix) in a specific fashion. * The default behavior is to resolve such paths as class path locations. * To resolve resource paths as file system locations, specify a * FileSystemResourceLoader here. diff --git a/org.springframework.context/src/main/java/org/springframework/context/support/GenericXmlApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/support/GenericXmlApplicationContext.java index 9346dd2b1ea..a0d45f8faaf 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/support/GenericXmlApplicationContext.java +++ b/org.springframework.context/src/main/java/org/springframework/context/support/GenericXmlApplicationContext.java @@ -17,7 +17,7 @@ package org.springframework.context.support; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; -import org.springframework.core.io.ClassPathResource; +import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.io.Resource; /** @@ -47,6 +47,7 @@ public class GenericXmlApplicationContext extends GenericApplicationContext { * through {@link #load} calls and then manually {@link #refresh refreshed}. */ public GenericXmlApplicationContext() { + reader.setEnvironment(this.getEnvironment()); } /** @@ -88,6 +89,15 @@ public class GenericXmlApplicationContext extends GenericApplicationContext { this.reader.setValidating(validating); } + /** + * Set a custom environment. Should be called before any call to + * {@link #load}. TODO SPR-7508: document + */ + @Override + public void setEnvironment(ConfigurableEnvironment environment) { + super.setEnvironment(environment); + this.reader.setEnvironment(this.getEnvironment()); + } /** * Load bean definitions from the given XML resources. diff --git a/org.springframework.context/src/main/java/org/springframework/jndi/support/SimpleJndiBeanFactory.java b/org.springframework.context/src/main/java/org/springframework/jndi/support/SimpleJndiBeanFactory.java index 493dc7618b3..4d39882719a 100644 --- a/org.springframework.context/src/main/java/org/springframework/jndi/support/SimpleJndiBeanFactory.java +++ b/org.springframework.context/src/main/java/org/springframework/jndi/support/SimpleJndiBeanFactory.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; + import javax.naming.NameNotFoundException; import javax.naming.NamingException; @@ -29,6 +30,8 @@ import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanNotOfRequiredTypeException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.DefaultEnvironment; import org.springframework.jndi.JndiLocatorSupport; import org.springframework.jndi.TypeMismatchNamingException; @@ -67,6 +70,9 @@ public class SimpleJndiBeanFactory extends JndiLocatorSupport implements BeanFac /** Cache of the types of nonshareable resources: bean name --> bean type */ private final Map resourceTypes = new HashMap(); + /** TODO SPR-7508: should be JNDI-specific environment */ + private ConfigurableEnvironment environment = new DefaultEnvironment(); + public SimpleJndiBeanFactory() { setResourceRef(true); @@ -94,6 +100,11 @@ public class SimpleJndiBeanFactory extends JndiLocatorSupport implements BeanFac } + //--------------------------------------------------------------------- + // Implementation of BeanFactory interface + //--------------------------------------------------------------------- + + public Object getBean(String name) throws BeansException { return getBean(name, Object.class); } diff --git a/org.springframework.context/src/main/resources/META-INF/spring.schemas b/org.springframework.context/src/main/resources/META-INF/spring.schemas index 21fce18c554..ec51d5eeea6 100644 --- a/org.springframework.context/src/main/resources/META-INF/spring.schemas +++ b/org.springframework.context/src/main/resources/META-INF/spring.schemas @@ -1,13 +1,17 @@ http\://www.springframework.org/schema/context/spring-context-2.5.xsd=org/springframework/context/config/spring-context-2.5.xsd http\://www.springframework.org/schema/context/spring-context-3.0.xsd=org/springframework/context/config/spring-context-3.0.xsd -http\://www.springframework.org/schema/context/spring-context.xsd=org/springframework/context/config/spring-context-3.0.xsd +http\://www.springframework.org/schema/context/spring-context-3.1.xsd=org/springframework/context/config/spring-context-3.1.xsd +http\://www.springframework.org/schema/context/spring-context.xsd=org/springframework/context/config/spring-context-3.1.xsd http\://www.springframework.org/schema/jee/spring-jee-2.0.xsd=org/springframework/ejb/config/spring-jee-2.0.xsd http\://www.springframework.org/schema/jee/spring-jee-2.5.xsd=org/springframework/ejb/config/spring-jee-2.5.xsd http\://www.springframework.org/schema/jee/spring-jee-3.0.xsd=org/springframework/ejb/config/spring-jee-3.0.xsd -http\://www.springframework.org/schema/jee/spring-jee.xsd=org/springframework/ejb/config/spring-jee-3.0.xsd +http\://www.springframework.org/schema/jee/spring-jee-3.1.xsd=org/springframework/ejb/config/spring-jee-3.1.xsd +http\://www.springframework.org/schema/jee/spring-jee.xsd=org/springframework/ejb/config/spring-jee-3.1.xsd http\://www.springframework.org/schema/lang/spring-lang-2.0.xsd=org/springframework/scripting/config/spring-lang-2.0.xsd http\://www.springframework.org/schema/lang/spring-lang-2.5.xsd=org/springframework/scripting/config/spring-lang-2.5.xsd http\://www.springframework.org/schema/lang/spring-lang-3.0.xsd=org/springframework/scripting/config/spring-lang-3.0.xsd -http\://www.springframework.org/schema/lang/spring-lang.xsd=org/springframework/scripting/config/spring-lang-3.0.xsd +http\://www.springframework.org/schema/lang/spring-lang-3.1.xsd=org/springframework/scripting/config/spring-lang-3.1.xsd +http\://www.springframework.org/schema/lang/spring-lang.xsd=org/springframework/scripting/config/spring-lang-3.1.xsd http\://www.springframework.org/schema/task/spring-task-3.0.xsd=org/springframework/scheduling/config/spring-task-3.0.xsd -http\://www.springframework.org/schema/task/spring-task.xsd=org/springframework/scheduling/config/spring-task-3.0.xsd +http\://www.springframework.org/schema/task/spring-task-3.1.xsd=org/springframework/scheduling/config/spring-task-3.1.xsd +http\://www.springframework.org/schema/task/spring-task.xsd=org/springframework/scheduling/config/spring-task-3.1.xsd diff --git a/org.springframework.context/src/main/resources/org/springframework/context/config/spring-context-3.1.xsd b/org.springframework.context/src/main/resources/org/springframework/context/config/spring-context-3.1.xsd new file mode 100644 index 00000000000..f5366683b2a --- /dev/null +++ b/org.springframework.context/src/main/resources/org/springframework/context/config/spring-context-3.1.xsd @@ -0,0 +1,500 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + tag for that purpose. + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.context/src/main/resources/org/springframework/ejb/config/spring-jee-3.1.xsd b/org.springframework.context/src/main/resources/org/springframework/ejb/config/spring-jee-3.1.xsd new file mode 100644 index 00000000000..217f391800b --- /dev/null +++ b/org.springframework.context/src/main/resources/org/springframework/ejb/config/spring-jee-3.1.xsd @@ -0,0 +1,254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.context/src/main/resources/org/springframework/scheduling/config/spring-task-3.1.xsd b/org.springframework.context/src/main/resources/org/springframework/scheduling/config/spring-task-3.1.xsd new file mode 100644 index 00000000000..1166d499ed3 --- /dev/null +++ b/org.springframework.context/src/main/resources/org/springframework/scheduling/config/spring-task-3.1.xsd @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.context/src/main/resources/org/springframework/scripting/config/spring-lang-3.1.xsd b/org.springframework.context/src/main/resources/org/springframework/scripting/config/spring-lang-3.1.xsd new file mode 100644 index 00000000000..6659a769449 --- /dev/null +++ b/org.springframework.context/src/main/resources/org/springframework/scripting/config/spring-lang-3.1.xsd @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.context/src/test/java/example/profilescan/ProfileAnnotatedComponent.java b/org.springframework.context/src/test/java/example/profilescan/ProfileAnnotatedComponent.java new file mode 100644 index 00000000000..860c7581b78 --- /dev/null +++ b/org.springframework.context/src/test/java/example/profilescan/ProfileAnnotatedComponent.java @@ -0,0 +1,13 @@ +package example.profilescan; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +@Profile(ProfileAnnotatedComponent.PROFILE_NAME) +@Component(ProfileAnnotatedComponent.BEAN_NAME) +public class ProfileAnnotatedComponent { + + public static final String BEAN_NAME = "profileAnnotatedComponent"; + public static final String PROFILE_NAME = "test"; + +} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/AsmCircularImportDetectionTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/AsmCircularImportDetectionTests.java index 390a5cf9220..21fc1e9105c 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/AsmCircularImportDetectionTests.java +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/AsmCircularImportDetectionTests.java @@ -16,6 +16,7 @@ package org.springframework.context.annotation; import org.springframework.beans.factory.parsing.FailFastProblemReporter; +import org.springframework.core.env.DefaultEnvironment; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; /** @@ -32,7 +33,7 @@ public class AsmCircularImportDetectionTests extends AbstractCircularImportDetec @Override protected ConfigurationClassParser newParser() { - return new ConfigurationClassParser(new CachingMetadataReaderFactory(), new FailFastProblemReporter()); + return new ConfigurationClassParser(new CachingMetadataReaderFactory(), new FailFastProblemReporter(), new DefaultEnvironment()); } @Override diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerTests.java index 4d214eb2c07..50b8cd20459 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerTests.java +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerTests.java @@ -152,11 +152,12 @@ public class ClassPathBeanDefinitionScannerTests { public void testSimpleScanWithDefaultFiltersAndOverriddenEqualNamedBean() { GenericApplicationContext context = new GenericApplicationContext(); context.registerBeanDefinition("myNamedDao", new RootBeanDefinition(NamedStubDao.class)); + int initialBeanCount = context.getBeanDefinitionCount(); ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); scanner.setIncludeAnnotationConfig(false); - int beanCount = scanner.scan(BASE_PACKAGE); - assertEquals(5, beanCount); - assertEquals(6, context.getBeanDefinitionCount()); + int scannedBeanCount = scanner.scan(BASE_PACKAGE); + assertEquals(5, scannedBeanCount); + assertEquals(initialBeanCount + scannedBeanCount, context.getBeanDefinitionCount()); assertTrue(context.containsBean("serviceInvocationCounter")); assertTrue(context.containsBean("fooServiceImpl")); assertTrue(context.containsBean("stubFooDao")); @@ -170,11 +171,12 @@ public class ClassPathBeanDefinitionScannerTests { RootBeanDefinition bd = new RootBeanDefinition(NamedStubDao.class); bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); context.registerBeanDefinition("myNamedDao", bd); + int initialBeanCount = context.getBeanDefinitionCount(); ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); scanner.setIncludeAnnotationConfig(false); - int beanCount = scanner.scan(BASE_PACKAGE); - assertEquals(5, beanCount); - assertEquals(6, context.getBeanDefinitionCount()); + int scannedBeanCount = scanner.scan(BASE_PACKAGE); + assertEquals(5, scannedBeanCount); + assertEquals(initialBeanCount + scannedBeanCount, context.getBeanDefinitionCount()); assertTrue(context.containsBean("serviceInvocationCounter")); assertTrue(context.containsBean("fooServiceImpl")); assertTrue(context.containsBean("stubFooDao")); @@ -362,11 +364,12 @@ public class ClassPathBeanDefinitionScannerTests { public void testMultipleScanCalls() { GenericApplicationContext context = new GenericApplicationContext(); ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); - int beanCount = scanner.scan(BASE_PACKAGE); - assertEquals(10, beanCount); - assertEquals(beanCount, context.getBeanDefinitionCount()); + int initialBeanCount = context.getBeanDefinitionCount(); + int scannedBeanCount = scanner.scan(BASE_PACKAGE); + assertEquals(10, scannedBeanCount); + assertEquals(scannedBeanCount, context.getBeanDefinitionCount() - initialBeanCount); int addedBeanCount = scanner.scan("org.springframework.aop.aspectj.annotation"); - assertEquals(beanCount + addedBeanCount, context.getBeanDefinitionCount()); + assertEquals(initialBeanCount + scannedBeanCount + addedBeanCount, context.getBeanDefinitionCount()); } @Test diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProviderTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProviderTests.java index 3ea25d3725d..0774a66cfd0 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProviderTests.java +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProviderTests.java @@ -16,10 +16,30 @@ package org.springframework.context.annotation; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + import java.util.Iterator; import java.util.Set; import java.util.regex.Pattern; +import org.aspectj.lang.annotation.Aspect; +import org.junit.Test; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.DefaultEnvironment; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.core.type.filter.AssignableTypeFilter; +import org.springframework.core.type.filter.RegexPatternTypeFilter; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Controller; +import org.springframework.stereotype.Repository; +import org.springframework.stereotype.Service; + +import example.profilescan.ProfileAnnotatedComponent; import example.scannable.FooDao; import example.scannable.FooService; import example.scannable.FooServiceImpl; @@ -28,18 +48,6 @@ import example.scannable.NamedComponent; import example.scannable.NamedStubDao; import example.scannable.ServiceInvocationCounter; import example.scannable.StubFooDao; -import org.aspectj.lang.annotation.Aspect; -import static org.junit.Assert.*; -import org.junit.Test; - -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.core.type.filter.AnnotationTypeFilter; -import org.springframework.core.type.filter.AssignableTypeFilter; -import org.springframework.core.type.filter.RegexPatternTypeFilter; -import org.springframework.stereotype.Component; -import org.springframework.stereotype.Controller; -import org.springframework.stereotype.Repository; -import org.springframework.stereotype.Service; /** * @author Mark Fisher @@ -49,7 +57,7 @@ import org.springframework.stereotype.Service; public class ClassPathScanningCandidateComponentProviderTests { private static final String TEST_BASE_PACKAGE = "example.scannable"; - //ClassPathScanningCandidateComponentProviderTests.class.getPackage().getName(); + private static final String TEST_PROFILE_PACKAGE = "example.profilescan"; @Test @@ -102,7 +110,6 @@ public class ClassPathScanningCandidateComponentProviderTests { assertFalse(containsBeanClass(candidates, NamedStubDao.class)); } - @SuppressWarnings("unchecked") @Test public void testWithAspectAnnotationOnly() throws Exception { ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); @@ -155,6 +162,59 @@ public class ClassPathScanningCandidateComponentProviderTests { assertFalse(containsBeanClass(candidates, FooServiceImpl.class)); } + @Test + public void testWithNullEnvironment() { + ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true); + Set candidates = provider.findCandidateComponents(TEST_PROFILE_PACKAGE); + assertThat(containsBeanClass(candidates, ProfileAnnotatedComponent.class), is(false)); + } + + @Test + public void testWithInactiveProfile() { + ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true); + ConfigurableEnvironment env = new DefaultEnvironment(); + env.setActiveProfiles("other"); + provider.setEnvironment(env); + Set candidates = provider.findCandidateComponents(TEST_PROFILE_PACKAGE); + assertThat(containsBeanClass(candidates, ProfileAnnotatedComponent.class), is(false)); + } + + @Test + public void testWithActiveProfile() { + ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true); + ConfigurableEnvironment env = new DefaultEnvironment(); + env.setActiveProfiles(ProfileAnnotatedComponent.PROFILE_NAME); + provider.setEnvironment(env); + Set candidates = provider.findCandidateComponents(TEST_PROFILE_PACKAGE); + assertThat(containsBeanClass(candidates, ProfileAnnotatedComponent.class), is(true)); + } + + @Test + public void testIntegrationWithAnnotationConfigApplicationContext_noProfile() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(ProfileAnnotatedComponent.class); + ctx.refresh(); + assertThat(ctx.containsBean(ProfileAnnotatedComponent.BEAN_NAME), is(false)); + } + + @Test + public void testIntegrationWithAnnotationConfigApplicationContext_validProfile() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.getEnvironment().setActiveProfiles(ProfileAnnotatedComponent.PROFILE_NAME); + ctx.register(ProfileAnnotatedComponent.class); + ctx.refresh(); + assertThat(ctx.containsBean(ProfileAnnotatedComponent.BEAN_NAME), is(true)); + } + + @Test + public void testIntegrationWithAnnotationConfigApplicationContext_invalidProfile() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.getEnvironment().setActiveProfiles("other"); + ctx.register(ProfileAnnotatedComponent.class); + ctx.refresh(); + assertThat(ctx.containsBean(ProfileAnnotatedComponent.BEAN_NAME), is(false)); + } + private boolean containsBeanClass(Set candidates, Class beanClass) { for (Iterator it = candidates.iterator(); it.hasNext();) { ScannedGenericBeanDefinition definition = (ScannedGenericBeanDefinition) it.next(); diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanAnnotationTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanAnnotationTests.java new file mode 100644 index 00000000000..39f8dffc112 --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanAnnotationTests.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import org.junit.Test; +import org.springframework.beans.factory.support.DefaultBeanNameGenerator; +import org.springframework.context.annotation.ComponentScan.ExcludeFilter; +import org.springframework.context.annotation.ComponentScan.IncludeFilter; +import org.springframework.core.type.filter.TypeFilter; + +/** + * Unit tests for {@link ComponentScan} annotation. + * + * @author Chris Beams + * @since 3.1 + */ +public class ComponentScanAnnotationTests { + @Test + public void test() { + + } +} + +@interface MyAnnotation { } + +@Configuration +@ComponentScan( + packageOf={TestBean.class}, + nameGenerator = DefaultBeanNameGenerator.class, + scopedProxy = ScopedProxyMode.NO, + scopeResolver = AnnotationScopeMetadataResolver.class, + useDefaultFilters = false, + resourcePattern = "**/*custom.class", + includeFilters = { + @IncludeFilter(type = FilterType.ANNOTATION, value = MyAnnotation.class) + }, + excludeFilters = { + @ExcludeFilter(type = FilterType.CUSTOM, value = TypeFilter.class) + } +) +class MyConfig { + +} + +@ComponentScan(packageOf=example.scannable.NamedComponent.class) +class SimpleConfig { } \ No newline at end of file diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanParserTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanParserTests.java index bd055d3e48b..4181cc2233c 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanParserTests.java +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/ComponentScanParserTests.java @@ -16,7 +16,12 @@ package org.springframework.context.annotation; -import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -26,11 +31,14 @@ import java.lang.annotation.Target; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.GenericXmlApplicationContext; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.TypeFilter; +import example.profilescan.ProfileAnnotatedComponent; import example.scannable.AutowiredQualifierFooService; /** @@ -88,6 +96,31 @@ public class ComponentScanParserTests { assertNotNull(testBean.getDependency()); } + @Test + public void testComponentScanRespectsProfileAnnotation() { + String xmlLocation = "org/springframework/context/annotation/componentScanRespectsProfileAnnotationTests.xml"; + { // should exclude the profile-annotated bean if active profiles remains unset + GenericXmlApplicationContext context = new GenericXmlApplicationContext(); + context.load(xmlLocation); + context.refresh(); + assertThat(context.containsBean(ProfileAnnotatedComponent.BEAN_NAME), is(false)); + } + { // should include the profile-annotated bean with active profiles set + GenericXmlApplicationContext context = new GenericXmlApplicationContext(); + context.getEnvironment().setActiveProfiles(ProfileAnnotatedComponent.PROFILE_NAME); + context.load(xmlLocation); + context.refresh(); + assertThat(context.containsBean(ProfileAnnotatedComponent.BEAN_NAME), is(true)); + } + { // ensure the same works for AbstractRefreshableApplicationContext impls too + ConfigurableApplicationContext context = + new ClassPathXmlApplicationContext(new String[]{xmlLocation}, false); + context.getEnvironment().setActiveProfiles(ProfileAnnotatedComponent.PROFILE_NAME); + context.refresh(); + assertThat(context.containsBean(ProfileAnnotatedComponent.BEAN_NAME), is(true)); + } + } + @Target({ElementType.TYPE, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/componentScanRespectsProfileAnnotationTests.xml b/org.springframework.context/src/test/java/org/springframework/context/annotation/componentScanRespectsProfileAnnotationTests.xml new file mode 100644 index 00000000000..a35ea025430 --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/componentScanRespectsProfileAnnotationTests.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/org.springframework.context/src/test/java/org/springframework/context/config/ContextNamespaceHandlerTests.java b/org.springframework.context/src/test/java/org/springframework/context/config/ContextNamespaceHandlerTests.java index c34c3f58850..c760e5d7eca 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/config/ContextNamespaceHandlerTests.java +++ b/org.springframework.context/src/test/java/org/springframework/context/config/ContextNamespaceHandlerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2008 the original author or authors. + * Copyright 2002-2010 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,23 +16,27 @@ package org.springframework.context.config; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + import java.util.Calendar; import java.util.Date; import java.util.Map; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import org.junit.Before; import org.junit.Test; - +import org.springframework.beans.factory.config.AbstractPropertyPlaceholderConfigurer; 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; +import org.springframework.core.io.ClassPathResource; +import org.springframework.mock.env.MockEnvironment; /** * @author Arjen Poutsma * @author Dave Syer + * @author Chris Beams * @since 2.5.6 */ public class ContextNamespaceHandlerTests { @@ -41,9 +45,9 @@ public class ContextNamespaceHandlerTests { public void propertyPlaceholder() throws Exception { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "contextNamespaceHandlerTests-replace.xml", getClass()); - Map beans = applicationContext - .getBeansOfType(PropertyPlaceholderConfigurer.class); - assertFalse("No PropertyPlaceHolderConfigurer found", beans.isEmpty()); + Map beans = applicationContext + .getBeansOfType(AbstractPropertyPlaceholderConfigurer.class); + assertFalse("No PropertyPlaceholderConfigurer found", beans.isEmpty()); String s = (String) applicationContext.getBean("string"); assertEquals("No properties replaced", "bar", s); } @@ -56,7 +60,7 @@ public class ContextNamespaceHandlerTests { "contextNamespaceHandlerTests-system.xml", getClass()); Map beans = applicationContext .getBeansOfType(PropertyPlaceholderConfigurer.class); - assertFalse("No PropertyPlaceHolderConfigurer found", beans.isEmpty()); + assertFalse("No PropertyPlaceholderConfigurer found", beans.isEmpty()); String s = (String) applicationContext.getBean("string"); assertEquals("No properties replaced", "spam", s); } finally { @@ -66,13 +70,27 @@ public class ContextNamespaceHandlerTests { } } + @Test + public void propertyPlaceholderEnvironmentProperties() throws Exception { + MockEnvironment env = MockEnvironment.withProperty("foo", "spam"); + GenericXmlApplicationContext applicationContext = new GenericXmlApplicationContext(); + applicationContext.setEnvironment(env); + applicationContext.load(new ClassPathResource("contextNamespaceHandlerTests-simple.xml", getClass())); + applicationContext.refresh(); + Map beans = applicationContext + .getBeansOfType(AbstractPropertyPlaceholderConfigurer.class); + assertFalse("No PropertyPlaceholderConfigurer found", beans.isEmpty()); + String s = (String) applicationContext.getBean("string"); + assertEquals("No properties replaced", "spam", s); + } + @Test 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()); + assertFalse("No PropertyPlaceholderConfigurer found", beans.isEmpty()); String s = (String) applicationContext.getBean("foo"); assertEquals("No properties replaced", "bar", s); s = (String) applicationContext.getBean("bar"); @@ -85,9 +103,9 @@ public class ContextNamespaceHandlerTests { public void propertyPlaceholderIgnored() throws Exception { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "contextNamespaceHandlerTests-replace-ignore.xml", getClass()); - Map beans = applicationContext - .getBeansOfType(PropertyPlaceholderConfigurer.class); - assertFalse("No PropertyPlaceHolderConfigurer found", beans.isEmpty()); + Map beans = applicationContext + .getBeansOfType(AbstractPropertyPlaceholderConfigurer.class); + assertFalse("No PropertyPlaceholderConfigurer found", beans.isEmpty()); String s = (String) applicationContext.getBean("string"); assertEquals("Properties replaced", "${bar}", s); } diff --git a/org.springframework.context/src/test/java/org/springframework/context/expression/ApplicationContextExpressionTests.java b/org.springframework.context/src/test/java/org/springframework/context/expression/ApplicationContextExpressionTests.java index c48b505337a..7149bbca543 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/expression/ApplicationContextExpressionTests.java +++ b/org.springframework.context/src/test/java/org/springframework/context/expression/ApplicationContextExpressionTests.java @@ -240,7 +240,6 @@ public class ApplicationContextExpressionTests { System.getProperties().remove("country"); System.getProperties().remove("name"); } - System.out.println(sw.getTotalTimeMillis()); assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 6000); } diff --git a/org.springframework.context/src/test/java/org/springframework/context/expression/EnvironmentAccessorIntegrationTests.java b/org.springframework.context/src/test/java/org/springframework/context/expression/EnvironmentAccessorIntegrationTests.java new file mode 100644 index 00000000000..755b50acefc --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/context/expression/EnvironmentAccessorIntegrationTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.expression; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition; + +import java.util.HashMap; + +import org.junit.Test; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.GenericApplicationContext; + +import test.beans.TestBean; + + +/** + * Integration tests for {@link EnvironmentAccessor}, which is registered with + * SpEL for all {@link AbstractApplicationContext} implementations via + * {@link StandardBeanExpressionResolver}. + * + * @author Chris Beams + */ +public class EnvironmentAccessorIntegrationTests { + + @Test + @SuppressWarnings("all") + public void braceAccess() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerBeanDefinition("testBean", + genericBeanDefinition(TestBean.class) + .addPropertyValue("name", "#{environment['my.name']}") + .getBeanDefinition()); + + GenericApplicationContext ctx = new GenericApplicationContext(bf); + ctx.getEnvironment().addPropertySource("testMap", new HashMap() {{ put("my.name", "myBean"); }}); + ctx.refresh(); + + assertThat(ctx.getBean(TestBean.class).getName(), equalTo("myBean")); + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/context/support/EnvironmentAwarePropertyPlaceholderConfigurerTests.java b/org.springframework.context/src/test/java/org/springframework/context/support/EnvironmentAwarePropertyPlaceholderConfigurerTests.java new file mode 100644 index 00000000000..852330cefba --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/context/support/EnvironmentAwarePropertyPlaceholderConfigurerTests.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.support; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition; + +import org.junit.Test; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.mock.env.MockEnvironment; + +import test.beans.TestBean; + +/** + * Unit tests for {@link EnvironmentAwarePropertyPlaceholderConfigurer}. + * + * @author Chris Beams + * @since 3.1 + * @see EnvironmentAwarePropertyPlaceholderConfigurerTests + */ +public class EnvironmentAwarePropertyPlaceholderConfigurerTests { + + @Test(expected=IllegalArgumentException.class) + public void environmentNotNull() { + new EnvironmentAwarePropertyPlaceholderConfigurer().postProcessBeanFactory(new DefaultListableBeanFactory()); + } + + @Test + public void localPropertiesOverrideFalse() { + localPropertiesOverride(false); + } + + @Test + public void localPropertiesOverrideTrue() { + localPropertiesOverride(true); + } + + private void localPropertiesOverride(boolean override) { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerBeanDefinition("testBean", + genericBeanDefinition(TestBean.class) + .addPropertyValue("name", "${foo}") + .getBeanDefinition()); + + EnvironmentAwarePropertyPlaceholderConfigurer ppc = new EnvironmentAwarePropertyPlaceholderConfigurer(); + + ppc.setLocalOverride(override); + ppc.setProperties(MockEnvironment.withProperty("foo", "local").asProperties()); + ppc.setEnvironment(MockEnvironment.withProperty("foo", "enclosing")); + ppc.postProcessBeanFactory(bf); + if (override) { + assertThat(bf.getBean(TestBean.class).getName(), equalTo("local")); + } else { + assertThat(bf.getBean(TestBean.class).getName(), equalTo("enclosing")); + } + } + + @Test + public void simpleReplacement() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerBeanDefinition("testBean", + genericBeanDefinition(TestBean.class) + .addPropertyValue("name", "${my.name}") + .getBeanDefinition()); + + MockEnvironment env = new MockEnvironment(); + env.setProperty("my.name", "myValue"); + + EnvironmentAwarePropertyPlaceholderConfigurer ppc = + new EnvironmentAwarePropertyPlaceholderConfigurer(); + ppc.setEnvironment(env); + ppc.postProcessBeanFactory(bf); + assertThat(bf.getBean(TestBean.class).getName(), equalTo("myValue")); + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/mock/env/MockEnvironment.java b/org.springframework.context/src/test/java/org/springframework/mock/env/MockEnvironment.java new file mode 100644 index 00000000000..2a6ec523686 --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/mock/env/MockEnvironment.java @@ -0,0 +1,48 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.env; + +import org.springframework.core.env.AbstractEnvironment; +import org.springframework.core.env.ConfigurableEnvironment; + + +/** + * Simple {@link ConfigurableEnvironment} implementation exposing a + * {@link #setProperty(String, String)} and {@link #withProperty(String, String)} + * methods for testing purposes. + * + * @author Chris Beams + * @see MockPropertySource + */ +public class MockEnvironment extends AbstractEnvironment { + + private MockPropertySource propertySource = new MockPropertySource(); + + public MockEnvironment() { + getPropertySources().add(propertySource); + } + + public void setProperty(String key, String value) { + propertySource.setProperty(key, value); + } + + public static MockEnvironment withProperty(String key, String value) { + MockEnvironment environment = new MockEnvironment(); + environment.setProperty(key, value); + return environment; + } +} diff --git a/org.springframework.context/src/test/java/org/springframework/mock/env/MockPropertySource.java b/org.springframework.context/src/test/java/org/springframework/mock/env/MockPropertySource.java new file mode 100644 index 00000000000..f1e7285c8ec --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/mock/env/MockPropertySource.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.env; + +import java.util.Properties; + +import org.springframework.core.env.PropertiesPropertySource; + +public class MockPropertySource extends PropertiesPropertySource { + + public MockPropertySource() { + this(new Properties()); + } + + private MockPropertySource(Properties properties) { + super("mockProperties", properties); + } + + public void setProperty(String key, String value) { + this.source.setProperty(key, value); + } + + public static MockPropertySource withProperty(String key, String value) { + Properties properties = new Properties(); + properties.setProperty(key, value); + return new MockPropertySource(properties); + } +} diff --git a/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-override.xml b/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-override.xml index 571397bd6e0..647e08ff9bf 100644 --- a/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-override.xml +++ b/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-override.xml @@ -2,7 +2,7 @@ diff --git a/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-replace-ignore.xml b/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-replace-ignore.xml index 727c03198d9..4714c36217a 100644 --- a/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-replace-ignore.xml +++ b/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-replace-ignore.xml @@ -2,7 +2,7 @@ diff --git a/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-replace.xml b/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-replace.xml index 286cff23d92..92161968f76 100644 --- a/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-replace.xml +++ b/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-replace.xml @@ -2,7 +2,7 @@ @@ -11,7 +11,7 @@ - + diff --git a/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-simple.xml b/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-simple.xml new file mode 100644 index 00000000000..a0b3eaf779f --- /dev/null +++ b/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-simple.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-system.xml b/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-system.xml index 9c475282fc0..d5268c52bcc 100644 --- a/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-system.xml +++ b/org.springframework.context/src/test/resources/org/springframework/context/config/contextNamespaceHandlerTests-system.xml @@ -3,7 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context-3.0.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd"> diff --git a/org.springframework.core/.settings/org.eclipse.jdt.core.prefs b/org.springframework.core/.settings/org.eclipse.jdt.core.prefs index 5a5d4fe0932..51fbd353764 100644 --- a/org.springframework.core/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.core/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ #Wed Jul 15 00:01:31 PDT 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/org.springframework.core/pom.xml b/org.springframework.core/pom.xml index 2c0dbf91320..4d5e6b2dbda 100644 --- a/org.springframework.core/pom.xml +++ b/org.springframework.core/pom.xml @@ -6,12 +6,12 @@ org.springframework spring-core jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/AbstractEnvironment.java b/org.springframework.core/src/main/java/org/springframework/core/env/AbstractEnvironment.java new file mode 100644 index 00000000000..7e6842b7c45 --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/env/AbstractEnvironment.java @@ -0,0 +1,284 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.env; + +import static java.lang.String.format; +import static org.springframework.util.StringUtils.commaDelimitedListToSet; +import static org.springframework.util.StringUtils.trimAllWhitespace; +import static org.springframework.util.SystemPropertyUtils.PLACEHOLDER_PREFIX; +import static org.springframework.util.SystemPropertyUtils.PLACEHOLDER_SUFFIX; +import static org.springframework.util.SystemPropertyUtils.VALUE_SEPARATOR; + +import java.security.AccessControlException; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.support.ConversionServiceFactory; +import org.springframework.util.PropertyPlaceholderHelper; +import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver; + + +/** + * TODO SPR-7508: document + * + * @author Chris Beams + * @since 3.1 + */ +public abstract class AbstractEnvironment implements ConfigurableEnvironment { + + public static final String SPRING_PROFILES_PROPERTY_NAME = "springProfiles"; + + protected final Log logger = LogFactory.getLog(getClass()); + + private final PropertyPlaceholderHelper nonStrictHelper = + new PropertyPlaceholderHelper(PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, VALUE_SEPARATOR, true); + + private final PropertyPlaceholderHelper strictHelper = + new PropertyPlaceholderHelper(PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, VALUE_SEPARATOR, false); + + private Set activeProfiles = new LinkedHashSet(); + private LinkedList> propertySources = new LinkedList>(); + private ConversionService conversionService = ConversionServiceFactory.createDefaultConversionService(); + + private boolean explicitlySetProfiles; + + + public void addPropertySource(PropertySource propertySource) { + propertySources.push(propertySource); + } + + public void addPropertySource(String name, Properties properties) { + addPropertySource(new PropertiesPropertySource(name, properties)); + } + + public void addPropertySource(String name, Map propertiesMap) { + addPropertySource(new MapPropertySource(name, propertiesMap)); + } + + public LinkedList> getPropertySources() { + return propertySources; + } + + public boolean containsProperty(String key) { + for (PropertySource propertySource : propertySources) { + if (propertySource.containsProperty(key)) { + return true; + } + } + return false; + } + + public String getProperty(String key) { + if (logger.isTraceEnabled()) { + logger.trace(format("getProperty(\"%s\") (implicit targetType [String])", key)); + } + return getProperty(key, String.class); + } + + public String getRequiredProperty(String key) { + String value = getProperty(key); + if (value == null) { + throw new IllegalArgumentException(format("required key [%s] not found", key)); + } + return value; + } + + public T getProperty(String key, Class targetValueType) { + boolean debugEnabled = logger.isDebugEnabled(); + if (logger.isTraceEnabled()) { + logger.trace(format("getProperty(\"%s\", %s)", key, targetValueType.getSimpleName())); + } + + for (PropertySource propertySource : propertySources) { + if (debugEnabled) { + logger.debug(format("Searching for key '%s' in [%s]", key, propertySource.getName())); + } + if (propertySource.containsProperty(key)) { + Object value = propertySource.getProperty(key); + Class valueType = value == null ? null : value.getClass(); + if (debugEnabled) { + logger.debug( + format("Found key '%s' in [%s] with type [%s] and value '%s'", + key, propertySource.getName(), + valueType == null ? "" : valueType.getSimpleName(), value)); + } + if (value == null) { + return null; + } + if (!conversionService.canConvert(valueType, targetValueType)) { + throw new IllegalArgumentException( + format("Cannot convert value [%s] from source type [%s] to target type [%s]", + value, valueType.getSimpleName(), targetValueType.getSimpleName())); + } + return conversionService.convert(value, targetValueType); + } + } + + if (debugEnabled) { + logger.debug(format("Could not find key '%s' in any property source. Returning [null]", key)); + } + return null; + } + + public T getRequiredProperty(String key, Class valueType) { + T value = getProperty(key, valueType); + if (value == null) { + throw new IllegalArgumentException(format("required key [%s] not found", key)); + } + return value; + } + + public int getPropertyCount() { + return asProperties().size(); + } + + public Properties asProperties() { + // TODO SPR-7508: refactor, simplify. only handles map-based propertysources right now. + Properties mergedProps = new Properties(); + Iterator> descendingIterator = getPropertySources().descendingIterator(); + while (descendingIterator.hasNext()) { + PropertySource propertySource = descendingIterator.next(); + Object object = propertySource.getSource(); + if (object instanceof Map) { + for (Entry entry : ((Map)object).entrySet()) { + mergedProps.put(entry.getKey(), entry.getValue()); + } + } else { + throw new IllegalArgumentException("unknown PropertySource source type: " + object.getClass().getName()); + } + } + return mergedProps; + } + + public Set getActiveProfiles() { + doGetProfiles(); + return Collections.unmodifiableSet(activeProfiles); + } + + private void doGetProfiles() { + if (explicitlySetProfiles) + return; + + String profiles = getProperty(SPRING_PROFILES_PROPERTY_NAME); + if (profiles == null || profiles.equals("")) { + return; + } + + this.activeProfiles = commaDelimitedListToSet(trimAllWhitespace(profiles)); + } + + public void setActiveProfiles(String... profiles) { + explicitlySetProfiles = true; + this.activeProfiles.clear(); + this.activeProfiles.addAll(Arrays.asList(profiles)); + } + + public Map getSystemEnvironment() { + Map systemEnvironment; + try { + systemEnvironment = System.getenv(); + } + catch (AccessControlException ex) { + systemEnvironment = new ReadOnlySystemAttributesMap() { + @Override + protected String getSystemAttribute(String variableName) { + try { + return System.getenv(variableName); + } + catch (AccessControlException ex) { + if (logger.isInfoEnabled()) { + logger.info(format("Caught AccessControlException when accessing system environment variable " + + "[%s]; its value will be returned [null]. Reason: %s", variableName, ex.getMessage())); + } + return null; + } + } + }; + } + return systemEnvironment; + } + + /** + * TODO SPR-7508: document + * + * Returns a string, string map even though the underlying system properties + * are a properties object that can technically contain non-string keys and values. + * Thus, the unchecked conversions and raw map type being used. In practice, it will + * always be 'safe' to interact with the properties map as if it contains only strings, + * because Properties copes with this in its getProperty method. We never access the + * properties object via its Hashtable.get() method, so any non-string keys/values + * get effectively ignored. + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + public Map getSystemProperties() { + Map systemProperties; + try { + systemProperties = System.getProperties(); + } + catch (AccessControlException ex) { + systemProperties = new ReadOnlySystemAttributesMap() { + @Override + protected String getSystemAttribute(String propertyName) { + try { + return System.getProperty(propertyName); + } + catch (AccessControlException ex) { + if (logger.isInfoEnabled()) { + logger.info(format("Caught AccessControlException when accessing system property " + + "[%s]; its value will be returned [null]. Reason: %s", propertyName, ex.getMessage())); + } + return null; + } + } + }; + } + return systemProperties; + } + + public String resolvePlaceholders(String text) { + return doResolvePlaceholders(text, nonStrictHelper); + } + + public String resolveRequiredPlaceholders(String text) { + return doResolvePlaceholders(text, strictHelper); + } + + private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) { + return helper.replacePlaceholders(text, new PlaceholderResolver() { + public String resolvePlaceholder(String placeholderName) { + return AbstractEnvironment.this.getProperty(placeholderName); + } + }); + } + + @Override + public String toString() { + return getClass().getSimpleName() + " [activeProfiles=" + activeProfiles + + ", propertySources=" + propertySources + "]"; + } + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/ConfigurableEnvironment.java b/org.springframework.core/src/main/java/org/springframework/core/env/ConfigurableEnvironment.java new file mode 100644 index 00000000000..d9242f527ea --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/env/ConfigurableEnvironment.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.env; + +/** + * TODO SPR-7508: document + * + * @author Chris Beams + * @since 3.1 + */ +public interface ConfigurableEnvironment extends Environment, PropertySourceAggregator { + + /** + * TODO SPR-7508: document + */ + void setActiveProfiles(String... profiles); + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/DefaultEnvironment.java b/org.springframework.core/src/main/java/org/springframework/core/env/DefaultEnvironment.java new file mode 100644 index 00000000000..6e6190e0079 --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/env/DefaultEnvironment.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.env; + + +/** + * TODO SPR-7508: document + * + * Explain why the default ordering of property sources is the way it is. + * + * @author Chris Beams + * @since 3.1 + */ +public class DefaultEnvironment extends AbstractEnvironment { + + public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment"; + public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties"; + + + public DefaultEnvironment() { + addPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()); + addPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()); + } + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/DefaultWebEnvironment.java b/org.springframework.core/src/main/java/org/springframework/core/env/DefaultWebEnvironment.java new file mode 100644 index 00000000000..97c3986a0ac --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/env/DefaultWebEnvironment.java @@ -0,0 +1,31 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.env; + + +/** + * TODO SPR-7508: document + * + * @author Chris Beams + * @since 3.1 + */ +public class DefaultWebEnvironment extends DefaultEnvironment { + + public static final String SERVLET_CONTEXT_PARAMS_PROPERTY_SOURCE_NAME = "servletContextInitParams"; + public static final String SERVLET_CONFIG_PARAMS_PROPERTY_SOURCE_NAME = "servletConfigInitParams"; + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/Environment.java b/org.springframework.core/src/main/java/org/springframework/core/env/Environment.java new file mode 100644 index 00000000000..12fe953cc04 --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/env/Environment.java @@ -0,0 +1,101 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.env; + +import java.util.Map; +import java.util.Properties; +import java.util.Set; + + +/** + * TODO SPR-7508: document + * TODO: Consider extracting a PropertyResolutionService interface + * + * @author Chris Beams + * @since 3.1 + */ +public interface Environment { + + /** + * TODO SPR-7508: document + */ + Set getActiveProfiles(); + + /** + * TODO SPR-7508: document + */ + boolean containsProperty(String key); + + /** + * TODO SPR-7508: document + */ + String getProperty(String key); + + /** + * TODO SPR-7508: document + */ + T getProperty(String key, Class targetType); + + /** + * TODO SPR-7508: document + */ + String getRequiredProperty(String key); + + /** + * TODO SPR-7508: document + */ + T getRequiredProperty(String key, Class targetType); + + /** + * TODO SPR-7508: document + */ + int getPropertyCount(); + + /** + * TODO SPR-7508: document + */ + Properties asProperties(); + + /** + * TODO SPR-7508: document that this returns {@link System#getenv()} if allowed, or + * {@link ReadOnlySystemAttributesMap} if not. + */ + Map getSystemEnvironment(); + + /** + * TODO SPR-7508: document that this returns {@link System#getProperties()} if allowed, or + * {@link ReadOnlySystemAttributesMap} if not. Actually, always returns + * {@link ReadOnlySystemAttributesMap} now. + * see notes within {@link AbstractEnvironment#getSystemProperties()} + */ + Map getSystemProperties(); + + /** + * TODO SPR-7508: document + * @see #resolveRequiredPlaceholders(String) + * @see org.springframework.util.SystemPropertyUtils#resolvePlaceholders(String, int) + */ + String resolvePlaceholders(String text); + + /** + * TODO SPR-7508: document + * @see #resolvePlaceholders(String) + * @see org.springframework.util.SystemPropertyUtils#resolvePlaceholders(String, int) + */ + String resolveRequiredPlaceholders(String path); + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/EnvironmentCapable.java b/org.springframework.core/src/main/java/org/springframework/core/env/EnvironmentCapable.java new file mode 100644 index 00000000000..5705502aecd --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/env/EnvironmentCapable.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.env; + + +/** + * TODO SPR-7508: document + * + * @author Chris Beams + * @since 3.1 + * @see Environment + * @see ConfigurableEnvironmentCapable + */ +public interface EnvironmentCapable { + + Environment getEnvironment(); + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/MapPropertySource.java b/org.springframework.core/src/main/java/org/springframework/core/env/MapPropertySource.java new file mode 100644 index 00000000000..469c590cc97 --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/env/MapPropertySource.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.env; + +import java.util.Map; + + +/** + * TODO SPR-7508: document + * + * Consider adding a TypeConvertingMapPropertySource to accommodate + * non-string keys and values. Could be confusing when used in conjunction + * with Environment.getProperty(), which also does type conversions. If this + * is added, consider renaming this class to SimpleMapPropertySource and + * rename PropertiesPropertySource to SimplePropertiesPropertySource. + * + * @author Chris Beams + * @since 3.1 + */ +public class MapPropertySource extends PropertySource> { + + protected MapPropertySource(String name, Map source) { + super(name, source); + } + + public boolean containsProperty(String key) { + return source.containsKey(key); + } + + public String getProperty(String key) { + return source.get(key); + } + + @Override + public int size() { + return source.size(); + } + +} \ No newline at end of file diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/PropertiesPropertySource.java b/org.springframework.core/src/main/java/org/springframework/core/env/PropertiesPropertySource.java new file mode 100644 index 00000000000..98ac9647fbf --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/env/PropertiesPropertySource.java @@ -0,0 +1,54 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.env; + +import java.util.Properties; + + +/** + * TODO SPR-7508: document how this does accept a Properties object, + * which is capable of holding non-string keys and values (because + * Properties is a Hashtable), but is limited to resolving string-based + * keys and values. + * + * Consider adding a TypeConvertingPropertiesPropertySource to accommodate + * non-string keys and values (such as is technically possible with + * System.getProperties()) + * + * @author Chris Beams + * @since 3.1 + */ +public class PropertiesPropertySource extends PropertySource { + + public PropertiesPropertySource(String name, Properties source) { + super(name, source); + } + + public boolean containsProperty(String key) { + return source.containsKey(key); + } + + public String getProperty(String key) { + return source.getProperty(key); + } + + @Override + public int size() { + return source.size(); + } + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/PropertySource.java b/org.springframework.core/src/main/java/org/springframework/core/env/PropertySource.java new file mode 100644 index 00000000000..31ee0124a2c --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/env/PropertySource.java @@ -0,0 +1,139 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.env; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +public abstract class PropertySource { + + protected final Log logger = LogFactory.getLog(this.getClass()); + + protected final String name; + protected final T source; + + public PropertySource(String name, T source) { + this.name = name; + this.source = source; + } + + public String getName() { + return name; + } + + public T getSource() { + return source; + } + + public abstract boolean containsProperty(String key); + + public abstract String getProperty(String key); + + public abstract int size(); + + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (!(obj instanceof PropertySource)) + return false; + PropertySource other = (PropertySource) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } + + /** + * Produce concise output (type, name, and number of properties) if the current log level does + * not include debug. If debug is enabled, produce verbose output including hashcode of the + * PropertySource instance and every key/value property pair. + * + * This variable verbosity is useful as a property source such as system properties + * or environment variables may contain an arbitrary number of property pairs, potentially + * leading to difficult to read exception and log messages. + * + * @see Log#isDebugEnabled() + */ + @Override + public String toString() { + if (logger.isDebugEnabled()) { + return String.format("%s@%s [name='%s', properties=%s]", + getClass().getSimpleName(), System.identityHashCode(this), name, source); + } + + return String.format("%s [name='%s', propertyCount=%d]", + getClass().getSimpleName(), name, this.size()); + } + + + /** + * For collection comparison purposes + * TODO SPR-7508: document + */ + public static PropertySource named(String name) { + return new ComparisonPropertySource(name); + } + + + /** + * TODO: SPR-7508: document + */ + public static class ComparisonPropertySource extends PropertySource{ + + private static final String USAGE_ERROR = + "ComparisonPropertySource instances are for collection comparison " + + "use only"; + + public ComparisonPropertySource(String name) { + super(name, null); + } + + @Override + public Void getSource() { + throw new UnsupportedOperationException(USAGE_ERROR); + } + public String getProperty(String key) { + throw new UnsupportedOperationException(USAGE_ERROR); + } + public boolean containsProperty(String key) { + throw new UnsupportedOperationException(USAGE_ERROR); + } + public int size() { + throw new UnsupportedOperationException(USAGE_ERROR); + } + + @Override + public String toString() { + return String.format("%s [name='%s']", getClass().getSimpleName(), name); + } + } +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/PropertySourceAggregator.java b/org.springframework.core/src/main/java/org/springframework/core/env/PropertySourceAggregator.java new file mode 100644 index 00000000000..431d3c2a835 --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/env/PropertySourceAggregator.java @@ -0,0 +1,51 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.env; + +import java.util.LinkedList; +import java.util.Map; +import java.util.Properties; + +/** + * TODO: SPR-7508 document + * + * @author Chris Beams + * @since 3.1 + */ +public interface PropertySourceAggregator { + + void addPropertySource(PropertySource propertySource); + + void addPropertySource(String name, Properties properties); + + void addPropertySource(String name, Map propertiesMap); + + /** + * TODO: SPR-7508 document + * + * Care should be taken to ensure duplicates are not introduced. + * + * Recommend using {@link LinkedList#set(int, Object)} for replacing items, + * and combining {@link LinkedList#remove()} with other methods like + * {@link LinkedList#add(Object)} to prevent duplicates. + * + * Explain how {@link PropertySource#equals(Object)} and hashCode work, and that + * recommend using {@link PropertySource#named(String)} for lookups in the list. + */ + LinkedList> getPropertySources(); + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/support/ReadOnlySystemAttributesMap.java b/org.springframework.core/src/main/java/org/springframework/core/env/ReadOnlySystemAttributesMap.java similarity index 66% rename from org.springframework.context/src/main/java/org/springframework/context/support/ReadOnlySystemAttributesMap.java rename to org.springframework.core/src/main/java/org/springframework/core/env/ReadOnlySystemAttributesMap.java index 992f58404a5..c31cb97d025 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/support/ReadOnlySystemAttributesMap.java +++ b/org.springframework.core/src/main/java/org/springframework/core/env/ReadOnlySystemAttributesMap.java @@ -14,12 +14,13 @@ * limitations under the License. */ -package org.springframework.context.support; +package org.springframework.core.env; import java.util.Collection; import java.util.Map; import java.util.Set; + /** * Read-only {@code Map} implementation that is backed by system properties or environment * variables. @@ -28,6 +29,7 @@ import java.util.Set; * System#getProperties()} or {@link System#getenv()}. * * @author Arjen Poutsma + * @author Chris Beams * @since 3.0 */ abstract class ReadOnlySystemAttributesMap implements Map { @@ -42,7 +44,25 @@ abstract class ReadOnlySystemAttributesMap implements Map { return getSystemAttribute(attributeName); } else { - return null; + // TODO SPR-7508: technically breaks backward-compat. Used to return null + // for non-string keys, now throws. Any callers who have coded to this + // behavior will now break. It's highly unlikely, however; could be + // a calculated risk to take. Throwing is a better choice, as returning + // null represents a 'false negative' - it's not actually that the key + // isn't present, it's simply that you cannot access it through the current + // abstraction. Remember, this case would only come up if (a) there are + // non-string keys or values in system properties, (b) there is a + // SecurityManager present, and (c) the user attempts to access one + // of those properties through this abstraction. This combination is + // probably unlikely enough to merit the change. + // + // note also that the previous implementation didn't consider the + // possibility of non-string values the anonymous implementation used + // for System properties access now does. + // + // See AbstractEnvironment for relevant anonymous implementations + // See DefaultEnvironmentTests for unit tests around these cases + throw new IllegalStateException("TODO SPR-7508: message"); } } diff --git a/org.springframework.core/src/main/java/org/springframework/core/io/ResourceEditor.java b/org.springframework.core/src/main/java/org/springframework/core/io/ResourceEditor.java index 710a4fb275e..6146040cc0c 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/io/ResourceEditor.java +++ b/org.springframework.core/src/main/java/org/springframework/core/io/ResourceEditor.java @@ -19,9 +19,11 @@ package org.springframework.core.io; import java.beans.PropertyEditorSupport; import java.io.IOException; +import org.springframework.core.env.DefaultEnvironment; +import org.springframework.core.env.Environment; import org.springframework.util.Assert; import org.springframework.util.StringUtils; -import org.springframework.util.SystemPropertyUtils; + /** * {@link java.beans.PropertyEditor Editor} for {@link Resource} @@ -30,24 +32,26 @@ import org.springframework.util.SystemPropertyUtils; * "classpath:myfile.txt") to Resource * properties instead of using a String location property. * - *

The path may contain ${...} placeholders, - * to be resolved as system properties: e.g. ${user.dir}. - * Unresolvable placeholder are ignored by default. + *

The path may contain ${...} placeholders, to be + * resolved as {@link Environment} properties: e.g. ${user.dir}. + * Unresolvable placeholders are ignored by default. * *

Delegates to a {@link ResourceLoader} to do the heavy lifting, * by default using a {@link DefaultResourceLoader}. * * @author Juergen Hoeller * @author Dave Syer + * @author Chris Beams * @since 28.12.2003 * @see Resource * @see ResourceLoader * @see DefaultResourceLoader - * @see org.springframework.util.SystemPropertyUtils#resolvePlaceholders - * @see System#getProperty(String) + * @see org.springframework.env.Environment#resolvePlaceholders */ public class ResourceEditor extends PropertyEditorSupport { + private final Environment environment; + private final ResourceLoader resourceLoader; private final boolean ignoreUnresolvablePlaceholders; @@ -55,31 +59,60 @@ public class ResourceEditor extends PropertyEditorSupport { /** * Create a new instance of the {@link ResourceEditor} class - * using a {@link DefaultResourceLoader}. + * using a {@link DefaultResourceLoader} and {@link DefaultEnvironment}. */ public ResourceEditor() { - this(new DefaultResourceLoader()); + this(new DefaultResourceLoader(), new DefaultEnvironment()); } /** * Create a new instance of the {@link ResourceEditor} class - * using the given {@link ResourceLoader}. + * using the given {@link ResourceLoader} and a {@link DefaultEnvironment}. + * @param resourceLoader the ResourceLoader to use + * @deprecated as of Spring 3.1 in favor of + * {@link #ResourceEditor(ResourceLoader, Environment)} + */ + @Deprecated + public ResourceEditor(ResourceLoader resourceLoader) { + this(resourceLoader, new DefaultEnvironment(), true); + } + + /** + * Create a new instance of the {@link ResourceEditor} class + * using the given {@link ResourceLoader} and {@link Environment}. * @param resourceLoader the ResourceLoader to use */ - public ResourceEditor(ResourceLoader resourceLoader) { - this(resourceLoader, true); + public ResourceEditor(ResourceLoader resourceLoader, Environment environment) { + this(resourceLoader, environment, true); } /** * Create a new instance of the {@link ResourceEditor} class - * using the given {@link ResourceLoader}. + * using the given {@link ResourceLoader} and a {@link DefaultEnvironment}. * @param resourceLoader the ResourceLoader to use * @param ignoreUnresolvablePlaceholders whether to ignore unresolvable placeholders - * if no corresponding system property could be found + * if no corresponding property could be found in the DefaultEnvironment + * @deprecated as of Spring 3.1 in favor of + * {@link #ResourceEditor(ResourceLoader, Environment, boolean)} */ + @Deprecated public ResourceEditor(ResourceLoader resourceLoader, boolean ignoreUnresolvablePlaceholders) { + this(resourceLoader, new DefaultEnvironment(), ignoreUnresolvablePlaceholders); + } + + /** + * Create a new instance of the {@link ResourceEditor} class + * using the given {@link ResourceLoader}. + * @param resourceLoader the ResourceLoader to use + * @param environment the Environment to use + * @param ignoreUnresolvablePlaceholders whether to ignore unresolvable placeholders + * if no corresponding property could be found in the given environment + */ + public ResourceEditor(ResourceLoader resourceLoader, Environment environment, boolean ignoreUnresolvablePlaceholders) { Assert.notNull(resourceLoader, "ResourceLoader must not be null"); + Assert.notNull(environment, "Environment must not be null"); this.resourceLoader = resourceLoader; + this.environment = environment; this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders; } @@ -96,14 +129,17 @@ public class ResourceEditor extends PropertyEditorSupport { } /** - * Resolve the given path, replacing placeholders with - * corresponding system property values if necessary. + * Resolve the given path, replacing placeholders with corresponding + * property values from the environment if necessary. * @param path the original file path * @return the resolved file path - * @see org.springframework.util.SystemPropertyUtils#resolvePlaceholders + * @see Environment#resolvePlaceholders + * @see Environment#resolveRequiredPlaceholders */ protected String resolvePath(String path) { - return SystemPropertyUtils.resolvePlaceholders(path, this.ignoreUnresolvablePlaceholders); + return this.ignoreUnresolvablePlaceholders ? + environment.resolvePlaceholders(path) : + environment.resolveRequiredPlaceholders(path); } diff --git a/org.springframework.core/src/main/java/org/springframework/core/io/support/PropertiesLoaderSupport.java b/org.springframework.core/src/main/java/org/springframework/core/io/support/PropertiesLoaderSupport.java index 65f80cec55c..e9289eed593 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/io/support/PropertiesLoaderSupport.java +++ b/org.springframework.core/src/main/java/org/springframework/core/io/support/PropertiesLoaderSupport.java @@ -23,7 +23,6 @@ import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.core.io.Resource; import org.springframework.util.CollectionUtils; import org.springframework.util.DefaultPropertiesPersister; @@ -45,12 +44,12 @@ public abstract class PropertiesLoaderSupport { /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); - private Properties[] localProperties; + protected Properties[] localProperties; + + protected boolean localOverride = false; private Resource[] locations; - private boolean localOverride = false; - private boolean ignoreResourceNotFound = false; private String fileEncoding; diff --git a/org.springframework.core/src/main/java/org/springframework/core/io/support/ResourceArrayPropertyEditor.java b/org.springframework.core/src/main/java/org/springframework/core/io/support/ResourceArrayPropertyEditor.java index 8e7ca5782fd..89cb3786011 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/io/support/ResourceArrayPropertyEditor.java +++ b/org.springframework.core/src/main/java/org/springframework/core/io/support/ResourceArrayPropertyEditor.java @@ -25,9 +25,9 @@ import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - +import org.springframework.core.env.DefaultEnvironment; +import org.springframework.core.env.Environment; import org.springframework.core.io.Resource; -import org.springframework.util.SystemPropertyUtils; /** * Editor for {@link org.springframework.core.io.Resource} arrays, to @@ -44,17 +44,19 @@ import org.springframework.util.SystemPropertyUtils; * by default using a {@link PathMatchingResourcePatternResolver}. * * @author Juergen Hoeller + * @author Chris Beams * @since 1.1.2 * @see org.springframework.core.io.Resource * @see ResourcePatternResolver * @see PathMatchingResourcePatternResolver - * @see org.springframework.util.SystemPropertyUtils#resolvePlaceholders - * @see System#getProperty(String) + * @see org.springframework.env.Environment#resolvePlaceholders */ public class ResourceArrayPropertyEditor extends PropertyEditorSupport { private static final Log logger = LogFactory.getLog(ResourceArrayPropertyEditor.class); + private final Environment environment; + private final ResourcePatternResolver resourcePatternResolver; private final boolean ignoreUnresolvablePlaceholders; @@ -62,29 +64,59 @@ public class ResourceArrayPropertyEditor extends PropertyEditorSupport { /** * Create a new ResourceArrayPropertyEditor with a default - * PathMatchingResourcePatternResolver. + * {@link PathMatchingResourcePatternResolver} and {@link DefaultEnvironment}. * @see PathMatchingResourcePatternResolver + * @see Environment */ public ResourceArrayPropertyEditor() { - this(new PathMatchingResourcePatternResolver()); + this(new PathMatchingResourcePatternResolver(), new DefaultEnvironment(), true); } /** - * Create a new ResourceArrayPropertyEditor with the given ResourcePatternResolver. + * Create a new ResourceArrayPropertyEditor with the given {@link ResourcePatternResolver} + * and a {@link DefaultEnvironment}. * @param resourcePatternResolver the ResourcePatternResolver to use + * @deprecated as of 3.1 in favor of {@link #ResourceArrayPropertyEditor(ResourcePatternResolver, Environment)} */ + @Deprecated public ResourceArrayPropertyEditor(ResourcePatternResolver resourcePatternResolver) { - this(resourcePatternResolver, true); + this(resourcePatternResolver, new DefaultEnvironment(), true); } /** - * Create a new ResourceArrayPropertyEditor with the given ResourcePatternResolver. + * Create a new ResourceArrayPropertyEditor with the given {@link ResourcePatternResolver} + * and {@link Environment}. + * @param resourcePatternResolver the ResourcePatternResolver to use + * @param environment the Environment to use + */ + public ResourceArrayPropertyEditor(ResourcePatternResolver resourcePatternResolver, Environment environment) { + this(resourcePatternResolver, environment, true); + } + + /** + * Create a new ResourceArrayPropertyEditor with the given {@link ResourcePatternResolver} + * and a {@link DefaultEnvironment}. * @param resourcePatternResolver the ResourcePatternResolver to use * @param ignoreUnresolvablePlaceholders whether to ignore unresolvable placeholders * if no corresponding system property could be found + * @deprecated as of 3.1 in favor of {@link #ResourceArrayPropertyEditor(ResourcePatternResolver, Environment, boolean)} */ + @Deprecated public ResourceArrayPropertyEditor(ResourcePatternResolver resourcePatternResolver, boolean ignoreUnresolvablePlaceholders) { + this(resourcePatternResolver, new DefaultEnvironment(), ignoreUnresolvablePlaceholders); + } + + /** + * Create a new ResourceArrayPropertyEditor with the given {@link ResourcePatternResolver} + * and {@link Environment}. + * @param resourcePatternResolver the ResourcePatternResolver to use + * @param environment the Environment to use + * @param ignoreUnresolvablePlaceholders whether to ignore unresolvable placeholders + * if no corresponding system property could be found + */ + public ResourceArrayPropertyEditor(ResourcePatternResolver resourcePatternResolver, Environment environment, boolean ignoreUnresolvablePlaceholders) { this.resourcePatternResolver = resourcePatternResolver; + this.environment = environment; this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders; } @@ -160,10 +192,13 @@ public class ResourceArrayPropertyEditor extends PropertyEditorSupport { * corresponding system property values if necessary. * @param path the original file path * @return the resolved file path - * @see org.springframework.util.SystemPropertyUtils#resolvePlaceholders + * @see Environment#resolvePlaceholders + * @see Environment#resolveRequiredPlaceholders */ protected String resolvePath(String path) { - return SystemPropertyUtils.resolvePlaceholders(path, this.ignoreUnresolvablePlaceholders); + return this.ignoreUnresolvablePlaceholders ? + environment.resolvePlaceholders(path) : + environment.resolveRequiredPlaceholders(path); } } diff --git a/org.springframework.core/src/main/java/org/springframework/util/SystemPropertyUtils.java b/org.springframework.core/src/main/java/org/springframework/util/SystemPropertyUtils.java index 6e8eaff2f13..8fbcda5510f 100644 --- a/org.springframework.core/src/main/java/org/springframework/util/SystemPropertyUtils.java +++ b/org.springframework.core/src/main/java/org/springframework/util/SystemPropertyUtils.java @@ -25,6 +25,12 @@ import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver; * ${user.dir}. Default values can be supplied using the ":" separator between key * and value. * + * TODO SPR-7508: review item - nearly all uses of {@link SystemPropertyUtils#resolvePlaceholders(String)} + * have been replaced by Environment#resolvePlaceholder(), however, there are several locations in the + * framework that cannot be so refactored as referring to Environment would introduce a cycle. Case in point + * Log4JConfigurer and Log4JWebConfigurer. Need to unify this functionality one way or another. It's + * currently pure duplication. + * * @author Juergen Hoeller * @author Rob Harrop * @author Dave Syer diff --git a/org.springframework.core/src/test/java/org/springframework/core/env/CustomEnvironmentTests.java b/org.springframework.core/src/test/java/org/springframework/core/env/CustomEnvironmentTests.java new file mode 100644 index 00000000000..f8f8160e73f --- /dev/null +++ b/org.springframework.core/src/test/java/org/springframework/core/env/CustomEnvironmentTests.java @@ -0,0 +1,75 @@ +package org.springframework.core.env; + +import org.junit.Ignore; +import org.junit.Test; + + +/** + * Unit tests covering the extensibility of AbstractEnvironment + * + * @author Chris Beams + * @since 3.1 + */ +public class CustomEnvironmentTests { + + @Ignore + @Test + public void noop() { + } + /* + @Retention(RetentionPolicy.RUNTIME) + public + static @interface MyEnvironment { } + + /** + * A custom {@link Environment} that evaluates class literals + * for the presence of a custom annotation. + * / + static class CustomEnvironment extends AbstractEnvironment { + @Override + public boolean accepts(Object object) { + if (object instanceof Class) { + return ((Class)object).isAnnotationPresent(MyEnvironment.class); + } + return super.accepts(object); + } + } + + @MyEnvironment + static class CandidateWithCustomAnnotation { } + + static class CandidateWithoutCustomAnnotation { } + + @Test + public void subclassOfAbstractEnvironment() { + ConfigurableEnvironment env = new CustomEnvironment(); + env.setActiveProfiles("test"); + assertThat(env.accepts(CandidateWithCustomAnnotation.class), is(true)); + assertThat(env.accepts(CandidateWithoutCustomAnnotation.class), is(false)); + assertThat(env.accepts("test"), is(true)); // AbstractEnvironment always returns true + assertThat(env.accepts(new Object()), is(true)); // AbstractEnvironment always returns true + } + + static class CustomDefaultEnvironment extends DefaultEnvironment { + @Override + public boolean accepts(Object object) { + if (object instanceof Class) { + return ((Class)object).isAnnotationPresent(MyEnvironment.class); + } + return super.accepts(object); + } + } + + @Test + public void subclassOfDefaultEnvironment() { + ConfigurableEnvironment env = new CustomDefaultEnvironment(); + env.setActiveProfiles("test"); + assertThat(env.accepts(CandidateWithCustomAnnotation.class), is(true)); + assertThat(env.accepts(CandidateWithoutCustomAnnotation.class), is(false)); + assertThat(env.accepts("test"), is(true)); // delegates to DefaultEnvironment + assertThat(env.accepts("bogus"), is(false)); // delegates to DefaultEnvironment + assertThat(env.accepts(new Object()), is(false)); // delegates to DefaultEnvironment + } + */ + +} diff --git a/org.springframework.core/src/test/java/org/springframework/core/env/DefaultEnvironmentTests.java b/org.springframework.core/src/test/java/org/springframework/core/env/DefaultEnvironmentTests.java new file mode 100644 index 00000000000..f912291e62e --- /dev/null +++ b/org.springframework.core/src/test/java/org/springframework/core/env/DefaultEnvironmentTests.java @@ -0,0 +1,452 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.env; + +import static java.lang.String.format; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.junit.matchers.JUnitMatchers.hasItem; +import static org.junit.matchers.JUnitMatchers.hasItems; +import static org.springframework.core.env.AbstractEnvironment.SPRING_PROFILES_PROPERTY_NAME; +import static org.springframework.core.env.DefaultEnvironmentTests.CollectionMatchers.isEmpty; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.security.AccessControlException; +import java.security.Permission; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.junit.Before; +import org.junit.Test; +import org.junit.internal.matchers.TypeSafeMatcher; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; + +/** + * Unit tests for {@link DefaultEnvironment}. + * + * @author Chris Beams + */ +public class DefaultEnvironmentTests { + + private static final String ALLOWED_PROPERTY_NAME = "theanswer"; + private static final String ALLOWED_PROPERTY_VALUE = "42"; + + private static final String DISALLOWED_PROPERTY_NAME = "verboten"; + private static final String DISALLOWED_PROPERTY_VALUE = "secret"; + + private static final String STRING_PROPERTY_NAME = "stringPropName"; + private static final String STRING_PROPERTY_VALUE = "stringPropValue"; + private static final Object NON_STRING_PROPERTY_NAME = new Object(); + private static final Object NON_STRING_PROPERTY_VALUE = new Object(); + + private ConfigurableEnvironment environment; + private Properties testProperties; + + @Before + public void setUp() { + environment = new DefaultEnvironment(); + testProperties = new Properties(); + environment.addPropertySource("testProperties", testProperties); + } + + @Test @SuppressWarnings({ "unchecked", "rawtypes", "serial" }) + public void getPropertySources_manipulatePropertySourceOrder() { + AbstractEnvironment env = new AbstractEnvironment() { }; + env.addPropertySource("system", new HashMap() {{ put("foo", "systemValue"); }}); + env.addPropertySource("local", new HashMap() {{ put("foo", "localValue"); }}); + + // 'local' was added (pushed) last so has precedence + assertThat(env.getProperty("foo"), equalTo("localValue")); + + // put 'system' at the front of the list + LinkedList> propertySources = env.getPropertySources(); + propertySources.push(propertySources.remove(propertySources.indexOf(PropertySource.named("system")))); + + // 'system' now has precedence + assertThat(env.getProperty("foo"), equalTo("systemValue")); + + assertThat(propertySources.size(), is(2)); + } + + @Test @SuppressWarnings({ "unchecked", "rawtypes", "serial" }) + public void getPropertySources_replacePropertySource() { + AbstractEnvironment env = new AbstractEnvironment() { }; + env.addPropertySource("system", new HashMap() {{ put("foo", "systemValue"); }}); + env.addPropertySource("local", new HashMap() {{ put("foo", "localValue"); }}); + + // 'local' was added (pushed) last so has precedence + assertThat(env.getProperty("foo"), equalTo("localValue")); + + // replace 'local' with new property source + LinkedList> propertySources = env.getPropertySources(); + int localIndex = propertySources.indexOf(PropertySource.named("local")); + MapPropertySource newSource = new MapPropertySource("new", new HashMap() {{ put("foo", "newValue"); }}); + propertySources.set(localIndex, newSource); + + // 'system' now has precedence + assertThat(env.getProperty("foo"), equalTo("newValue")); + + assertThat(propertySources.size(), is(2)); + } + + @Test + public void getProperty() { + assertThat(environment.getProperty("foo"), nullValue()); + testProperties.put("foo", "bar"); + assertThat(environment.getProperty("foo"), is("bar")); + } + + @Test + public void getProperty_withExplicitNullValue() { + // java.util.Properties does not allow null values (because Hashtable does not) + Map nullableProperties = new HashMap(); + environment.addPropertySource("nullableProperties", nullableProperties); + nullableProperties.put("foo", null); + assertThat(environment.getProperty("foo"), nullValue()); + } + + @Test + public void getProperty_withStringArrayConversion() { + testProperties.put("foo", "bar,baz"); + assertThat(environment.getProperty("foo", String[].class), equalTo(new String[] { "bar", "baz" })); + } + + @Test + public void getProperty_withNonConvertibleTargetType() { + testProperties.put("foo", "bar"); + + class TestType { } + + try { + environment.getProperty("foo", TestType.class); + fail("Expected IllegalArgumentException due to non-convertible types"); + } catch (IllegalArgumentException ex) { + // expected + } + } + + @Test + public void getRequiredProperty() { + testProperties.put("exists", "xyz"); + assertThat(environment.getRequiredProperty("exists"), is("xyz")); + + try { + environment.getRequiredProperty("bogus"); + fail("expected IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected + } + } + + @Test + public void getRequiredProperty_withStringArrayConversion() { + testProperties.put("exists", "abc,123"); + assertThat(environment.getRequiredProperty("exists", String[].class), equalTo(new String[] { "abc", "123" })); + + try { + environment.getRequiredProperty("bogus", String[].class); + fail("expected IllegalArgumentException"); + } catch (IllegalArgumentException ex) { + // expected + } + } + + @Test @SuppressWarnings({ "rawtypes", "serial", "unchecked" }) + public void asProperties() { + ConfigurableEnvironment env = new AbstractEnvironment() { }; + assertThat(env.asProperties(), notNullValue()); + + env.addPropertySource("lowestPrecedence", new HashMap() {{ put("common", "lowCommon"); put("lowKey", "lowVal"); }}); + env.addPropertySource("middlePrecedence", new HashMap() {{ put("common", "midCommon"); put("midKey", "midVal"); }}); + env.addPropertySource("highestPrecedence", new HashMap() {{ put("common", "highCommon"); put("highKey", "highVal"); }}); + + Properties props = env.asProperties(); + assertThat(props.getProperty("common"), is("highCommon")); + assertThat(props.getProperty("lowKey"), is("lowVal")); + assertThat(props.getProperty("midKey"), is("midVal")); + assertThat(props.getProperty("highKey"), is("highVal")); + assertThat(props.size(), is(4)); + } + + @Test + public void activeProfiles() { + assertThat(environment.getActiveProfiles(), isEmpty()); + environment.setActiveProfiles("local", "embedded"); + Set activeProfiles = environment.getActiveProfiles(); + assertThat(activeProfiles, hasItems("local", "embedded")); + assertThat(activeProfiles.size(), is(2)); + try { + environment.getActiveProfiles().add("bogus"); + fail("activeProfiles should be unmodifiable"); + } catch (UnsupportedOperationException ex) { + // expected + } + environment.setActiveProfiles("foo"); + assertThat(activeProfiles, hasItem("foo")); + assertThat(environment.getActiveProfiles().size(), is(1)); + } + + @Test + public void systemPropertiesEmpty() { + assertThat(environment.getActiveProfiles(), isEmpty()); + + System.setProperty(SPRING_PROFILES_PROPERTY_NAME, ""); + assertThat(environment.getActiveProfiles(), isEmpty()); + + System.getProperties().remove(SPRING_PROFILES_PROPERTY_NAME); + } + + @Test + public void systemPropertiesResoloutionOfProfiles() { + assertThat(environment.getActiveProfiles(), isEmpty()); + + System.setProperty(SPRING_PROFILES_PROPERTY_NAME, "foo"); + assertThat(environment.getActiveProfiles(), hasItem("foo")); + + // clean up + System.getProperties().remove(SPRING_PROFILES_PROPERTY_NAME); + } + + @Test + public void systemPropertiesResoloutionOfMultipleProfiles() { + assertThat(environment.getActiveProfiles(), isEmpty()); + + System.setProperty(SPRING_PROFILES_PROPERTY_NAME, "foo,bar"); + assertThat(environment.getActiveProfiles(), hasItems("foo", "bar")); + + System.setProperty(SPRING_PROFILES_PROPERTY_NAME, " bar , baz "); // notice whitespace + assertThat(environment.getActiveProfiles(), not(hasItems("foo", "bar"))); + assertThat(environment.getActiveProfiles(), hasItems("bar", "baz")); + + System.getProperties().remove(SPRING_PROFILES_PROPERTY_NAME); + } + + /* + static class WithNoProfile { } + @Profile("test") + static class WithTestProfile { } + + @Test + public void accepts() throws IOException { + + assertThat(environment.accepts(metadataForClass(WithNoProfile.class)), is(true)); + assertThat(environment.accepts(metadataForClass(WithTestProfile.class)), is(false)); + assertThat(environment.accepts("foo,bar"), is(false)); + assertThat(environment.accepts("test"), is(false)); + assertThat(environment.accepts("test,foo"), is(false)); + + environment.setActiveProfiles("test"); + assertThat(environment.accepts(metadataForClass(WithNoProfile.class)), is(true)); + assertThat(environment.accepts(metadataForClass(WithTestProfile.class)), is(true)); + assertThat(environment.accepts("foo,bar"), is(false)); + assertThat(environment.accepts("test"), is(true)); + assertThat(environment.accepts("test,foo"), is(true)); + } + */ + + @Test + public void systemPropertiesAccess() { + System.setProperty(ALLOWED_PROPERTY_NAME, ALLOWED_PROPERTY_VALUE); + System.setProperty(DISALLOWED_PROPERTY_NAME, DISALLOWED_PROPERTY_VALUE); + System.getProperties().put(STRING_PROPERTY_NAME, NON_STRING_PROPERTY_VALUE); + System.getProperties().put(NON_STRING_PROPERTY_NAME, STRING_PROPERTY_VALUE); + + { + Map systemProperties = environment.getSystemProperties(); + assertThat(systemProperties, notNullValue()); + assertSame(systemProperties, System.getProperties()); + assertThat(systemProperties.get(ALLOWED_PROPERTY_NAME), equalTo((Object)ALLOWED_PROPERTY_VALUE)); + assertThat(systemProperties.get(DISALLOWED_PROPERTY_NAME), equalTo((Object)DISALLOWED_PROPERTY_VALUE)); + + // non-string keys and values work fine... until the security manager is introduced below + assertThat(systemProperties.get(STRING_PROPERTY_NAME), equalTo(NON_STRING_PROPERTY_VALUE)); + assertThat(systemProperties.get(NON_STRING_PROPERTY_NAME), equalTo((Object)STRING_PROPERTY_VALUE)); + } + + SecurityManager oldSecurityManager = System.getSecurityManager(); + SecurityManager securityManager = new SecurityManager() { + @Override + public void checkPropertiesAccess() { + // see http://download.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#getProperties() + throw new AccessControlException("Accessing the system properties is disallowed"); + } + @Override + public void checkPropertyAccess(String key) { + // see http://download.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#getProperty(java.lang.String) + if (DISALLOWED_PROPERTY_NAME.equals(key)) { + throw new AccessControlException( + format("Accessing the system property [%s] is disallowed", DISALLOWED_PROPERTY_NAME)); + } + } + @Override + public void checkPermission(Permission perm) { + // allow everything else + } + }; + System.setSecurityManager(securityManager); + + { + Map systemProperties = environment.getSystemProperties(); + assertThat(systemProperties, notNullValue()); + assertThat(systemProperties, instanceOf(ReadOnlySystemAttributesMap.class)); + assertThat((String)systemProperties.get(ALLOWED_PROPERTY_NAME), equalTo(ALLOWED_PROPERTY_VALUE)); + assertThat(systemProperties.get(DISALLOWED_PROPERTY_NAME), equalTo(null)); + + // nothing we can do here in terms of warning the user that there was + // actually a (non-string) value available. By this point, we only + // have access to calling System.getProperty(), which itself returns null + // if the value is non-string. So we're stuck with returning a potentially + // misleading null. + assertThat(systemProperties.get(STRING_PROPERTY_NAME), nullValue()); + + // in the case of a non-string *key*, however, we can do better. Alert + // the user that under these very special conditions (non-object key + + // SecurityManager that disallows access to system properties), they + // cannot do what they're attempting. + try { + systemProperties.get(NON_STRING_PROPERTY_NAME); + fail("Expected IllegalStateException when searching with non-string key against ReadOnlySystemAttributesMap"); + } catch (IllegalStateException ex) { + // expected + } + } + + System.setSecurityManager(oldSecurityManager); + System.clearProperty(ALLOWED_PROPERTY_NAME); + System.clearProperty(DISALLOWED_PROPERTY_NAME); + System.getProperties().remove(STRING_PROPERTY_NAME); + System.getProperties().remove(NON_STRING_PROPERTY_NAME); + } + + @Test + public void systemEnvironmentAccess() throws Exception { + getModifiableSystemEnvironment().put(ALLOWED_PROPERTY_NAME, ALLOWED_PROPERTY_VALUE); + getModifiableSystemEnvironment().put(DISALLOWED_PROPERTY_NAME, DISALLOWED_PROPERTY_VALUE); + + { + Map systemEnvironment = environment.getSystemEnvironment(); + assertThat(systemEnvironment, notNullValue()); + assertSame(systemEnvironment, System.getenv()); + } + + SecurityManager oldSecurityManager = System.getSecurityManager(); + SecurityManager securityManager = new SecurityManager() { + @Override + public void checkPermission(Permission perm) { + //see http://download.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#getenv() + if ("getenv.*".equals(perm.getName())) { + throw new AccessControlException("Accessing the system environment is disallowed"); + } + //see http://download.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#getenv(java.lang.String) + if (("getenv."+DISALLOWED_PROPERTY_NAME).equals(perm.getName())) { + throw new AccessControlException( + format("Accessing the system environment variable [%s] is disallowed", DISALLOWED_PROPERTY_NAME)); + } + } + }; + System.setSecurityManager(securityManager); + + { + Map systemEnvironment = environment.getSystemEnvironment(); + assertThat(systemEnvironment, notNullValue()); + assertThat(systemEnvironment, instanceOf(ReadOnlySystemAttributesMap.class)); + assertThat(systemEnvironment.get(ALLOWED_PROPERTY_NAME), equalTo(ALLOWED_PROPERTY_VALUE)); + assertThat(systemEnvironment.get(DISALLOWED_PROPERTY_NAME), nullValue()); + } + + System.setSecurityManager(oldSecurityManager); + getModifiableSystemEnvironment().remove(ALLOWED_PROPERTY_NAME); + getModifiableSystemEnvironment().remove(DISALLOWED_PROPERTY_NAME); + } + + @Test + public void resolvePlaceholders() { + AbstractEnvironment env = new AbstractEnvironment() { }; + Properties testProperties = new Properties(); + testProperties.setProperty("foo", "bar"); + env.addPropertySource("testProperties", testProperties); + String resolved = env.resolvePlaceholders("pre-${foo}-${unresolvable}-post"); + assertThat(resolved, is("pre-bar-${unresolvable}-post")); + } + + @Test + public void resolveRequiredPlaceholders() { + AbstractEnvironment env = new AbstractEnvironment() { }; + Properties testProperties = new Properties(); + testProperties.setProperty("foo", "bar"); + env.addPropertySource("testProperties", testProperties); + try { + env.resolveRequiredPlaceholders("pre-${foo}-${unresolvable}-post"); + fail("expected exception"); + } catch (IllegalArgumentException ex) { + assertThat(ex.getMessage(), is("Could not resolve placeholder 'unresolvable'")); + } + } + + private AnnotationMetadata metadataForClass(Class clazz) throws IOException { + return new SimpleMetadataReaderFactory().getMetadataReader(clazz.getName()).getAnnotationMetadata(); + } + + public static class CollectionMatchers { + public static Matcher> isEmpty() { + + return new TypeSafeMatcher>() { + + @Override + public boolean matchesSafely(Collection collection) { + return collection.isEmpty(); + } + + public void describeTo(Description desc) { + desc.appendText("an empty collection"); + } + }; + } + } + + // TODO SPR-7508: duplicated from EnvironmentPropertyResolutionSearchTests + @SuppressWarnings("unchecked") + private static Map getModifiableSystemEnvironment() throws Exception { + Class[] classes = Collections.class.getDeclaredClasses(); + Map systemEnv = System.getenv(); + for (Class cl : classes) { + if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) { + Field field = cl.getDeclaredField("m"); + field.setAccessible(true); + Object obj = field.get(systemEnv); + return (Map) obj; + } + } + throw new IllegalStateException(); + } +} diff --git a/org.springframework.core/src/test/java/org/springframework/core/env/EnvironmentPropertyResolutionLateBindingTests.java b/org.springframework.core/src/test/java/org/springframework/core/env/EnvironmentPropertyResolutionLateBindingTests.java new file mode 100644 index 00000000000..f307415e26a --- /dev/null +++ b/org.springframework.core/src/test/java/org/springframework/core/env/EnvironmentPropertyResolutionLateBindingTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.env; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +import org.junit.Test; + + +/** + * Test that {@link Environment#getValue} performs late-resolution of property + * values i.e., does not eagerly resolve and cache only at construction time. + * + * @see EnvironmentPropertyResolutionSearchTests + * @author Chris Beams + * @since 3.1 + */ +public class EnvironmentPropertyResolutionLateBindingTests { + @Test + public void replaceExistingKeyPostConstruction() { + String key = "foo"; + String value1 = "bar"; + String value2 = "biz"; + + System.setProperty(key, value1); // before construction + DefaultEnvironment env = new DefaultEnvironment(); + assertThat(env.getProperty(key), equalTo(value1)); + System.setProperty(key, value2); // after construction and first resolution + assertThat(env.getProperty(key), equalTo(value2)); + System.clearProperty(key); // clean up + } + + @Test + public void addNewKeyPostConstruction() { + DefaultEnvironment env = new DefaultEnvironment(); + assertThat(env.getProperty("foo"), equalTo(null)); + System.setProperty("foo", "42"); + assertThat(env.getProperty("foo"), equalTo("42")); + System.clearProperty("foo"); // clean up + } +} diff --git a/org.springframework.core/src/test/java/org/springframework/core/env/EnvironmentPropertyResolutionSearchTests.java b/org.springframework.core/src/test/java/org/springframework/core/env/EnvironmentPropertyResolutionSearchTests.java new file mode 100644 index 00000000000..308da06244c --- /dev/null +++ b/org.springframework.core/src/test/java/org/springframework/core/env/EnvironmentPropertyResolutionSearchTests.java @@ -0,0 +1,102 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.env; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.junit.Test; + +/** + * Unit tests for {@link DefaultEnvironment} proving that it (a) searches + * standard property sources (b) in the correct order. + * + * @see AbstractEnvironment#getProperty(String) + * @author Chris Beams + * @since 3.1 + */ +public class EnvironmentPropertyResolutionSearchTests { + + @Test @SuppressWarnings({ "unchecked", "serial", "rawtypes" }) + public void propertySourcesHaveLIFOSearchOrder() { + ConfigurableEnvironment env = new AbstractEnvironment() { }; + env.addPropertySource("ps1", new HashMap() {{ put("pName", "ps1Value"); }}); + assertThat(env.getProperty("pName"), equalTo("ps1Value")); + env.addPropertySource("ps2", new HashMap() {{ put("pName", "ps2Value"); }}); + assertThat(env.getProperty("pName"), equalTo("ps2Value")); + env.addPropertySource("ps3", new HashMap() {{ put("pName", "ps3Value"); }}); + assertThat(env.getProperty("pName"), equalTo("ps3Value")); + } + + @Test + public void resolveFromDefaultPropertySources() throws Exception { + String key = "x"; + String localPropsValue = "local"; + String sysPropsValue = "sys"; + String envVarsValue = "env"; + + Map systemEnvironment = getModifiableSystemEnvironment(); + Properties systemProperties = System.getProperties(); + Properties localProperties = new Properties(); + + DefaultEnvironment env = new DefaultEnvironment(); + env.addPropertySource("localProperties", localProperties); + + // set all properties + systemEnvironment.put(key, envVarsValue); + systemProperties.setProperty(key, sysPropsValue); + localProperties.setProperty(key, localPropsValue); + + // local properties should have highest resolution precedence + assertThat(env.getProperty(key), equalTo(localPropsValue)); + + // system properties should be next in line + localProperties.remove(key); + assertThat(env.getProperty(key), equalTo(sysPropsValue)); + + // system environment variables should be final fallback + systemProperties.remove(key); + assertThat(env.getProperty(key), equalTo(envVarsValue)); + + // with no propertysource containing the key in question, should return null + systemEnvironment.remove(key); + assertThat(env.getProperty(key), equalTo(null)); + } + + @SuppressWarnings("unchecked") + private static Map getModifiableSystemEnvironment() throws Exception { + Class[] classes = Collections.class.getDeclaredClasses(); + Map env = System.getenv(); + for (Class cl : classes) { + if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) { + Field field = cl.getDeclaredField("m"); + field.setAccessible(true); + Object obj = field.get(env); + return (Map) obj; + } + } + throw new IllegalStateException(); + } + +} diff --git a/org.springframework.core/src/test/java/org/springframework/core/env/PropertySourceTests.java b/org.springframework.core/src/test/java/org/springframework/core/env/PropertySourceTests.java new file mode 100644 index 00000000000..5877ad4bd9f --- /dev/null +++ b/org.springframework.core/src/test/java/org/springframework/core/env/PropertySourceTests.java @@ -0,0 +1,120 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.env; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Properties; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.junit.Test; + +/** + * Unit tests for {@link AbstractPropertySource} implementations. + * + * @author Chris Beams + * @since 3.1 + */ +public class PropertySourceTests { + @Test @SuppressWarnings("serial") + public void equals() { + Map map1 = new HashMap() {{ put("a", "b"); }}; + Map map2 = new HashMap() {{ put("c", "d"); }}; + Properties props1 = new Properties() {{ setProperty("a", "b"); }}; + Properties props2 = new Properties() {{ setProperty("c", "d"); }}; + + MapPropertySource mps = new MapPropertySource("mps", map1); + assertThat(mps, equalTo(mps)); + + assertThat(new MapPropertySource("x", map1).equals(new MapPropertySource("x", map1)), is(true)); + assertThat(new MapPropertySource("x", map1).equals(new MapPropertySource("x", map2)), is(true)); + assertThat(new MapPropertySource("x", map1).equals(new PropertiesPropertySource("x", props1)), is(true)); + assertThat(new MapPropertySource("x", map1).equals(new PropertiesPropertySource("x", props2)), is(true)); + + assertThat(new MapPropertySource("x", map1).equals(new Object()), is(false)); + assertThat(new MapPropertySource("x", map1).equals("x"), is(false)); + assertThat(new MapPropertySource("x", map1).equals(new MapPropertySource("y", map1)), is(false)); + assertThat(new MapPropertySource("x", map1).equals(new MapPropertySource("y", map2)), is(false)); + assertThat(new MapPropertySource("x", map1).equals(new PropertiesPropertySource("y", props1)), is(false)); + assertThat(new MapPropertySource("x", map1).equals(new PropertiesPropertySource("y", props2)), is(false)); + } + + @Test @SuppressWarnings("serial") + public void collectionsOperations() { + Map map1 = new HashMap() {{ put("a", "b"); }}; + Map map2 = new HashMap() {{ put("c", "d"); }}; + + PropertySource ps1 = new MapPropertySource("ps1", map1); + ps1.getSource(); + LinkedList> propertySources = new LinkedList>(); + assertThat(propertySources.add(ps1), equalTo(true)); + assertThat(propertySources.contains(ps1), is(true)); + assertThat(propertySources.contains(PropertySource.named("ps1")), is(true)); + + // TODO SPR-7508: consider disallowing duplicates somehow (in the actual data structure used by environment) + PropertySource ps1replacement = new MapPropertySource("ps1", map2); // notice - different map + assertThat(propertySources.add(ps1replacement), is(true)); // true because linkedlist allows duplicates + assertThat(propertySources.size(), is(2)); + assertThat(propertySources.remove(PropertySource.named("ps1")), is(true)); + assertThat(propertySources.size(), is(1)); + assertThat(propertySources.remove(PropertySource.named("ps1")), is(true)); + assertThat(propertySources.size(), is(0)); + + PropertySource ps2 = new MapPropertySource("ps2", map2); + propertySources.add(ps1); + propertySources.add(ps2); + assertThat(propertySources.indexOf(PropertySource.named("ps1")), is(0)); + assertThat(propertySources.indexOf(PropertySource.named("ps2")), is(1)); + propertySources.clear(); + } + + @Test @SuppressWarnings("serial") + public void toString_verbosityVariesOnLogLevel() { + String name = "props"; + Map map = new HashMap() {{ put("k1", "v1"); }}; + MapPropertySource ps = new MapPropertySource(name, map); + Logger logger = Logger.getLogger(ps.getClass()); + Level original = logger.getLevel(); + + try { + logger.setLevel(Level.DEBUG); + assertThat("PropertySource.toString() should render verbose output for log levels <= DEBUG", + ps.toString(), + equalTo(String.format("%s@%s [name='%s', properties=%s]", + ps.getClass().getSimpleName(), + System.identityHashCode(ps), + name, + map))); + + logger.setLevel(Level.INFO); + assertThat("PropertySource.toString() should render concise output for log levels >= INFO", + ps.toString(), + equalTo(String.format("%s [name='%s', propertyCount=%d]", + ps.getClass().getSimpleName(), + name, + map.size()))); + } finally { + logger.setLevel(original); + } + } +} diff --git a/org.springframework.core/src/test/java/org/springframework/core/io/ResourceEditorTests.java b/org.springframework.core/src/test/java/org/springframework/core/io/ResourceEditorTests.java index 792115e643e..6558875c1fd 100644 --- a/org.springframework.core/src/test/java/org/springframework/core/io/ResourceEditorTests.java +++ b/org.springframework.core/src/test/java/org/springframework/core/io/ResourceEditorTests.java @@ -20,6 +20,7 @@ import java.beans.PropertyEditor; import static org.junit.Assert.*; import org.junit.Test; +import org.springframework.core.env.DefaultEnvironment; /** * Unit tests for the {@link ResourceEditor} class. @@ -40,8 +41,8 @@ public final class ResourceEditorTests { } @Test(expected = IllegalArgumentException.class) - public void ctorWithNullResourceLoader() throws Exception { - new ResourceEditor(null); + public void ctorWithNullCtorArgs() throws Exception { + new ResourceEditor(null, null); } @Test @@ -74,7 +75,7 @@ public final class ResourceEditorTests { @Test(expected=IllegalArgumentException.class) public void testStrictSystemPropertyReplacement() { - PropertyEditor editor = new ResourceEditor(new DefaultResourceLoader(), false); + PropertyEditor editor = new ResourceEditor(new DefaultResourceLoader(), new DefaultEnvironment(), false); System.setProperty("test.prop", "foo"); try { editor.setAsText("${test.prop}-${bar}"); diff --git a/org.springframework.expression/pom.xml b/org.springframework.expression/pom.xml index be9165cdd69..1ac99341d02 100644 --- a/org.springframework.expression/pom.xml +++ b/org.springframework.expression/pom.xml @@ -4,12 +4,12 @@ org.springframework spring-expression jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.instrument.tomcat/.settings/org.eclipse.jdt.core.prefs b/org.springframework.instrument.tomcat/.settings/org.eclipse.jdt.core.prefs index a15f738edcd..4655eeb423f 100644 --- a/org.springframework.instrument.tomcat/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.instrument.tomcat/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ #Wed Jul 15 00:01:30 PDT 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/org.springframework.instrument.tomcat/pom.xml b/org.springframework.instrument.tomcat/pom.xml index f4425b63fb5..bf94631dfbc 100644 --- a/org.springframework.instrument.tomcat/pom.xml +++ b/org.springframework.instrument.tomcat/pom.xml @@ -4,12 +4,12 @@ org.springframework spring-instrument-tomcat jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.instrument/.settings/org.eclipse.jdt.core.prefs b/org.springframework.instrument/.settings/org.eclipse.jdt.core.prefs index 0e29d554498..7a583ba283d 100644 --- a/org.springframework.instrument/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.instrument/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ #Wed Jul 15 00:01:31 PDT 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/org.springframework.instrument/pom.xml b/org.springframework.instrument/pom.xml index 0431aa599dc..c7b4d47fe8c 100644 --- a/org.springframework.instrument/pom.xml +++ b/org.springframework.instrument/pom.xml @@ -4,12 +4,12 @@ org.springframework spring-instrument jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.integration-tests/.classpath b/org.springframework.integration-tests/.classpath index 9be354aa269..23691001718 100644 --- a/org.springframework.integration-tests/.classpath +++ b/org.springframework.integration-tests/.classpath @@ -84,6 +84,7 @@ + diff --git a/org.springframework.integration-tests/.project b/org.springframework.integration-tests/.project index e09fe3e7d83..d10e4a930f7 100644 --- a/org.springframework.integration-tests/.project +++ b/org.springframework.integration-tests/.project @@ -10,8 +10,14 @@ + + org.springframework.ide.eclipse.core.springbuilder + + + + org.springframework.ide.eclipse.core.springnature org.eclipse.jdt.core.javanature diff --git a/org.springframework.integration-tests/.settings/org.eclipse.jdt.core.prefs b/org.springframework.integration-tests/.settings/org.eclipse.jdt.core.prefs index a15f738edcd..4655eeb423f 100644 --- a/org.springframework.integration-tests/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.integration-tests/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ #Wed Jul 15 00:01:30 PDT 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/org.springframework.integration-tests/integration-tests.iml b/org.springframework.integration-tests/integration-tests.iml index d615db5f0e9..13421323256 100644 --- a/org.springframework.integration-tests/integration-tests.iml +++ b/org.springframework.integration-tests/integration-tests.iml @@ -28,6 +28,7 @@ + diff --git a/org.springframework.integration-tests/ivy.xml b/org.springframework.integration-tests/ivy.xml index fc5be79b019..28be250ce21 100644 --- a/org.springframework.integration-tests/ivy.xml +++ b/org.springframework.integration-tests/ivy.xml @@ -95,6 +95,7 @@ + diff --git a/org.springframework.integration-tests/pom.xml b/org.springframework.integration-tests/pom.xml index 007f340aa30..9e6dc336182 100644 --- a/org.springframework.integration-tests/pom.xml +++ b/org.springframework.integration-tests/pom.xml @@ -4,12 +4,12 @@ org.springframework spring-integration-tests jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.integration-tests/src/main/java/.gitignore b/org.springframework.integration-tests/src/main/java/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/org.springframework.integration-tests/src/test/java/.gitignore b/org.springframework.integration-tests/src/test/java/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/org.springframework.integration-tests/src/test/java/org/springframework/core/env/EnvironmentIntegrationTests-context-dev.xml b/org.springframework.integration-tests/src/test/java/org/springframework/core/env/EnvironmentIntegrationTests-context-dev.xml new file mode 100644 index 00000000000..45c18434e72 --- /dev/null +++ b/org.springframework.integration-tests/src/test/java/org/springframework/core/env/EnvironmentIntegrationTests-context-dev.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/org.springframework.integration-tests/src/test/java/org/springframework/core/env/EnvironmentIntegrationTests-context-prod.xml b/org.springframework.integration-tests/src/test/java/org/springframework/core/env/EnvironmentIntegrationTests-context-prod.xml new file mode 100644 index 00000000000..472a09aed76 --- /dev/null +++ b/org.springframework.integration-tests/src/test/java/org/springframework/core/env/EnvironmentIntegrationTests-context-prod.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/org.springframework.integration-tests/src/test/java/org/springframework/core/env/EnvironmentIntegrationTests-context.xml b/org.springframework.integration-tests/src/test/java/org/springframework/core/env/EnvironmentIntegrationTests-context.xml new file mode 100644 index 00000000000..1ebf65c89a4 --- /dev/null +++ b/org.springframework.integration-tests/src/test/java/org/springframework/core/env/EnvironmentIntegrationTests-context.xml @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/org.springframework.integration-tests/src/test/java/org/springframework/core/env/EnvironmentIntegrationTests.java b/org.springframework.integration-tests/src/test/java/org/springframework/core/env/EnvironmentIntegrationTests.java new file mode 100644 index 00000000000..5c3332ed2ad --- /dev/null +++ b/org.springframework.integration-tests/src/test/java/org/springframework/core/env/EnvironmentIntegrationTests.java @@ -0,0 +1,712 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.env; + +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isIn; +import static org.hamcrest.Matchers.lessThan; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; +import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; +import static org.springframework.context.ConfigurableApplicationContext.ENVIRONMENT_BEAN_NAME; +import static org.springframework.core.env.EnvironmentIntegrationTests.Constants.DERIVED_DEV_BEAN_NAME; +import static org.springframework.core.env.EnvironmentIntegrationTests.Constants.DERIVED_DEV_ENV_NAME; +import static org.springframework.core.env.EnvironmentIntegrationTests.Constants.DEV_BEAN_NAME; +import static org.springframework.core.env.EnvironmentIntegrationTests.Constants.DEV_ENV_NAME; +import static org.springframework.core.env.EnvironmentIntegrationTests.Constants.ENVIRONMENT_AWARE_BEAN_NAME; +import static org.springframework.core.env.EnvironmentIntegrationTests.Constants.PROD_BEAN_NAME; +import static org.springframework.core.env.EnvironmentIntegrationTests.Constants.PROD_ENV_NAME; +import static org.springframework.core.env.EnvironmentIntegrationTests.Constants.TRANSITIVE_BEAN_NAME; +import static org.springframework.core.env.EnvironmentIntegrationTests.Constants.XML_PATH; + +import java.io.File; +import java.io.IOException; +import java.util.LinkedList; +import java.util.Properties; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.EnvironmentAware; +import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Profile; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.FileSystemXmlApplicationContext; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.context.support.GenericXmlApplicationContext; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.core.io.ClassPathResource; +import org.springframework.jca.context.ResourceAdapterApplicationContext; +import org.springframework.jca.support.SimpleBootstrapContext; +import org.springframework.jca.work.SimpleTaskWorkManager; +import org.springframework.mock.web.MockServletConfig; +import org.springframework.mock.web.MockServletContext; +import org.springframework.util.FileCopyUtils; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.AbstractRefreshableWebApplicationContext; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; +import org.springframework.web.context.support.GenericWebApplicationContext; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.context.support.XmlWebApplicationContext; +import org.springframework.web.portlet.context.AbstractRefreshablePortletApplicationContext; +import org.springframework.web.portlet.context.StaticPortletApplicationContext; +import org.springframework.web.portlet.context.XmlPortletApplicationContext; + + +/** + * Integration tests for container support of {@link Environment} + * interface. + * + * Tests all existing BeanFactory and ApplicationContext implementations to + * ensure that: + * - a default environment object is always present + * - a custom environment object can be set and retrieved against the factory/context + * - the {@link EnvironmentAware} interface is respected + * - the environment object is registered with the container as a singleton + * bean (if an ApplicationContext) + * - bean definition files (if any, and whether XML or @Configuration) are + * registered conditionally based on environment metadata + * + * @author Chris Beams + */ +public class EnvironmentIntegrationTests { + + private ConfigurableEnvironment prodEnv; + private ConfigurableEnvironment devEnv; + + /** + * Constants used both locally and in scan* sub-packages + */ + public static class Constants { + public static final String XML_PATH = "org/springframework/core/env/EnvironmentIntegrationTests-context.xml"; + + public static final String ENVIRONMENT_AWARE_BEAN_NAME = "envAwareBean"; + + public static final String PROD_BEAN_NAME = "prodBean"; + public static final String DEV_BEAN_NAME = "devBean"; + public static final String DERIVED_DEV_BEAN_NAME = "derivedDevBean"; + public static final String TRANSITIVE_BEAN_NAME = "transitiveBean"; + + public static final String PROD_ENV_NAME = "prod"; + public static final String DEV_ENV_NAME = "dev"; + public static final String DERIVED_DEV_ENV_NAME = "derivedDev"; + } + + @Before + public void setUp() { + prodEnv = new DefaultEnvironment(); + prodEnv.setActiveProfiles(PROD_ENV_NAME); + + devEnv = new DefaultEnvironment(); + devEnv.setActiveProfiles(DEV_ENV_NAME); + } + + @Test + public void genericApplicationContext_defaultEnv() { + ConfigurableApplicationContext ctx = + new GenericApplicationContext(newBeanFactoryWithEnvironmentAwareBean()); + + ctx.refresh(); + + assertHasDefaultEnvironment(ctx); + assertEnvironmentBeanRegistered(ctx); + assertEnvironmentAwareInvoked(ctx, ctx.getEnvironment()); + } + + @Test + public void genericApplicationContext_customEnv() { + GenericApplicationContext ctx = + new GenericApplicationContext(newBeanFactoryWithEnvironmentAwareBean()); + ctx.setEnvironment(prodEnv); + ctx.refresh(); + + assertHasEnvironment(ctx, prodEnv); + assertEnvironmentBeanRegistered(ctx); + assertEnvironmentAwareInvoked(ctx, prodEnv); + } + + @Test + public void xmlBeanDefinitionReader_inheritsEnvironmentFromEnvironmentCapableBDR() { + GenericApplicationContext ctx = new GenericApplicationContext(); + ctx.setEnvironment(prodEnv); + new XmlBeanDefinitionReader(ctx).loadBeanDefinitions(XML_PATH); + ctx.refresh(); + assertThat(ctx.containsBean(DEV_BEAN_NAME), is(false)); + assertThat(ctx.containsBean(PROD_BEAN_NAME), is(true)); + } + + @Test + public void annotatedBeanDefinitionReader_inheritsEnvironmentFromEnvironmentCapableBDR() { + GenericApplicationContext ctx = new GenericApplicationContext(); + ctx.setEnvironment(prodEnv); + new AnnotatedBeanDefinitionReader(ctx).register(Config.class); + ctx.refresh(); + assertThat(ctx.containsBean(DEV_BEAN_NAME), is(false)); + assertThat(ctx.containsBean(PROD_BEAN_NAME), is(true)); + } + + @Test + public void classPathBeanDefinitionScanner_inheritsEnvironmentFromEnvironmentCapableBDR_scanProfileAnnotatedConfigClasses() { + // it's actually ConfigurationClassPostProcessor's Environment that gets the job done here. + GenericApplicationContext ctx = new GenericApplicationContext(); + ctx.setEnvironment(prodEnv); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(ctx); + scanner.scan("org.springframework.core.env.scan1"); + ctx.refresh(); + assertThat(ctx.containsBean(DEV_BEAN_NAME), is(false)); + assertThat(ctx.containsBean(PROD_BEAN_NAME), is(true)); + } + + @Test + public void classPathBeanDefinitionScanner_inheritsEnvironmentFromEnvironmentCapableBDR_scanProfileAnnotatedComponents() { + GenericApplicationContext ctx = new GenericApplicationContext(); + ctx.setEnvironment(prodEnv); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(ctx); + scanner.scan("org.springframework.core.env.scan2"); + ctx.refresh(); + assertThat(scanner.getEnvironment(), is((Environment)ctx.getEnvironment())); + assertThat(ctx.containsBean(DEV_BEAN_NAME), is(false)); + assertThat(ctx.containsBean(PROD_BEAN_NAME), is(true)); + } + + @Test + public void genericXmlApplicationContext() { + GenericXmlApplicationContext ctx = new GenericXmlApplicationContext(); + + assertHasDefaultEnvironment(ctx); + + ctx.setEnvironment(prodEnv); + + ctx.load(XML_PATH); + ctx.refresh(); + + assertHasEnvironment(ctx, prodEnv); + assertEnvironmentBeanRegistered(ctx); + assertEnvironmentAwareInvoked(ctx, prodEnv); + assertThat(ctx.containsBean(DEV_BEAN_NAME), is(false)); + assertThat(ctx.containsBean(PROD_BEAN_NAME), is(true)); + } + + @Test + public void classPathXmlApplicationContext() { + ConfigurableApplicationContext ctx = + new ClassPathXmlApplicationContext(new String[] { XML_PATH }); + ctx.setEnvironment(prodEnv); + ctx.refresh(); + + assertEnvironmentBeanRegistered(ctx); + assertHasEnvironment(ctx, prodEnv); + assertEnvironmentAwareInvoked(ctx, ctx.getEnvironment()); + assertThat(ctx.containsBean(DEV_BEAN_NAME), is(false)); + assertThat(ctx.containsBean(PROD_BEAN_NAME), is(true)); + } + + @Test + public void fileSystemXmlApplicationContext() throws IOException { + ClassPathResource xml = new ClassPathResource(XML_PATH); + File tmpFile = File.createTempFile("test", "xml"); + FileCopyUtils.copy(xml.getFile(), tmpFile); + + // strange - FSXAC strips leading '/' unless prefixed with 'file:' + ConfigurableApplicationContext ctx = + new FileSystemXmlApplicationContext(new String[] { "file:"+tmpFile.getPath() }, false); + ctx.setEnvironment(prodEnv); + ctx.refresh(); + assertEnvironmentBeanRegistered(ctx); + assertHasEnvironment(ctx, prodEnv); + assertEnvironmentAwareInvoked(ctx, ctx.getEnvironment()); + assertThat(ctx.containsBean(DEV_BEAN_NAME), is(false)); + assertThat(ctx.containsBean(PROD_BEAN_NAME), is(true)); + } + + @Test + public void annotationConfigApplicationContext_withPojos() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + + assertHasDefaultEnvironment(ctx); + ctx.setEnvironment(prodEnv); + + ctx.register(EnvironmentAwareBean.class); + ctx.refresh(); + + assertEnvironmentAwareInvoked(ctx, prodEnv); + } + + @Test + public void annotationConfigApplicationContext_withProdEnvAndProdConfigClass() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + + assertHasDefaultEnvironment(ctx); + ctx.setEnvironment(prodEnv); + + ctx.register(ProdConfig.class); + ctx.refresh(); + + assertThat("should have prod bean", ctx.containsBean(PROD_BEAN_NAME), is(true)); + } + + @Test + public void annotationConfigApplicationContext_withProdEnvAndDevConfigClass() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + + assertHasDefaultEnvironment(ctx); + ctx.setEnvironment(prodEnv); + + ctx.register(DevConfig.class); + ctx.refresh(); + + assertThat("should not have dev bean", ctx.containsBean(DEV_BEAN_NAME), is(false)); + assertThat("should not have transitive bean", ctx.containsBean(TRANSITIVE_BEAN_NAME), is(false)); + } + + @Test + public void annotationConfigApplicationContext_withDevEnvAndDevConfigClass() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + + assertHasDefaultEnvironment(ctx); + ctx.setEnvironment(devEnv); + + ctx.register(DevConfig.class); + ctx.refresh(); + + assertThat("should have dev bean", ctx.containsBean(DEV_BEAN_NAME), is(true)); + assertThat("should have transitive bean", ctx.containsBean(TRANSITIVE_BEAN_NAME), is(true)); + } + + @Test + public void annotationConfigApplicationContext_withImportedConfigClasses() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + + assertHasDefaultEnvironment(ctx); + ctx.setEnvironment(prodEnv); + + ctx.register(Config.class); + ctx.refresh(); + + assertEnvironmentAwareInvoked(ctx, prodEnv); + assertThat("should have prod bean", ctx.containsBean(PROD_BEAN_NAME), is(true)); + assertThat("should not have dev bean", ctx.containsBean(DEV_BEAN_NAME), is(false)); + assertThat("should not have transitive bean", ctx.containsBean(TRANSITIVE_BEAN_NAME), is(false)); + } + + @Test + public void mostSpecificDerivedClassDrivesEnvironment_withDerivedDevEnvAndDerivedDevConfigClass() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + DefaultEnvironment derivedDevEnv = new DefaultEnvironment(); + derivedDevEnv.setActiveProfiles(DERIVED_DEV_ENV_NAME); + ctx.setEnvironment(derivedDevEnv); + ctx.register(DerivedDevConfig.class); + ctx.refresh(); + + assertThat("should have dev bean", ctx.containsBean(DEV_BEAN_NAME), is(true)); + assertThat("should have derived dev bean", ctx.containsBean(DERIVED_DEV_BEAN_NAME), is(true)); + assertThat("should have transitive bean", ctx.containsBean(TRANSITIVE_BEAN_NAME), is(true)); + } + + @Test + public void mostSpecificDerivedClassDrivesEnvironment_withDevEnvAndDerivedDevConfigClass() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.setEnvironment(devEnv); + ctx.register(DerivedDevConfig.class); + ctx.refresh(); + + assertThat("should not have dev bean", ctx.containsBean(DEV_BEAN_NAME), is(false)); + assertThat("should not have derived dev bean", ctx.containsBean(DERIVED_DEV_BEAN_NAME), is(false)); + assertThat("should not have transitive bean", ctx.containsBean(TRANSITIVE_BEAN_NAME), is(false)); + } + + @Test + public void webApplicationContext() { + GenericWebApplicationContext ctx = + new GenericWebApplicationContext(newBeanFactoryWithEnvironmentAwareBean()); + + assertHasDefaultWebEnvironment(ctx); + + ctx.setEnvironment(prodEnv); + ctx.refresh(); + + assertHasEnvironment(ctx, prodEnv); + assertEnvironmentBeanRegistered(ctx); + assertEnvironmentAwareInvoked(ctx, prodEnv); + } + + // TODO SPR-7508: need to think about how a custom environment / custom property sources + // would be specified in an actual webapp using XmlWebApplicationContext. What do the + // context params look like, etc. + @Test + public void xmlWebApplicationContext() { + AbstractRefreshableWebApplicationContext ctx = new XmlWebApplicationContext(); + ctx.setConfigLocation("classpath:" + XML_PATH); + ctx.setEnvironment(prodEnv); + ctx.refresh(); + + assertHasEnvironment(ctx, prodEnv); + assertEnvironmentBeanRegistered(ctx); + assertEnvironmentAwareInvoked(ctx, prodEnv); + assertThat(ctx.containsBean(DEV_BEAN_NAME), is(false)); + assertThat(ctx.containsBean(PROD_BEAN_NAME), is(true)); + } + + @Test + public void staticApplicationContext() { + StaticApplicationContext ctx = new StaticApplicationContext(); + + assertHasDefaultEnvironment(ctx); + + registerEnvironmentBeanDefinition(ctx); + + ctx.setEnvironment(prodEnv); + ctx.refresh(); + + assertHasEnvironment(ctx, prodEnv); + assertEnvironmentBeanRegistered(ctx); + assertEnvironmentAwareInvoked(ctx, prodEnv); + } + + @Test + public void staticWebApplicationContext() { + StaticWebApplicationContext ctx = new StaticWebApplicationContext(); + + assertHasDefaultWebEnvironment(ctx); + + registerEnvironmentBeanDefinition(ctx); + + ctx.setEnvironment(prodEnv); + ctx.refresh(); + + assertHasEnvironment(ctx, prodEnv); + assertEnvironmentBeanRegistered(ctx); + assertEnvironmentAwareInvoked(ctx, prodEnv); + } + + @Test + public void annotationConfigWebApplicationContext() { + AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); + ctx.setEnvironment(prodEnv); + ctx.setConfigLocation(EnvironmentAwareBean.class.getName()); + ctx.refresh(); + + assertHasEnvironment(ctx, prodEnv); + assertEnvironmentBeanRegistered(ctx); + assertEnvironmentAwareInvoked(ctx, prodEnv); + } + + @Test + public void registerServletParamPropertySources_AbstractRefreshableWebApplicationContext() { + MockServletContext servletContext = new MockServletContext(); + servletContext.addInitParameter("pCommon", "pCommonContextValue"); + servletContext.addInitParameter("pContext1", "pContext1Value"); + + MockServletConfig servletConfig = new MockServletConfig(servletContext); + servletConfig.addInitParameter("pCommon", "pCommonConfigValue"); + servletConfig.addInitParameter("pConfig1", "pConfig1Value"); + + AbstractRefreshableWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); + ctx.setConfigLocation(EnvironmentAwareBean.class.getName()); + ctx.setServletConfig(servletConfig); + ctx.refresh(); + + ConfigurableEnvironment environment = ctx.getEnvironment(); + assertThat(environment, instanceOf(DefaultWebEnvironment.class)); + LinkedList> propertySources = environment.getPropertySources(); + assertThat(PropertySource.named(DefaultWebEnvironment.SERVLET_CONTEXT_PARAMS_PROPERTY_SOURCE_NAME), isIn(propertySources)); + assertThat(PropertySource.named(DefaultWebEnvironment.SERVLET_CONFIG_PARAMS_PROPERTY_SOURCE_NAME), isIn(propertySources)); + + // ServletConfig gets precedence + assertThat(environment.getProperty("pCommon"), is("pCommonConfigValue")); + assertThat(propertySources.indexOf(PropertySource.named(DefaultWebEnvironment.SERVLET_CONFIG_PARAMS_PROPERTY_SOURCE_NAME)), + lessThan(propertySources.indexOf(PropertySource.named(DefaultWebEnvironment.SERVLET_CONTEXT_PARAMS_PROPERTY_SOURCE_NAME)))); + + // but all params are available + assertThat(environment.getProperty("pContext1"), is("pContext1Value")); + assertThat(environment.getProperty("pConfig1"), is("pConfig1Value")); + + // Servlet* PropertySources have precedence over System* PropertySources + assertThat(propertySources.indexOf(PropertySource.named(DefaultWebEnvironment.SERVLET_CONFIG_PARAMS_PROPERTY_SOURCE_NAME)), + lessThan(propertySources.indexOf(PropertySource.named(DefaultEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)))); + + // Replace system properties with a mock property source for convenience + MockPropertySource mockSystemProperties = new MockPropertySource(DefaultEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME); + mockSystemProperties.setProperty("pCommon", "pCommonSysPropsValue"); + mockSystemProperties.setProperty("pSysProps1", "pSysProps1Value"); + propertySources.set( + propertySources.indexOf(PropertySource.named(DefaultEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)), + mockSystemProperties); + + // assert that servletconfig init params resolve with higher precedence than sysprops + assertThat(environment.getProperty("pCommon"), is("pCommonConfigValue")); + assertThat(environment.getProperty("pSysProps1"), is("pSysProps1Value")); + } + + @Test + public void registerServletParamPropertySources_GenericWebApplicationContext() { + MockServletContext servletContext = new MockServletContext(); + servletContext.addInitParameter("pCommon", "pCommonContextValue"); + servletContext.addInitParameter("pContext1", "pContext1Value"); + + GenericWebApplicationContext ctx = new GenericWebApplicationContext(); + ctx.setServletContext(servletContext); + ctx.refresh(); + + ConfigurableEnvironment environment = ctx.getEnvironment(); + assertThat(environment, instanceOf(DefaultWebEnvironment.class)); + LinkedList> propertySources = environment.getPropertySources(); + assertThat(PropertySource.named(DefaultWebEnvironment.SERVLET_CONTEXT_PARAMS_PROPERTY_SOURCE_NAME), isIn(propertySources)); + assertThat(PropertySource.named(DefaultWebEnvironment.SERVLET_CONFIG_PARAMS_PROPERTY_SOURCE_NAME), not(isIn(propertySources))); + + // ServletContext params are available + assertThat(environment.getProperty("pCommon"), is("pCommonContextValue")); + assertThat(environment.getProperty("pContext1"), is("pContext1Value")); + + // Servlet* PropertySources have precedence over System* PropertySources + assertThat(propertySources.indexOf(PropertySource.named(DefaultWebEnvironment.SERVLET_CONTEXT_PARAMS_PROPERTY_SOURCE_NAME)), + lessThan(propertySources.indexOf(PropertySource.named(DefaultEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)))); + + // Replace system properties with a mock property source for convenience + MockPropertySource mockSystemProperties = new MockPropertySource(DefaultEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME); + mockSystemProperties.setProperty("pCommon", "pCommonSysPropsValue"); + mockSystemProperties.setProperty("pSysProps1", "pSysProps1Value"); + propertySources.set( + propertySources.indexOf(PropertySource.named(DefaultEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)), + mockSystemProperties); + + // assert that servletcontext init params resolve with higher precedence than sysprops + assertThat(environment.getProperty("pCommon"), is("pCommonContextValue")); + assertThat(environment.getProperty("pSysProps1"), is("pSysProps1Value")); + } + + @Test + public void registerServletParamPropertySources_StaticWebApplicationContext() { + MockServletContext servletContext = new MockServletContext(); + servletContext.addInitParameter("pCommon", "pCommonContextValue"); + servletContext.addInitParameter("pContext1", "pContext1Value"); + + MockServletConfig servletConfig = new MockServletConfig(servletContext); + servletConfig.addInitParameter("pCommon", "pCommonConfigValue"); + servletConfig.addInitParameter("pConfig1", "pConfig1Value"); + + StaticWebApplicationContext ctx = new StaticWebApplicationContext(); + ctx.setServletConfig(servletConfig); + ctx.refresh(); + + ConfigurableEnvironment environment = ctx.getEnvironment(); + LinkedList> propertySources = environment.getPropertySources(); + assertThat(PropertySource.named(DefaultWebEnvironment.SERVLET_CONTEXT_PARAMS_PROPERTY_SOURCE_NAME), isIn(propertySources)); + assertThat(PropertySource.named(DefaultWebEnvironment.SERVLET_CONFIG_PARAMS_PROPERTY_SOURCE_NAME), isIn(propertySources)); + + // ServletConfig gets precedence + assertThat(environment.getProperty("pCommon"), is("pCommonConfigValue")); + assertThat(propertySources.indexOf(PropertySource.named(DefaultWebEnvironment.SERVLET_CONFIG_PARAMS_PROPERTY_SOURCE_NAME)), + lessThan(propertySources.indexOf(PropertySource.named(DefaultWebEnvironment.SERVLET_CONTEXT_PARAMS_PROPERTY_SOURCE_NAME)))); + + // but all params are available + assertThat(environment.getProperty("pContext1"), is("pContext1Value")); + assertThat(environment.getProperty("pConfig1"), is("pConfig1Value")); + + // Servlet* PropertySources have precedence over System* PropertySources + assertThat(propertySources.indexOf(PropertySource.named(DefaultWebEnvironment.SERVLET_CONFIG_PARAMS_PROPERTY_SOURCE_NAME)), + lessThan(propertySources.indexOf(PropertySource.named(DefaultEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)))); + + // Replace system properties with a mock property source for convenience + MockPropertySource mockSystemProperties = new MockPropertySource(DefaultEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME); + mockSystemProperties.setProperty("pCommon", "pCommonSysPropsValue"); + mockSystemProperties.setProperty("pSysProps1", "pSysProps1Value"); + propertySources.set( + propertySources.indexOf(PropertySource.named(DefaultEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)), + mockSystemProperties); + + // assert that servletconfig init params resolve with higher precedence than sysprops + assertThat(environment.getProperty("pCommon"), is("pCommonConfigValue")); + assertThat(environment.getProperty("pSysProps1"), is("pSysProps1Value")); + } + + static class MockPropertySource extends PropertiesPropertySource { + public MockPropertySource() { + this("MockPropertySource"); + } + + public MockPropertySource(String name) { + super(name, new Properties()); + } + + public void setProperty(String key, String value) { + this.source.setProperty(key, value); + } + } + + @Test + public void resourceAdapterApplicationContext() { + ResourceAdapterApplicationContext ctx = new ResourceAdapterApplicationContext(new SimpleBootstrapContext(new SimpleTaskWorkManager())); + + // TODO SPR-7508: should be a JCA-specific environment? + assertHasDefaultEnvironment(ctx); + + registerEnvironmentBeanDefinition(ctx); + + ctx.setEnvironment(prodEnv); + ctx.refresh(); + + assertHasEnvironment(ctx, prodEnv); + assertEnvironmentBeanRegistered(ctx); + assertEnvironmentAwareInvoked(ctx, prodEnv); + } + + @Test + public void staticPortletApplicationContext() { + StaticPortletApplicationContext ctx = new StaticPortletApplicationContext(); + + // TODO SPR-7508: should be a Portlet-specific environment? + assertHasDefaultWebEnvironment(ctx); + + registerEnvironmentBeanDefinition(ctx); + + ctx.setEnvironment(prodEnv); + ctx.refresh(); + + assertHasEnvironment(ctx, prodEnv); + assertEnvironmentBeanRegistered(ctx); + assertEnvironmentAwareInvoked(ctx, prodEnv); + } + + @Test + public void xmlPortletApplicationContext() { + AbstractRefreshablePortletApplicationContext ctx = new XmlPortletApplicationContext(); + ctx.setEnvironment(prodEnv); + ctx.setConfigLocation("classpath:" + XML_PATH); + ctx.refresh(); + + assertHasEnvironment(ctx, prodEnv); + assertEnvironmentBeanRegistered(ctx); + assertEnvironmentAwareInvoked(ctx, prodEnv); + assertThat(ctx.containsBean(DEV_BEAN_NAME), is(false)); + assertThat(ctx.containsBean(PROD_BEAN_NAME), is(true)); + } + + + private DefaultListableBeanFactory newBeanFactoryWithEnvironmentAwareBean() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + registerEnvironmentBeanDefinition(bf); + return bf; + } + + private void registerEnvironmentBeanDefinition(BeanDefinitionRegistry registry) { + registry.registerBeanDefinition(ENVIRONMENT_AWARE_BEAN_NAME, + rootBeanDefinition(EnvironmentAwareBean.class).getBeanDefinition()); + } + + private void assertEnvironmentBeanRegistered( + ConfigurableApplicationContext ctx) { + // ensure environment is registered as a bean + assertThat(ctx.containsBean(ENVIRONMENT_BEAN_NAME), is(true)); + } + + private void assertHasDefaultEnvironment(ApplicationContext ctx) { + Environment defaultEnv = ctx.getEnvironment(); + assertThat(defaultEnv, notNullValue()); + assertThat(defaultEnv, instanceOf(DefaultEnvironment.class)); + } + + private void assertHasDefaultWebEnvironment(WebApplicationContext ctx) { + // ensure a default web environment exists + Environment defaultEnv = ctx.getEnvironment(); + assertThat(defaultEnv, notNullValue()); + assertThat(defaultEnv, instanceOf(DefaultWebEnvironment.class)); + } + + private void assertHasEnvironment(ApplicationContext ctx, Environment expectedEnv) { + // ensure the custom environment took + Environment actualEnv = ctx.getEnvironment(); + assertThat(actualEnv, notNullValue()); + assertThat(actualEnv, is(expectedEnv)); + // ensure environment is registered as a bean + assertThat(ctx.containsBean(ENVIRONMENT_BEAN_NAME), is(true)); + } + + private void assertEnvironmentAwareInvoked(ConfigurableApplicationContext ctx, Environment expectedEnv) { + assertThat(ctx.getBean(EnvironmentAwareBean.class).environment, is(expectedEnv)); + } + + private static class EnvironmentAwareBean implements EnvironmentAware { + + public Environment environment; + + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + } + + /** + * Mirrors the structure of beans and environment-specific config files + * in EnvironmentIntegrationTests-context.xml + */ + @Configuration + @Import({DevConfig.class, ProdConfig.class}) + static class Config { + @Bean + public EnvironmentAwareBean envAwareBean() { + return new EnvironmentAwareBean(); + } + } + + @Profile(DEV_ENV_NAME) + @Configuration + @Import(TransitiveConfig.class) + static class DevConfig { + @Bean + public Object devBean() { + return new Object(); + } + } + + @Profile(PROD_ENV_NAME) + @Configuration + static class ProdConfig { + @Bean + public Object prodBean() { + return new Object(); + } + } + + @Configuration + static class TransitiveConfig { + @Bean + public Object transitiveBean() { + return new Object(); + } + } + + @Profile(DERIVED_DEV_ENV_NAME) + @Configuration + static class DerivedDevConfig extends DevConfig { + @Bean + public Object derivedDevBean() { + return new Object(); + } + } +} diff --git a/org.springframework.integration-tests/src/test/java/org/springframework/core/env/scan1/package-info.java b/org.springframework.integration-tests/src/test/java/org/springframework/core/env/scan1/package-info.java new file mode 100644 index 00000000000..d2a554752a9 --- /dev/null +++ b/org.springframework.integration-tests/src/test/java/org/springframework/core/env/scan1/package-info.java @@ -0,0 +1,52 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Mirrors the structure of beans and environment-specific config files + * in EnvironmentIntegrationTests-context.xml + */ +package org.springframework.core.env.scan1; + +import static org.springframework.core.env.EnvironmentIntegrationTests.Constants.DEV_ENV_NAME; +import static org.springframework.core.env.EnvironmentIntegrationTests.Constants.PROD_ENV_NAME; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Profile; + +@Configuration +@Import({DevConfig.class, ProdConfig.class}) +class Config { +} + +@Profile(DEV_ENV_NAME) +@Configuration +class DevConfig { + @Bean + public Object devBean() { + return new Object(); + } +} + +@Profile(PROD_ENV_NAME) +@Configuration +class ProdConfig { + @Bean + public Object prodBean() { + return new Object(); + } +} diff --git a/org.springframework.integration-tests/src/test/java/org/springframework/core/env/scan2/package-info.java b/org.springframework.integration-tests/src/test/java/org/springframework/core/env/scan2/package-info.java new file mode 100644 index 00000000000..be66aa076a1 --- /dev/null +++ b/org.springframework.integration-tests/src/test/java/org/springframework/core/env/scan2/package-info.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Mirrors the structure of beans and environment-specific config files + * in EnvironmentIntegrationTests-context.xml + */ +package org.springframework.core.env.scan2; + +import static org.springframework.core.env.EnvironmentIntegrationTests.Constants.DEV_BEAN_NAME; +import static org.springframework.core.env.EnvironmentIntegrationTests.Constants.DEV_ENV_NAME; +import static org.springframework.core.env.EnvironmentIntegrationTests.Constants.PROD_BEAN_NAME; +import static org.springframework.core.env.EnvironmentIntegrationTests.Constants.PROD_ENV_NAME; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +@Profile(DEV_ENV_NAME) +@Component(DEV_BEAN_NAME) +class DevBean { } + +@Profile(PROD_ENV_NAME) +@Component(PROD_BEAN_NAME) +class ProdBean { } diff --git a/org.springframework.integration-tests/src/test/resources/log4j.xml b/org.springframework.integration-tests/src/test/resources/log4j.xml index 767b96d6206..f8aeb053a52 100644 --- a/org.springframework.integration-tests/src/test/resources/log4j.xml +++ b/org.springframework.integration-tests/src/test/resources/log4j.xml @@ -15,6 +15,10 @@ + + + + @@ -25,4 +29,4 @@ - \ No newline at end of file + diff --git a/org.springframework.jdbc/.settings/org.eclipse.jdt.core.prefs b/org.springframework.jdbc/.settings/org.eclipse.jdt.core.prefs index 5a5d4fe0932..51fbd353764 100644 --- a/org.springframework.jdbc/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.jdbc/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ #Wed Jul 15 00:01:31 PDT 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/org.springframework.jdbc/pom.xml b/org.springframework.jdbc/pom.xml index b658fd195ce..d27a822aa82 100644 --- a/org.springframework.jdbc/pom.xml +++ b/org.springframework.jdbc/pom.xml @@ -4,12 +4,12 @@ org.springframework spring-jdbc jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodesFactory.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodesFactory.java index 4b984e7f577..30f7a55dc8b 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodesFactory.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodesFactory.java @@ -103,6 +103,7 @@ public class SQLErrorCodesFactory { DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); lbf.setBeanClassLoader(getClass().getClassLoader()); XmlBeanDefinitionReader bdr = new XmlBeanDefinitionReader(lbf); + // TODO: SPR-7508 consider setEnvironment() here // Load default SQL error codes. Resource resource = loadResource(SQL_ERROR_CODE_DEFAULT_PATH); diff --git a/org.springframework.jdbc/src/main/resources/META-INF/spring.schemas b/org.springframework.jdbc/src/main/resources/META-INF/spring.schemas index 0b9d1bae079..5db9fd4b2b4 100644 --- a/org.springframework.jdbc/src/main/resources/META-INF/spring.schemas +++ b/org.springframework.jdbc/src/main/resources/META-INF/spring.schemas @@ -1,2 +1,3 @@ http\://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd=org/springframework/jdbc/config/spring-jdbc-3.0.xsd -http\://www.springframework.org/schema/jdbc/spring-jdbc.xsd=org/springframework/jdbc/config/spring-jdbc-3.0.xsd \ No newline at end of file +http\://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd=org/springframework/jdbc/config/spring-jdbc-3.1.xsd +http\://www.springframework.org/schema/jdbc/spring-jdbc.xsd=org/springframework/jdbc/config/spring-jdbc-3.1.xsd diff --git a/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/config/spring-jdbc-3.1.xsd b/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/config/spring-jdbc-3.1.xsd new file mode 100644 index 00000000000..269e08a8a12 --- /dev/null +++ b/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/config/spring-jdbc-3.1.xsd @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + elements. + ]]> + + + + + + + + + + + + + + + + + + + + + + Is this bean "enabled", meaning the scripts will be executed? + Defaults to true, but can be used to switch on and off the initialization depending on the environment. + + + + + + + Should failed SQL statements be ignored during initialization? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.jms/.settings/org.eclipse.jdt.core.prefs b/org.springframework.jms/.settings/org.eclipse.jdt.core.prefs index 75d5c65c971..792acc823a3 100644 --- a/org.springframework.jms/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.jms/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ #Wed Jul 15 00:01:30 PDT 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=do not generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/org.springframework.jms/pom.xml b/org.springframework.jms/pom.xml index 073b6e79f52..7bbc1d7bca2 100644 --- a/org.springframework.jms/pom.xml +++ b/org.springframework.jms/pom.xml @@ -4,12 +4,12 @@ org.springframework spring-jms jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.jms/src/main/resources/META-INF/spring.schemas b/org.springframework.jms/src/main/resources/META-INF/spring.schemas index cee622f1872..64d6c75c6ff 100644 --- a/org.springframework.jms/src/main/resources/META-INF/spring.schemas +++ b/org.springframework.jms/src/main/resources/META-INF/spring.schemas @@ -1,3 +1,4 @@ http\://www.springframework.org/schema/jms/spring-jms-2.5.xsd=org/springframework/jms/config/spring-jms-2.5.xsd http\://www.springframework.org/schema/jms/spring-jms-3.0.xsd=org/springframework/jms/config/spring-jms-3.0.xsd -http\://www.springframework.org/schema/jms/spring-jms.xsd=org/springframework/jms/config/spring-jms-3.0.xsd +http\://www.springframework.org/schema/jms/spring-jms-3.1.xsd=org/springframework/jms/config/spring-jms-3.1.xsd +http\://www.springframework.org/schema/jms/spring-jms.xsd=org/springframework/jms/config/spring-jms-3.1.xsd diff --git a/org.springframework.jms/src/main/resources/org/springframework/jms/config/spring-jms-3.1.xsd b/org.springframework.jms/src/main/resources/org/springframework/jms/config/spring-jms-3.1.xsd new file mode 100644 index 00000000000..b4cfb626ed3 --- /dev/null +++ b/org.springframework.jms/src/main/resources/org/springframework/jms/config/spring-jms-3.1.xsd @@ -0,0 +1,472 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.orm/.settings/org.eclipse.jdt.core.prefs b/org.springframework.orm/.settings/org.eclipse.jdt.core.prefs index 0e29d554498..7a583ba283d 100644 --- a/org.springframework.orm/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.orm/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ #Wed Jul 15 00:01:31 PDT 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/org.springframework.orm/pom.xml b/org.springframework.orm/pom.xml index 3c7375b7e98..542321ea173 100644 --- a/org.springframework.orm/pom.xml +++ b/org.springframework.orm/pom.xml @@ -6,12 +6,12 @@ org.springframework spring-orm jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.oxm/pom.xml b/org.springframework.oxm/pom.xml index 8131e2ea157..701b405249b 100644 --- a/org.springframework.oxm/pom.xml +++ b/org.springframework.oxm/pom.xml @@ -6,12 +6,12 @@ org.springframework spring-oxm jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.oxm/src/main/resources/META-INF/spring.schemas b/org.springframework.oxm/src/main/resources/META-INF/spring.schemas index ea48a6fa429..e746146264a 100644 --- a/org.springframework.oxm/src/main/resources/META-INF/spring.schemas +++ b/org.springframework.oxm/src/main/resources/META-INF/spring.schemas @@ -1,2 +1,3 @@ http\://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd=org/springframework/oxm/config/spring-oxm-3.0.xsd -http\://www.springframework.org/schema/oxm/spring-oxm.xsd=org/springframework/oxm/config/spring-oxm-3.0.xsd \ No newline at end of file +http\://www.springframework.org/schema/oxm/spring-oxm-3.1.xsd=org/springframework/oxm/config/spring-oxm-3.1.xsd +http\://www.springframework.org/schema/oxm/spring-oxm.xsd=org/springframework/oxm/config/spring-oxm-3.1.xsd diff --git a/org.springframework.oxm/src/main/resources/org/springframework/oxm/config/spring-oxm-3.1.xsd b/org.springframework.oxm/src/main/resources/org/springframework/oxm/config/spring-oxm-3.1.xsd new file mode 100644 index 00000000000..67325c70b90 --- /dev/null +++ b/org.springframework.oxm/src/main/resources/org/springframework/oxm/config/spring-oxm-3.1.xsd @@ -0,0 +1,118 @@ + + + + + + + + + Defines the elements used in Spring's Object/XML Mapping integration. + + + + + + + + Defines a JAXB2 Marshaller. + + + + + + + + + + + + + + + + + + + The JAXB Context path + + + + + + + + + + + + Defines a JiBX Marshaller. + + + + + + + + + + + + + The binding name used by this marshaller. + + + + + + + + + + + + Defines a XMLBeans Marshaller. + + + + + + + + + + + + + The bean name of the XmlOptions that is to be used for this marshaller. Typically a + XmlOptionsFactoryBean definition. + + + + + + + + + + + + + + + + A class supported by a marshaller. + + + + + + + + + + + diff --git a/org.springframework.spring-library/pom.xml b/org.springframework.spring-library/pom.xml index 5e9b592fe33..37e9857c3fa 100644 --- a/org.springframework.spring-library/pom.xml +++ b/org.springframework.spring-library/pom.xml @@ -14,7 +14,7 @@ org.springframework spring-library libd - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT Spring Framework Spring is a layered Java/J2EE application platform, based on code published in Expert One-on-One J2EE Design and Development by Rod Johnson (Wrox, 2002). diff --git a/org.springframework.spring-parent/pom.xml b/org.springframework.spring-parent/pom.xml index 9d38c6e85d6..f407bc490fa 100644 --- a/org.springframework.spring-parent/pom.xml +++ b/org.springframework.spring-parent/pom.xml @@ -14,7 +14,7 @@ spring-parent pom Spring Framework - Parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT Spring Framework Parent https://fisheye.springframework.org/browse/spring-framework diff --git a/org.springframework.test/.settings/org.eclipse.jdt.core.prefs b/org.springframework.test/.settings/org.eclipse.jdt.core.prefs index b96e8d13cd6..1cbe5a3ebee 100644 --- a/org.springframework.test/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.test/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ #Wed Jul 15 00:01:31 PDT 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=20 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/org.springframework.test/pom.xml b/org.springframework.test/pom.xml index d933ee82d81..79787997adf 100644 --- a/org.springframework.test/pom.xml +++ b/org.springframework.test/pom.xml @@ -4,12 +4,12 @@ org.springframework spring-test jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.transaction/.settings/org.eclipse.jdt.core.prefs b/org.springframework.transaction/.settings/org.eclipse.jdt.core.prefs index 0e29d554498..7a583ba283d 100644 --- a/org.springframework.transaction/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.transaction/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ #Wed Jul 15 00:01:31 PDT 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/org.springframework.transaction/pom.xml b/org.springframework.transaction/pom.xml index ac19a8335f5..9fed17f6faa 100644 --- a/org.springframework.transaction/pom.xml +++ b/org.springframework.transaction/pom.xml @@ -4,12 +4,12 @@ org.springframework spring-tx jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.transaction/src/main/java/org/springframework/jca/context/SpringContextResourceAdapter.java b/org.springframework.transaction/src/main/java/org/springframework/jca/context/SpringContextResourceAdapter.java index ae041d3934e..e9af714e540 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/jca/context/SpringContextResourceAdapter.java +++ b/org.springframework.transaction/src/main/java/org/springframework/jca/context/SpringContextResourceAdapter.java @@ -166,6 +166,7 @@ public class SpringContextResourceAdapter implements ResourceAdapter { new ResourceAdapterApplicationContext(bootstrapContext); // Set ResourceAdapter's ClassLoader as bean class loader. applicationContext.setClassLoader(getClass().getClassLoader()); + // TODO: SPR-7508 consider setEnvironment() here // Extract individual config locations. String[] configLocations = StringUtils.tokenizeToStringArray(getContextConfigLocation(), CONFIG_LOCATION_DELIMITERS); @@ -184,6 +185,7 @@ public class SpringContextResourceAdapter implements ResourceAdapter { * @see #setContextConfigLocation */ protected void loadBeanDefinitions(BeanDefinitionRegistry registry, String[] configLocations) { + // TODO: SPR-7508 consider setEnvironment() here new XmlBeanDefinitionReader(registry).loadBeanDefinitions(configLocations); } diff --git a/org.springframework.transaction/src/main/resources/META-INF/spring.schemas b/org.springframework.transaction/src/main/resources/META-INF/spring.schemas index 6fb4116d0b5..acf00109446 100644 --- a/org.springframework.transaction/src/main/resources/META-INF/spring.schemas +++ b/org.springframework.transaction/src/main/resources/META-INF/spring.schemas @@ -1,4 +1,5 @@ http\://www.springframework.org/schema/tx/spring-tx-2.0.xsd=org/springframework/transaction/config/spring-tx-2.0.xsd http\://www.springframework.org/schema/tx/spring-tx-2.5.xsd=org/springframework/transaction/config/spring-tx-2.5.xsd http\://www.springframework.org/schema/tx/spring-tx-3.0.xsd=org/springframework/transaction/config/spring-tx-3.0.xsd -http\://www.springframework.org/schema/tx/spring-tx.xsd=org/springframework/transaction/config/spring-tx-3.0.xsd +http\://www.springframework.org/schema/tx/spring-tx-3.1.xsd=org/springframework/transaction/config/spring-tx-3.1.xsd +http\://www.springframework.org/schema/tx/spring-tx.xsd=org/springframework/transaction/config/spring-tx-3.1.xsd diff --git a/org.springframework.transaction/src/main/resources/org/springframework/transaction/config/spring-tx-3.1.xsd b/org.springframework.transaction/src/main/resources/org/springframework/transaction/config/spring-tx-3.1.xsd new file mode 100644 index 00000000000..8d76ee3a43b --- /dev/null +++ b/org.springframework.transaction/src/main/resources/org/springframework/transaction/config/spring-tx-3.1.xsd @@ -0,0 +1,244 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.web.portlet/.settings/org.eclipse.jdt.core.prefs b/org.springframework.web.portlet/.settings/org.eclipse.jdt.core.prefs index 7b0e30db0ed..13ebdb03704 100644 --- a/org.springframework.web.portlet/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.web.portlet/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ #Wed Jul 15 00:01:32 PDT 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/org.springframework.web.portlet/pom.xml b/org.springframework.web.portlet/pom.xml index f415286cc55..ac6678b3f4f 100644 --- a/org.springframework.web.portlet/pom.xml +++ b/org.springframework.web.portlet/pom.xml @@ -4,12 +4,12 @@ org.springframework spring-webmvc-portlet jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/GenericPortletBean.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/GenericPortletBean.java index 3ace247159f..f73ce1b6db4 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/GenericPortletBean.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/GenericPortletBean.java @@ -27,13 +27,14 @@ import javax.portlet.PortletException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.beans.BeanWrapper; import org.springframework.beans.BeansException; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.PropertyAccessorFactory; import org.springframework.beans.PropertyValue; import org.springframework.beans.PropertyValues; +import org.springframework.core.env.DefaultWebEnvironment; +import org.springframework.core.env.Environment; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceEditor; import org.springframework.core.io.ResourceLoader; @@ -74,7 +75,12 @@ public abstract class GenericPortletBean extends GenericPortlet { */ private final Set requiredProperties = new HashSet(); - + /** + * TODO SPR-7508: think about making this overridable {@link EnvironmentAware}? + */ + private Environment environment = new DefaultWebEnvironment(); + + /** * Subclasses can invoke this method to specify that this property * (which must match a JavaBean property they expose) is mandatory, @@ -103,7 +109,7 @@ public abstract class GenericPortletBean extends GenericPortlet { PropertyValues pvs = new PortletConfigPropertyValues(getPortletConfig(), this.requiredProperties); BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); ResourceLoader resourceLoader = new PortletContextResourceLoader(getPortletContext()); - bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader)); + bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment)); initBeanWrapper(bw); bw.setPropertyValues(pvs, true); } diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/AbstractRefreshablePortletApplicationContext.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/AbstractRefreshablePortletApplicationContext.java index db136444e57..39ad0bdb735 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/AbstractRefreshablePortletApplicationContext.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/AbstractRefreshablePortletApplicationContext.java @@ -21,6 +21,7 @@ import javax.portlet.PortletContext; import javax.servlet.ServletContext; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.AbstractRefreshableConfigApplicationContext; import org.springframework.core.io.Resource; @@ -167,4 +168,8 @@ public abstract class AbstractRefreshablePortletApplicationContext extends Abstr return new PortletContextResourcePatternResolver(this); } + @Override + protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { + super.customizeBeanFactory(beanFactory); + } } diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/StaticPortletApplicationContext.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/StaticPortletApplicationContext.java index ecaf20061f1..2746d8a1138 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/StaticPortletApplicationContext.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/StaticPortletApplicationContext.java @@ -23,6 +23,7 @@ import javax.servlet.ServletContext; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.StaticApplicationContext; +import org.springframework.core.env.DefaultWebEnvironment; import org.springframework.core.io.Resource; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.web.context.WebApplicationContext; @@ -60,6 +61,7 @@ public class StaticPortletApplicationContext extends StaticApplicationContext public StaticPortletApplicationContext() { setDisplayName("Root Portlet ApplicationContext"); + setEnvironment(new DefaultWebEnvironment()); // TODO SPR-7508: create custom portlet env? } diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/XmlPortletApplicationContext.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/XmlPortletApplicationContext.java index 6cb6e91f287..83769628ac1 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/XmlPortletApplicationContext.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/XmlPortletApplicationContext.java @@ -83,6 +83,7 @@ public class XmlPortletApplicationContext extends AbstractRefreshablePortletAppl // Configure the bean definition reader with this context's // resource loading environment. + beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/context/XmlPortletApplicationContextTests.java b/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/context/XmlPortletApplicationContextTests.java index 283340c8046..d968e5fd3fb 100644 --- a/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/context/XmlPortletApplicationContextTests.java +++ b/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/context/XmlPortletApplicationContextTests.java @@ -118,7 +118,7 @@ public class XmlPortletApplicationContextTests extends AbstractXmlWebApplication public void testCount() { assertTrue("should have 16 beans, not "+ this.applicationContext.getBeanDefinitionCount(), - this.applicationContext.getBeanDefinitionCount() == 16); + this.applicationContext.getBeanDefinitionCount() == 16); } public void testPortletContextAwareBean() { diff --git a/org.springframework.web.servlet/.settings/org.eclipse.jdt.core.prefs b/org.springframework.web.servlet/.settings/org.eclipse.jdt.core.prefs index 0e29d554498..7a583ba283d 100644 --- a/org.springframework.web.servlet/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.web.servlet/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ #Wed Jul 15 00:01:31 PDT 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/org.springframework.web.servlet/pom.xml b/org.springframework.web.servlet/pom.xml index d28b484d3b5..44a99a6f8af 100644 --- a/org.springframework.web.servlet/pom.xml +++ b/org.springframework.web.servlet/pom.xml @@ -6,12 +6,12 @@ org.springframework spring-webmvc jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/HttpServletBean.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/HttpServletBean.java index 1d994096ed7..f166bdbc96b 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/HttpServletBean.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/HttpServletBean.java @@ -34,6 +34,9 @@ import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.PropertyAccessorFactory; import org.springframework.beans.PropertyValue; import org.springframework.beans.PropertyValues; +import org.springframework.context.EnvironmentAware; +import org.springframework.core.env.DefaultWebEnvironment; +import org.springframework.core.env.Environment; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceEditor; import org.springframework.core.io.ResourceLoader; @@ -83,6 +86,11 @@ public abstract class HttpServletBean extends HttpServlet { */ private final Set requiredProperties = new HashSet(); + /** + * TODO SPR-7508: think about making this overridable {@link EnvironmentAware}? + */ + private Environment environment = new DefaultWebEnvironment(); + /** * Subclasses can invoke this method to specify that this property @@ -114,7 +122,7 @@ public abstract class HttpServletBean extends HttpServlet { PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); - bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader)); + bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment)); initBeanWrapper(bw); bw.setPropertyValues(pvs, true); } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/XmlViewResolver.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/XmlViewResolver.java index 0cbe725b9b0..35dc231f508 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/XmlViewResolver.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/XmlViewResolver.java @@ -136,6 +136,7 @@ public class XmlViewResolver extends AbstractCachingViewResolver // Load XML resource with context-aware entity resolver. XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); + reader.setEnvironment(getApplicationContext().getEnvironment()); reader.setEntityResolver(new ResourceEntityResolver(getApplicationContext())); reader.loadBeanDefinitions(actualLocation); diff --git a/org.springframework.web.servlet/src/main/resources/META-INF/spring.schemas b/org.springframework.web.servlet/src/main/resources/META-INF/spring.schemas index d1b483ddb0f..3dfc9eed6f5 100644 --- a/org.springframework.web.servlet/src/main/resources/META-INF/spring.schemas +++ b/org.springframework.web.servlet/src/main/resources/META-INF/spring.schemas @@ -1,2 +1,3 @@ http\://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd=org/springframework/web/servlet/config/spring-mvc-3.0.xsd -http\://www.springframework.org/schema/mvc/spring-mvc.xsd=org/springframework/web/servlet/config/spring-mvc-3.0.xsd \ No newline at end of file +http\://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd=org/springframework/web/servlet/config/spring-mvc-3.1.xsd +http\://www.springframework.org/schema/mvc/spring-mvc.xsd=org/springframework/web/servlet/config/spring-mvc-3.1.xsd diff --git a/org.springframework.web.servlet/src/main/resources/org/springframework/web/servlet/config/spring-mvc-3.1.xsd b/org.springframework.web.servlet/src/main/resources/org/springframework/web/servlet/config/spring-mvc-3.1.xsd new file mode 100644 index 00000000000..02c6e7ebad7 --- /dev/null +++ b/org.springframework.web.servlet/src/main/resources/org/springframework/web/servlet/config/spring-mvc-3.1.xsd @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.web.struts/.settings/org.eclipse.jdt.core.prefs b/org.springframework.web.struts/.settings/org.eclipse.jdt.core.prefs index 0e29d554498..7a583ba283d 100644 --- a/org.springframework.web.struts/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.web.struts/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ #Wed Jul 15 00:01:31 PDT 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/org.springframework.web.struts/pom.xml b/org.springframework.web.struts/pom.xml index 0609ca3b9c4..a82f148510e 100644 --- a/org.springframework.web.struts/pom.xml +++ b/org.springframework.web.struts/pom.xml @@ -6,12 +6,12 @@ org.springframework spring-struts jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.web/.settings/org.eclipse.jdt.core.prefs b/org.springframework.web/.settings/org.eclipse.jdt.core.prefs index a15f738edcd..4655eeb423f 100644 --- a/org.springframework.web/.settings/org.eclipse.jdt.core.prefs +++ b/org.springframework.web/.settings/org.eclipse.jdt.core.prefs @@ -1,15 +1,15 @@ #Wed Jul 15 00:01:30 PDT 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/org.springframework.web/pom.xml b/org.springframework.web/pom.xml index c1840271c3f..5f9bb413b6d 100644 --- a/org.springframework.web/pom.xml +++ b/org.springframework.web/pom.xml @@ -6,12 +6,12 @@ org.springframework spring-web jar - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT org.springframework spring-parent ../org.springframework.spring-parent - 3.0.5.BUILD-SNAPSHOT + 3.1.0.BUILD-SNAPSHOT diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/support/AbstractRefreshableWebApplicationContext.java b/org.springframework.web/src/main/java/org/springframework/web/context/support/AbstractRefreshableWebApplicationContext.java index 58d2a081825..8cf8d01646e 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/context/support/AbstractRefreshableWebApplicationContext.java +++ b/org.springframework.web/src/main/java/org/springframework/web/context/support/AbstractRefreshableWebApplicationContext.java @@ -21,6 +21,7 @@ import javax.servlet.ServletContext; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.support.AbstractRefreshableConfigApplicationContext; +import org.springframework.core.env.DefaultWebEnvironment; import org.springframework.core.io.Resource; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.ui.context.Theme; @@ -92,11 +93,14 @@ public abstract class AbstractRefreshableWebApplicationContext extends AbstractR public AbstractRefreshableWebApplicationContext() { setDisplayName("Root WebApplicationContext"); + setEnvironment(new DefaultWebEnvironment()); } public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; + // TODO: SPR-7508 extract createEnvironment() method; do also in GWAC + this.getEnvironment().getPropertySources().push(new ServletContextPropertySource(this.servletContext)); } public ServletContext getServletContext() { @@ -106,8 +110,10 @@ public abstract class AbstractRefreshableWebApplicationContext extends AbstractR public void setServletConfig(ServletConfig servletConfig) { this.servletConfig = servletConfig; if (servletConfig != null && this.servletContext == null) { - this.servletContext = servletConfig.getServletContext(); + this.setServletContext(servletConfig.getServletContext()); } + // TODO: SPR-7508 extract createEnvironment() method; do also in GWAC + this.getEnvironment().getPropertySources().push(new ServletConfigPropertySource(servletConfig)); } public ServletConfig getServletConfig() { diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/support/AnnotationConfigWebApplicationContext.java b/org.springframework.web/src/main/java/org/springframework/web/context/support/AnnotationConfigWebApplicationContext.java index e47c26fa9d9..b126cb3ec33 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/context/support/AnnotationConfigWebApplicationContext.java +++ b/org.springframework.web/src/main/java/org/springframework/web/context/support/AnnotationConfigWebApplicationContext.java @@ -71,7 +71,11 @@ public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWe @Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) { AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(beanFactory); + reader.setEnvironment(this.getEnvironment()); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory); + scanner.setEnvironment(this.getEnvironment()); + BeanNameGenerator beanNameGenerator = getBeanNameGenerator(); ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver(); if (beanNameGenerator != null) { diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/support/GenericWebApplicationContext.java b/org.springframework.web/src/main/java/org/springframework/web/context/support/GenericWebApplicationContext.java index 69293d20803..daf5b5805a0 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/context/support/GenericWebApplicationContext.java +++ b/org.springframework.web/src/main/java/org/springframework/web/context/support/GenericWebApplicationContext.java @@ -21,6 +21,7 @@ import javax.servlet.ServletContext; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.support.GenericApplicationContext; +import org.springframework.core.env.DefaultWebEnvironment; import org.springframework.core.io.Resource; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.ui.context.Theme; @@ -60,6 +61,11 @@ public class GenericWebApplicationContext extends GenericApplicationContext private ThemeSource themeSource; + // override superclass definition of environment + // TODO SPR-7508: polish + { + this.setEnvironment(new DefaultWebEnvironment()); + } /** * Create a new GenericWebApplicationContext. @@ -154,6 +160,7 @@ public class GenericWebApplicationContext extends GenericApplicationContext @Override protected void onRefresh() { this.themeSource = UiApplicationContextUtils.initThemeSource(this); + this.getEnvironment().getPropertySources().push(new ServletContextPropertySource(servletContext)); } public Theme getTheme(String themeName) { diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/support/ServletConfigPropertySource.java b/org.springframework.web/src/main/java/org/springframework/web/context/support/ServletConfigPropertySource.java new file mode 100644 index 00000000000..61d8658d200 --- /dev/null +++ b/org.springframework.web/src/main/java/org/springframework/web/context/support/ServletConfigPropertySource.java @@ -0,0 +1,70 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context.support; + +import java.util.Enumeration; + +import javax.servlet.ServletConfig; + +import org.springframework.core.env.DefaultWebEnvironment; +import org.springframework.core.env.PropertySource; + + +/** + * TODO SPR-7508: document + * + * @author Chris Beams + * @since 3.1 + * @see ServletContextPropertySource + */ +public class ServletConfigPropertySource extends PropertySource { + + public ServletConfigPropertySource(ServletConfig servletConfig) { + this(DefaultWebEnvironment.SERVLET_CONFIG_PARAMS_PROPERTY_SOURCE_NAME, servletConfig); + } + + public ServletConfigPropertySource(String name, ServletConfig servletConfig) { + super(name, servletConfig); + } + + @Override + public boolean containsProperty(String name) { + Enumeration initParamNames = this.source.getInitParameterNames(); + while (initParamNames.hasMoreElements()) { + if (initParamNames.nextElement().equals(name)) { + return true; + } + } + return false; + } + + @Override + public String getProperty(String name) { + return this.source.getInitParameter(name); + } + + @Override + public int size() { + int size=0; + Enumeration initParamNames = this.source.getInitParameterNames(); + while (initParamNames.hasMoreElements()) { + initParamNames.nextElement(); + size++; + } + return size; + } +} diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/support/ServletContextPropertyPlaceholderConfigurer.java b/org.springframework.web/src/main/java/org/springframework/web/context/support/ServletContextPropertyPlaceholderConfigurer.java index 0e7254f68e0..3a35563168b 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/context/support/ServletContextPropertyPlaceholderConfigurer.java +++ b/org.springframework.web/src/main/java/org/springframework/web/context/support/ServletContextPropertyPlaceholderConfigurer.java @@ -21,8 +21,10 @@ import java.util.Properties; import javax.servlet.ServletContext; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; +import org.springframework.context.support.EnvironmentAwarePropertyPlaceholderConfigurer; import org.springframework.web.context.ServletContextAware; + /** * Subclass of PropertyPlaceholderConfigurer that resolves placeholders as * ServletContext init parameters (that is, web.xml context-param @@ -57,7 +59,10 @@ import org.springframework.web.context.ServletContextAware; * @see #setSearchContextAttributes * @see javax.servlet.ServletContext#getInitParameter(String) * @see javax.servlet.ServletContext#getAttribute(String) + * @deprecated in Spring 3.1 in favor of {@link EnvironmentAwarePropertyPlaceholderConfigurer} + * in conjunction with {@link org.springframework.core.env.DefaultWebEnvironment}. */ +@Deprecated public class ServletContextPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer implements ServletContextAware { diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/support/ServletContextPropertySource.java b/org.springframework.web/src/main/java/org/springframework/web/context/support/ServletContextPropertySource.java new file mode 100644 index 00000000000..8bcad5ab2f8 --- /dev/null +++ b/org.springframework.web/src/main/java/org/springframework/web/context/support/ServletContextPropertySource.java @@ -0,0 +1,70 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context.support; + +import java.util.Enumeration; + +import javax.servlet.ServletContext; + +import org.springframework.core.env.DefaultWebEnvironment; +import org.springframework.core.env.PropertySource; + + +/** + * TODO SPR-7508: document + * + * @author Chris Beams + * @since 3.1 + * @see ServletConfigPropertySource + */ +public class ServletContextPropertySource extends PropertySource { + + public ServletContextPropertySource(ServletContext servletContext) { + this(DefaultWebEnvironment.SERVLET_CONTEXT_PARAMS_PROPERTY_SOURCE_NAME, servletContext); + } + + public ServletContextPropertySource(String name, ServletContext servletContext) { + super(name, servletContext); + } + + @Override + public boolean containsProperty(String name) { + Enumeration initParamNames = this.source.getInitParameterNames(); + while (initParamNames.hasMoreElements()) { + if (initParamNames.nextElement().equals(name)) { + return true; + } + } + return false; + } + + @Override + public String getProperty(String name) { + return this.source.getInitParameter(name); + } + + @Override + public int size() { + int size=0; + Enumeration initParamNames = this.source.getInitParameterNames(); + while (initParamNames.hasMoreElements()) { + initParamNames.nextElement(); + size++; + } + return size; + } +} diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/support/StaticWebApplicationContext.java b/org.springframework.web/src/main/java/org/springframework/web/context/support/StaticWebApplicationContext.java index 740fb880203..60ff3d6655a 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/context/support/StaticWebApplicationContext.java +++ b/org.springframework.web/src/main/java/org/springframework/web/context/support/StaticWebApplicationContext.java @@ -16,11 +16,15 @@ package org.springframework.web.context.support; +import java.util.LinkedList; + import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.support.StaticApplicationContext; +import org.springframework.core.env.DefaultWebEnvironment; +import org.springframework.core.env.PropertySource; import org.springframework.core.io.Resource; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.ui.context.Theme; @@ -66,6 +70,7 @@ public class StaticWebApplicationContext extends StaticApplicationContext public StaticWebApplicationContext() { setDisplayName("Root WebApplicationContext"); + setEnvironment(new DefaultWebEnvironment()); // TODO SPR-7508: see GenericWebApplicationContext, AbstractRefreshableWebApplicationContext } @@ -164,6 +169,9 @@ public class StaticWebApplicationContext extends StaticApplicationContext @Override protected void onRefresh() { this.themeSource = UiApplicationContextUtils.initThemeSource(this); + LinkedList> propertySources = this.getEnvironment().getPropertySources(); + propertySources.push(new ServletContextPropertySource(servletContext)); + propertySources.push(new ServletConfigPropertySource(servletConfig)); } public Theme getTheme(String themeName) { diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/support/XmlWebApplicationContext.java b/org.springframework.web/src/main/java/org/springframework/web/context/support/XmlWebApplicationContext.java index 0290cb668a8..84d4b38f3cc 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/context/support/XmlWebApplicationContext.java +++ b/org.springframework.web/src/main/java/org/springframework/web/context/support/XmlWebApplicationContext.java @@ -84,6 +84,7 @@ public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationC // Configure the bean definition reader with this context's // resource loading environment. + beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); diff --git a/org.springframework.web/src/main/java/org/springframework/web/filter/GenericFilterBean.java b/org.springframework.web/src/main/java/org/springframework/web/filter/GenericFilterBean.java index 1572d63f3f7..288532600b8 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/filter/GenericFilterBean.java +++ b/org.springframework.web/src/main/java/org/springframework/web/filter/GenericFilterBean.java @@ -37,6 +37,9 @@ import org.springframework.beans.PropertyValues; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.EnvironmentAware; +import org.springframework.core.env.DefaultWebEnvironment; +import org.springframework.core.env.Environment; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceEditor; import org.springframework.core.io.ResourceLoader; @@ -74,7 +77,7 @@ import org.springframework.web.util.NestedServletException; * @see #doFilter */ public abstract class GenericFilterBean implements - Filter, BeanNameAware, ServletContextAware, InitializingBean, DisposableBean { + Filter, BeanNameAware, EnvironmentAware, ServletContextAware, InitializingBean, DisposableBean { /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); @@ -88,9 +91,15 @@ public abstract class GenericFilterBean implements /* The FilterConfig of this filter */ private FilterConfig filterConfig; - private String beanName; + /** + * TODO SPR-7508: document + * Defaults to {@link DefaultWebEnvironment}; can be overriden if deployed + * as a spring bean by {@link #setEnvironment(Environment)} + */ + private Environment environment = new DefaultWebEnvironment(); + private ServletContext servletContext; @@ -105,6 +114,13 @@ public abstract class GenericFilterBean implements this.beanName = beanName; } + /** + * TODO SPR-7508: document + */ + public void setEnvironment(Environment environment) { + this.environment = environment; + } + /** * Stores the ServletContext that the bean factory runs in. *

Only relevant in case of initialization as bean, to have a ServletContext @@ -164,7 +180,7 @@ public abstract class GenericFilterBean implements PropertyValues pvs = new FilterConfigPropertyValues(filterConfig, this.requiredProperties); BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); ResourceLoader resourceLoader = new ServletContextResourceLoader(filterConfig.getServletContext()); - bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader)); + bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment)); initBeanWrapper(bw); bw.setPropertyValues(pvs, true); } diff --git a/spring-framework.ipr b/spring-framework.ipr index b0aec2604d9..3b638343cda 100644 --- a/spring-framework.ipr +++ b/spring-framework.ipr @@ -953,6 +953,15 @@ + + + + + + + + + diff --git a/src/test/java/org/springframework/core/env/PropertyPlaceholderConfigurerEnvironmentIntegrationTests.java b/src/test/java/org/springframework/core/env/PropertyPlaceholderConfigurerEnvironmentIntegrationTests.java new file mode 100644 index 00000000000..89010245486 --- /dev/null +++ b/src/test/java/org/springframework/core/env/PropertyPlaceholderConfigurerEnvironmentIntegrationTests.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.env; + +import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; + +import org.junit.Test; +import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; +import org.springframework.context.support.GenericApplicationContext; + +public class PropertyPlaceholderConfigurerEnvironmentIntegrationTests { + @Test + public void test() { + GenericApplicationContext ctx = new GenericApplicationContext(); + ctx.registerBeanDefinition("ppc", + rootBeanDefinition(PropertyPlaceholderConfigurer.class) + .addPropertyValue("searchSystemEnvironment", false) + .getBeanDefinition()); + ctx.refresh(); + ctx.getBean("ppc"); + } +}