M1 cut of environment, profiles and property work (SPR-7508)
Decomposed Environment interface into PropertySources, PropertyResolver
objects
Environment interface and implementations are still present, but
simpler.
PropertySources container aggregates PropertySource objects;
PropertyResolver provides search, conversion, placeholder
replacement. Single implementation for now is
PropertySourcesPlaceholderResolver
Renamed EnvironmentAwarePropertyPlaceholderConfigurer to
PropertySourcesPlaceholderConfigurer
<context:property-placeholder/> now registers PSPC by default, else
PPC if systemPropertiesMode* settings are involved
Refined configuration and behavior of default profiles
See Environment interface Javadoc for details
Added Portlet implementations of relevant interfaces:
* DefaultPortletEnvironment
* PortletConfigPropertySource, PortletContextPropertySource
* Integrated each appropriately throughout Portlet app contexts
Added protected 'createEnvironment()' method to AbstractApplicationContext
Subclasses can override at will to supply a custom Environment
implementation. In practice throughout the framework, this is how
Web- and Portlet-related ApplicationContexts override use of the
DefaultEnvironment and swap in DefaultWebEnvironment or
DefaultPortletEnvironment as appropriate.
Introduced "stub-and-replace" behavior for Servlet- and Portlet-based
PropertySource implementations
Allows for early registration and ordering of the stub, then
replacement with actual backing object at refresh() time.
Added AbstractApplicationContext.initPropertySources() method to
support stub-and-replace behavior. Called from within existing
prepareRefresh() method so as to avoid impact with
ApplicationContext implementations that copy and modify AAC's
refresh() method (e.g.: Spring DM).
Added methods to WebApplicationContextUtils and
PortletApplicationContextUtils to support stub-and-replace behavior
Added comprehensive Javadoc for all new or modified types and members
Added XSD documentation for all new or modified elements and attributes
Including nested <beans>, <beans profile="..."/>, and changes for
certain attributes type from xsd:IDREF to xsd:string
Improved fix for detecting non-file based Resources in
PropertiesLoaderSupport (SPR-7547, SPR-7552)
Technically unrelated to environment work, but grouped in with
this changeset for convenience.
Deprecated (removed) context:property-placeholder
'system-properties-mode' attribute from spring-context-3.1.xsd
Functionality is preserved for those using schemas up to and including
spring-context-3.0. For 3.1, system-properties-mode is no longer
supported as it conflicts with the idea of managing a set of property
sources within the context's Environment object. See Javadoc in
PropertyPlaceholderConfigurer, AbstractPropertyPlaceholderConfigurer
and PropertySourcesPlaceholderConfigurer for details.
Introduced CollectionUtils.toArray(Enumeration<E>, A[])
Work items remaining for 3.1 M2:
Consider repackaging PropertySource* types; eliminate internal use
of SystemPropertyUtils and deprecate
Further work on composition of Environment interface; consider
repurposing existing PlaceholderResolver interface to obviate need
for resolve[Required]Placeholder() methods currently in Environment.
Ensure configurability of placeholder prefix, suffix, and value
separator when working against an AbstractPropertyResolver
Add JNDI-based Environment / PropertySource implementatinos
Consider support for @Profile at the @Bean level
Provide consistent logging for the entire property resolution
lifecycle; consider issuing all such messages against a dedicated
logger with a single category.
Add reference documentation to cover the featureset.
This commit is contained in:
parent
b130a36af7
commit
b3ff9be78f
|
|
@ -1,15 +1,17 @@
|
|||
target
|
||||
*.java.hsp
|
||||
*.sonarj
|
||||
*.sw*
|
||||
.DS_Store
|
||||
.settings
|
||||
.springBeans
|
||||
bin
|
||||
build.sh
|
||||
integration-repo
|
||||
ivy-cache
|
||||
jmx.log
|
||||
.springBeans
|
||||
.settings
|
||||
.DS_Store
|
||||
*.sw*
|
||||
org.springframework.test/test-output/
|
||||
org.springframework.jdbc/derby.log
|
||||
org.springframework.spring-parent/.classpath
|
||||
org.springframework.spring-parent/.project
|
||||
build.sh
|
||||
org.springframework.jdbc/derby.log
|
||||
org.springframework.test/test-output/
|
||||
spring-build
|
||||
target
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ public interface BeanFactory {
|
|||
/**
|
||||
* Return the bean instance that uniquely matches the given object type, if any.
|
||||
* @param requiredType type the bean must match; can be an interface or superclass.
|
||||
* {@literal null} is disallowed.
|
||||
* {@code null} is disallowed.
|
||||
* <p>This method goes into {@link ListableBeanFactory} by-type lookup territory
|
||||
* but may also be translated into a conventional by-name lookup based on the name
|
||||
* of the given type. For more extensive retrieval operations across sets of beans,
|
||||
|
|
|
|||
|
|
@ -432,7 +432,6 @@ 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 {
|
||||
|
|
|
|||
|
|
@ -29,26 +29,87 @@ import org.springframework.util.StringValueResolver;
|
|||
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document.
|
||||
* Abstract base class for property resource configurers that resolve placeholders
|
||||
* in bean definition property values. Implementations <em>pull</em> values from a
|
||||
* properties file or other {@linkplain org.springframework.core.env.PropertySource
|
||||
* property source} into bean definitions.
|
||||
*
|
||||
* <p>The default placeholder syntax follows the Ant / Log4J / JSP EL style:
|
||||
*
|
||||
*<pre class="code">${...}</pre>
|
||||
*
|
||||
* Example XML bean definition:
|
||||
*
|
||||
*<pre class="code">{@code
|
||||
*<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"/>
|
||||
* <property name="driverClassName" value="}${driver}{@code"/>
|
||||
* <property name="url" value="jdbc:}${dbname}{@code"/>
|
||||
*</bean>
|
||||
*}</pre>
|
||||
*
|
||||
* Example properties file:
|
||||
*
|
||||
* <pre class="code"> driver=com.mysql.jdbc.Driver
|
||||
* dbname=mysql:mydb</pre>
|
||||
*
|
||||
* Annotated bean definitions may take advantage of property replacement using
|
||||
* the {@link org.springframework.beans.factory.annotation.Value @Value} annotation:
|
||||
*
|
||||
*<pre class="code">@Value("${person.age}")</pre>
|
||||
*
|
||||
* Implementations check simple property values, lists, maps, props, and bean names
|
||||
* in bean references. Furthermore, placeholder values can also cross-reference
|
||||
* other placeholders, like:
|
||||
*
|
||||
*<pre class="code">rootPath=myrootdir
|
||||
*subPath=${rootPath}/subdir</pre>
|
||||
*
|
||||
* In contrast to {@link PropertyOverrideConfigurer}, subclasses of this type allow
|
||||
* filling in of explicit placeholders in bean definitions.
|
||||
*
|
||||
* <p>If a configurer cannot resolve a placeholder, a {@link BeanDefinitionStoreException}
|
||||
* will be thrown. If you want to check against multiple properties files, specify multiple
|
||||
* resources via the {@link #setLocations locations} property. You can also define multiple
|
||||
* configurers, each with its <em>own</em> placeholder syntax. Use {@link
|
||||
* #ignoreUnresolvablePlaceholders} to intentionally suppress throwing an exception if a
|
||||
* placeholder cannot be resolved.
|
||||
*
|
||||
* <p>Default property values can be defined globally for each configurer instance
|
||||
* via the {@link #setProperties properties} property, or on a property-by-property basis
|
||||
* using the default value separator which is {@code ":"} by default and
|
||||
* customizable via {@link #setValueSeparator(String)}.
|
||||
*
|
||||
* <p>Example XML property with default value:
|
||||
*
|
||||
*<pre class="code">{@code
|
||||
* <property name="url" value="jdbc:}${dbname:defaultdb}{@code"/>
|
||||
*}</pre>
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
* @see PropertyPlaceholderConfigurer
|
||||
* @see org.springframework.context.support.PropertySourcesPlaceholderConfigurer
|
||||
*/
|
||||
public abstract class AbstractPropertyPlaceholderConfigurer extends PropertyResourceConfigurer
|
||||
implements BeanNameAware, BeanFactoryAware {
|
||||
|
||||
/** Default placeholder prefix: "${" */
|
||||
/** Default placeholder prefix: {@value} */
|
||||
public static final String DEFAULT_PLACEHOLDER_PREFIX = "${";
|
||||
/** Default placeholder suffix: "}" */
|
||||
|
||||
/** Default placeholder suffix: {@value} */
|
||||
public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";
|
||||
/** Default value separator: ":" */
|
||||
|
||||
/** Default value separator: {@value} */
|
||||
public static final String DEFAULT_VALUE_SEPARATOR = ":";
|
||||
|
||||
/** Defaults to {@value #DEFAULT_PLACEHOLDER_PREFIX} */
|
||||
protected String placeholderPrefix = DEFAULT_PLACEHOLDER_PREFIX;
|
||||
|
||||
/** Defaults to {@value #DEFAULT_PLACEHOLDER_SUFFIX} */
|
||||
protected String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX;
|
||||
|
||||
/** Defaults to {@value #DEFAULT_VALUE_SEPARATOR} */
|
||||
protected String valueSeparator = DEFAULT_VALUE_SEPARATOR;
|
||||
|
||||
protected boolean ignoreUnresolvablePlaceholders = false;
|
||||
|
|
@ -60,12 +121,14 @@ public abstract class AbstractPropertyPlaceholderConfigurer extends PropertyReso
|
|||
private BeanFactory beanFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Return the {@code PlaceholderResolver} for this configurer.
|
||||
*/
|
||||
protected abstract PlaceholderResolver getPlaceholderResolver(Properties props);
|
||||
|
||||
/**
|
||||
* Set the prefix that a placeholder string starts with.
|
||||
* The default is "${".
|
||||
* @see #DEFAULT_PLACEHOLDER_PREFIX
|
||||
* The default is {@value #DEFAULT_PLACEHOLDER_PREFIX}.
|
||||
*/
|
||||
public void setPlaceholderPrefix(String placeholderPrefix) {
|
||||
this.placeholderPrefix = placeholderPrefix;
|
||||
|
|
@ -73,8 +136,7 @@ public abstract class AbstractPropertyPlaceholderConfigurer extends PropertyReso
|
|||
|
||||
/**
|
||||
* Set the suffix that a placeholder string ends with.
|
||||
* The default is "}".
|
||||
* @see #DEFAULT_PLACEHOLDER_SUFFIX
|
||||
* The default is {@value #DEFAULT_PLACEHOLDER_SUFFIX}.
|
||||
*/
|
||||
public void setPlaceholderSuffix(String placeholderSuffix) {
|
||||
this.placeholderSuffix = placeholderSuffix;
|
||||
|
|
@ -82,22 +144,22 @@ public abstract class AbstractPropertyPlaceholderConfigurer extends PropertyReso
|
|||
|
||||
/**
|
||||
* Specify the separating character between the placeholder variable
|
||||
* and the associated default value, or <code>null</code> if no such
|
||||
* and the associated default value, or {@code null} if no such
|
||||
* special character should be processed as a value separator.
|
||||
* The default is ":".
|
||||
* The default is {@value #DEFAULT_VALUE_SEPARATOR}.
|
||||
*/
|
||||
public void setValueSeparator(String valueSeparator) {
|
||||
this.valueSeparator = valueSeparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value that should be treated as <code>null</code> when
|
||||
* Set a value that should be treated as {@code null} when
|
||||
* resolved as a placeholder value: e.g. "" (empty String) or "null".
|
||||
* <p>Note that this will only apply to full property values,
|
||||
* not to parts of concatenated values.
|
||||
* <p>By default, no such null value is defined. This means that
|
||||
* there is no way to express <code>null</code> as a property
|
||||
* value unless you explictly map a corresponding value here.
|
||||
* there is no way to express {@code null} as a property
|
||||
* value unless you explicitly map a corresponding value here.
|
||||
*/
|
||||
public void setNullValue(String nullValue) {
|
||||
this.nullValue = nullValue;
|
||||
|
|
@ -139,6 +201,10 @@ public abstract class AbstractPropertyPlaceholderConfigurer extends PropertyReso
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Visit each bean definition in the given bean factory and attempt to replace ${...} property
|
||||
* placeholders with values from the given properties.
|
||||
*/
|
||||
@Override
|
||||
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
|
||||
throws BeansException {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 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.
|
||||
|
|
@ -25,69 +25,40 @@ import org.springframework.core.Constants;
|
|||
import org.springframework.util.PropertyPlaceholderHelper;
|
||||
import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
|
||||
|
||||
|
||||
/**
|
||||
* A property resource configurer that resolves placeholders in bean property values of
|
||||
* context definitions. It <i>pulls</i> values from a properties file into bean definitions.
|
||||
* {@link AbstractPropertyPlaceholderConfigurer} subclass that resolves ${...} placeholders
|
||||
* against {@link #setLocation local} {@link #setProperties properties} and/or system properties
|
||||
* and environment variables.
|
||||
*
|
||||
* <p>The default placeholder syntax follows the Ant / Log4J / JSP EL style:
|
||||
* <p>As of Spring 3.1, {@link org.springframework.context.support.PropertySourcesPlaceholderConfigurer
|
||||
* PropertySourcesPlaceholderConfigurer} should be used preferentially over this implementation; it is
|
||||
* more flexible through taking advantage of the {@link org.springframework.core.env.Environment Environment} and
|
||||
* {@link org.springframework.core.env.PropertySource PropertySource} mechanisms also made available in Spring 3.1.
|
||||
*
|
||||
* <pre class="code">${...}</pre>
|
||||
* <p>{@link PropertyPlaceholderConfigurer} is still appropriate for use when:
|
||||
* <ul>
|
||||
* <li>the {@link org.springframework.context spring-context} module is not available (i.e., one is using
|
||||
* Spring's {@code BeanFactory} API as opposed to {@code ApplicationContext}).
|
||||
* <li>existing configuration makes use of the {@link #setSystemPropertiesMode(int) "systemPropertiesMode"} and/or
|
||||
* {@link #setSystemPropertiesModeName(String) "systemPropertiesModeName"} properties. Users are encouraged to move
|
||||
* away from using these settings, and rather configure property source search order through the container's
|
||||
* {@code Environment}; however, exact preservation of functionality may be maintained by continuing to
|
||||
* use {@code PropertyPlaceholderConfigurer}.
|
||||
* </ul>
|
||||
*
|
||||
* Example XML context definition:
|
||||
*
|
||||
* <pre class="code"><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
||||
* <property name="driverClassName"><value>${driver}</value></property>
|
||||
* <property name="url"><value>jdbc:${dbname}</value></property>
|
||||
* </bean></pre>
|
||||
*
|
||||
* Example properties file:
|
||||
*
|
||||
* <pre class="code">driver=com.mysql.jdbc.Driver
|
||||
* dbname=mysql:mydb</pre>
|
||||
*
|
||||
* PropertyPlaceholderConfigurer checks simple property values, lists, maps,
|
||||
* props, and bean names in bean references. Furthermore, placeholder values can
|
||||
* also cross-reference other placeholders, like:
|
||||
*
|
||||
* <pre class="code">rootPath=myrootdir
|
||||
* subPath=${rootPath}/subdir</pre>
|
||||
*
|
||||
* In contrast to PropertyOverrideConfigurer, this configurer allows to fill in
|
||||
* explicit placeholders in context definitions. Therefore, the original definition
|
||||
* cannot specify any default values for such bean properties, and the placeholder
|
||||
* properties file is supposed to contain an entry for each defined placeholder.
|
||||
*
|
||||
* <p>If a configurer cannot resolve a placeholder, a BeanDefinitionStoreException
|
||||
* will be thrown. If you want to check against multiple properties files, specify
|
||||
* multiple resources via the "locations" setting. You can also define multiple
|
||||
* PropertyPlaceholderConfigurers, each with its <i>own</i> placeholder syntax.
|
||||
*
|
||||
* <p>Default property values can be defined via "properties", to make overriding
|
||||
* definitions in properties files optional. A configurer will also check against
|
||||
* system properties (e.g. "user.dir") if it cannot resolve a placeholder with any
|
||||
* of the specified properties. This can be customized via "systemPropertiesMode".
|
||||
*
|
||||
* <p>Note that the context definition <i>is</i> aware of being incomplete;
|
||||
* this is immediately obvious to users when looking at the XML definition file.
|
||||
* Hence, placeholders have to be resolved; any desired defaults have to be
|
||||
* defined as placeholder values as well (for example in a default properties file).
|
||||
*
|
||||
* <p>Property values can be converted after reading them in, through overriding
|
||||
* the {@link #convertPropertyValue} method. For example, encrypted values can
|
||||
* be detected and decrypted accordingly before processing them.
|
||||
* <p>Prior to Spring 3.1, the {@code <context:property-placeholder/>} namespace element
|
||||
* registered an instance of {@code PropertyPlaceholderConfigurer}. It will still do so if
|
||||
* using the {@code spring-beans-3.0.xsd} definition of the namespace. That is, you can preserve
|
||||
* registration of {@code PropertyPlaceholderConfigurer} through the namespace, even if using Spring 3.1;
|
||||
* simply do not update your {@code xsi:schemaLocation} and continue using the 3.0 XSD.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @since 02.10.2003
|
||||
* @see #setLocations
|
||||
* @see #setProperties
|
||||
* @see #setPlaceholderPrefix
|
||||
* @see #setPlaceholderSuffix
|
||||
* @see #setSystemPropertiesModeName
|
||||
* @see System#getProperty(String)
|
||||
* @see #convertPropertyValue
|
||||
* @see AbstractPropertyPlaceholderConfigurer
|
||||
* @see PropertyOverrideConfigurer
|
||||
* @see org.springframework.context.support.PropertySourcesPlaceholderConfigurer
|
||||
*/
|
||||
public class PropertyPlaceholderConfigurer extends AbstractPropertyPlaceholderConfigurer
|
||||
implements BeanNameAware, BeanFactoryAware {
|
||||
|
|
|
|||
|
|
@ -55,15 +55,24 @@ public abstract class PropertyResourceConfigurer extends PropertiesLoaderSupport
|
|||
private int order = Ordered.LOWEST_PRECEDENCE; // default: same as non-Ordered
|
||||
|
||||
|
||||
/**
|
||||
* Set the order value of this object for sorting purposes.
|
||||
* @see PriorityOrdered
|
||||
*/
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
return this.order;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@linkplain #mergeProperties Merge}, {@linkplain #convertProperties convert} and
|
||||
* {@linkplain #processProperties process} properties against the given bean factory.
|
||||
* @throws BeanInitializationException if any properties cannot be loaded
|
||||
*/
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
try {
|
||||
Properties mergedProps = mergeProperties();
|
||||
|
|
@ -88,7 +97,7 @@ public abstract class PropertyResourceConfigurer extends PropertiesLoaderSupport
|
|||
* @see #processProperties
|
||||
*/
|
||||
protected void convertProperties(Properties props) {
|
||||
Enumeration propertyNames = props.propertyNames();
|
||||
Enumeration<?> propertyNames = props.propertyNames();
|
||||
while (propertyNames.hasMoreElements()) {
|
||||
String propertyName = (String) propertyNames.nextElement();
|
||||
String propertyValue = props.getProperty(propertyName);
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import org.springframework.util.Assert;
|
|||
* and the class loader to use for loading bean classes.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @since 11.12.2003
|
||||
* @see BeanDefinitionReaderUtils
|
||||
*/
|
||||
|
|
@ -140,16 +141,14 @@ public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable
|
|||
}
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
* @param environment
|
||||
* Set the Environment to use when reading bean definitions. Most often used
|
||||
* for evaluating profile information to determine which bean definitions
|
||||
* should be read and which should be omitted.
|
||||
*/
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
*/
|
||||
public Environment getEnvironment() {
|
||||
return this.environment;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,6 @@ 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;
|
||||
|
|
@ -170,8 +169,6 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
|
||||
new NamedThreadLocal<Object>("Prototype beans currently in creation");
|
||||
|
||||
private ConfigurableEnvironment environment = new DefaultEnvironment();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new AbstractBeanFactory.
|
||||
|
|
|
|||
|
|
@ -33,8 +33,6 @@ 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;
|
||||
|
||||
/**
|
||||
|
|
@ -61,9 +59,6 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
|
|||
/** Map from bean name to bean instance */
|
||||
private final Map<String, Object> beans = new HashMap<String, Object>();
|
||||
|
||||
/** TODO SPR-7508: document */
|
||||
private ConfigurableEnvironment environment = new DefaultEnvironment();
|
||||
|
||||
|
||||
/**
|
||||
* Add a new singleton bean.
|
||||
|
|
|
|||
|
|
@ -16,9 +16,10 @@
|
|||
|
||||
package org.springframework.beans.factory.xml;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
/**
|
||||
* SPI for parsing an XML document that contains Spring bean definitions.
|
||||
|
|
@ -46,4 +47,11 @@ public interface BeanDefinitionDocumentReader {
|
|||
void registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
|
||||
throws BeanDefinitionStoreException;
|
||||
|
||||
/**
|
||||
* Set the Environment to use when reading bean definitions. Used for evaluating
|
||||
* profile information to determine whether a {@code <beans/>} document/element should
|
||||
* be included or omitted.
|
||||
*/
|
||||
void setEnvironment(Environment environment);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1476,7 +1476,7 @@ public class BeanDefinitionParserDelegate {
|
|||
/**
|
||||
* Determine whether the name of the supplied node is equal to the supplied name.
|
||||
* <p>The default implementation checks the supplied desired name against both
|
||||
* {@link Node#getNodeName()) and {@link Node#getLocalName()}.
|
||||
* {@link Node#getNodeName()} and {@link Node#getLocalName()}.
|
||||
* <p>Subclasses may override the default implementation to provide a different
|
||||
* mechanism for comparing node names.
|
||||
* @param node the node to compare
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ 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.Assert;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
|
@ -88,18 +89,21 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
|
|||
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
* @param environment
|
||||
* {@inheritDoc}
|
||||
* <p>Default value is {@code null}; property is required for parsing any
|
||||
* {@code <beans/>} element with a {@code profile} attribute present.
|
||||
* @see #doRegisterBeanDefinitions
|
||||
*/
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses bean definitions according to the "spring-beans" DTD. TODO SPR-7508 XSD
|
||||
* {@inheritDoc}
|
||||
* <p>This implementation parses bean definitions according to the "spring-beans" XSD
|
||||
* (or DTD, historically).
|
||||
* <p>Opens a DOM Document; then initializes the default settings
|
||||
* specified at <code><beans></code> level; then parses
|
||||
* the contained bean definitions.
|
||||
* specified at the {@code <beans/>} level; then parses the contained bean definitions.
|
||||
*/
|
||||
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
|
||||
this.readerContext = readerContext;
|
||||
|
|
@ -110,17 +114,24 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
|
|||
doRegisterBeanDefinitions(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register each bean definition within the given root {@code <beans/>} element.
|
||||
* @throws IllegalStateException if {@code <beans profile="..."} attribute is present
|
||||
* and Environment property has not been set
|
||||
* @see #setEnvironment
|
||||
*/
|
||||
protected void doRegisterBeanDefinitions(Element root) {
|
||||
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
|
||||
if (StringUtils.hasText(profileSpec)) {
|
||||
Assert.state(this.environment != null, "environment property must not be null");
|
||||
String[] specifiedProfiles = commaDelimitedListToStringArray(trimAllWhitespace(profileSpec));
|
||||
if (!this.environment.acceptsProfiles(specifiedProfiles)) {
|
||||
// TODO SPR-7508: log that this bean is being rejected on profile mismatch
|
||||
return;
|
||||
}
|
||||
if (!this.environment.acceptsProfiles(specifiedProfiles)) {
|
||||
// TODO SPR-7508: log that this bean is being rejected on profile mismatch
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// any nested <beans> elements will cause recursion in this method. in
|
||||
// any nested <beans> elements will cause recursion in this method. In
|
||||
// order to propagate and preserve <beans> 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,
|
||||
|
|
@ -212,7 +223,7 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
|
|||
}
|
||||
|
||||
// Resolve system properties: e.g. "${user.dir}"
|
||||
location = environment.resolveRequiredPlaceholders(location);
|
||||
location = environment.getPropertyResolver().resolveRequiredPlaceholders(location);
|
||||
|
||||
Set<Resource> actualResources = new LinkedHashSet<Resource>(4);
|
||||
|
||||
|
|
|
|||
|
|
@ -487,12 +487,8 @@ public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
|
|||
* @see BeanDefinitionDocumentReader#registerBeanDefinitions
|
||||
*/
|
||||
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
|
||||
// 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());
|
||||
}
|
||||
documentReader.setEnvironment(this.getEnvironment());
|
||||
int countBefore = getRegistry().getBeanDefinitionCount();
|
||||
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
|
||||
return getRegistry().getBeanDefinitionCount() - countBefore;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2011 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.
|
||||
|
|
@ -19,7 +19,6 @@ 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;
|
||||
|
||||
/**
|
||||
|
|
@ -35,7 +34,8 @@ import org.springframework.core.io.Resource;
|
|||
* <p>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. // TODO SPR-7508 polish - s/dtd/xsd/
|
||||
* See {@code "spring-beans-3.x.xsd"} (or historically, {@code "spring-beans-2.0.dtd"}) for
|
||||
* details on options and configuration style.
|
||||
*
|
||||
* <p><b>For advanced needs, consider using a {@link DefaultListableBeanFactory} with
|
||||
* an {@link XmlBeanDefinitionReader}.</b> The latter allows for reading from multiple XML
|
||||
|
|
@ -63,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, (BeanFactory)null);
|
||||
this(resource, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -36,8 +36,6 @@
|
|||
|
||||
There is also support for lists, sets, maps, and java.util.Properties
|
||||
as bean property types or constructor argument types.
|
||||
|
||||
TODO:SPR-7508: Document use of nested beans elements.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
|
|
@ -63,8 +61,11 @@
|
|||
<xsd:element name="beans">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The top level (typically root) element. Allows the definition
|
||||
of default values for all nested bean definitions.
|
||||
Container for <bean> and other elements, typically the root element in the document.
|
||||
Allows the definition of default values for all nested bean definitions. May itself
|
||||
be nested for the purpose of defining a subset of beans with certain default values or
|
||||
to be registered only when certain profile(s) are active. Any such nested <beans> element
|
||||
must be declared as the last element in the document.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
|
|
@ -81,16 +82,20 @@
|
|||
<xsd:attribute name="profile" use="optional" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
TODO:SPR-7508: Document profile annotation:
|
||||
* may be comma-delimited
|
||||
* empty profile means beans will always be registered
|
||||
* ConfigurableEnvironment.setActiveProfiles(String...) sets which profiles are active
|
||||
* 'spring.profile.active' sets which profiles are active (typically as a -D system property)
|
||||
servlet context/init param)
|
||||
* ConfigurableEnvironment.setDefaultProfiles(String...) or 'spring.profile.default' property specifies one
|
||||
or more default profiles, e.g., 'default'
|
||||
* if 'default' is specified as a default profile, `profile="xyz,default"` means that beans will be
|
||||
registered if 'xyz' is active or if no profile is active
|
||||
The set of profiles for which this <beans> element may be parsed. May be a comma-delimited
|
||||
list in the case of multiple profiles. If one or more of the specified profiles are active at time
|
||||
of parsing, the <beans> element will be parsed, and all of its <bean> elements registered,
|
||||
<import> elements followed, etc. If none of the specified profiles are active at time of parsing,
|
||||
then the entire element and its contents will be ignored.
|
||||
|
||||
Profiles are activated in one of two ways:
|
||||
Programmatic:
|
||||
ConfigurableEnvironment#setActiveProfiles(String...)
|
||||
ConfigurableEnvironment#setDefaultProfiles(String...)
|
||||
|
||||
Properties (typically through -D system properties, environment variables, or servlet context init params):
|
||||
spring.profile.active=p1,p2
|
||||
spring.profile.default=p1,p2
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
|
@ -115,7 +120,7 @@
|
|||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The default 'autowire' value; see the documentation for the
|
||||
'autowire' attribute of the 'bean' element. The default is 'no'.
|
||||
'autowire' attribute of the 'bean' element. The default is 'default'.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ 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.genericBeanDefinition;
|
||||
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition;
|
||||
import static org.springframework.beans.factory.support.BeanDefinitionReaderUtils.registerWithGeneratedName;
|
||||
|
||||
|
|
@ -33,13 +34,16 @@ 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.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import test.beans.TestBean;
|
||||
|
||||
|
||||
/**
|
||||
* Unit tests for {@link EnvironmentAwarePropertyPlaceholderConfigurer}.
|
||||
* Unit tests for {@link PropertyPlaceholderConfigurer}.
|
||||
*
|
||||
* @see PropertySourcesPlaceholderConfigurerTests
|
||||
* @see PropertyResourceConfigurerTests
|
||||
* @author Chris Beams
|
||||
*/
|
||||
|
|
@ -50,7 +54,7 @@ public class PropertyPlaceholderConfigurerTests {
|
|||
private static final String P1_SYSTEM_ENV_VAL = "p1SystemEnvVal";
|
||||
|
||||
private DefaultListableBeanFactory bf;
|
||||
private AbstractPropertyPlaceholderConfigurer ppc;
|
||||
private PropertyPlaceholderConfigurer ppc;
|
||||
private Properties ppcProperties;
|
||||
|
||||
private AbstractBeanDefinition p1BeanDef;
|
||||
|
|
@ -79,9 +83,19 @@ public class PropertyPlaceholderConfigurerTests {
|
|||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Tests to ensure backward-compatibility for Environment refactoring
|
||||
// -------------------------------------------------------------------------
|
||||
@Test
|
||||
public void localPropertiesViaResource() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.registerBeanDefinition("testBean",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${my.name}")
|
||||
.getBeanDefinition());
|
||||
|
||||
PropertyPlaceholderConfigurer pc = new PropertyPlaceholderConfigurer();
|
||||
Resource resource = new ClassPathResource("PropertyPlaceholderConfigurerTests.properties", this.getClass());
|
||||
pc.setLocation(resource);
|
||||
pc.postProcessBeanFactory(bf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveFromSystemProperties() {
|
||||
|
|
@ -115,7 +129,6 @@ public class PropertyPlaceholderConfigurerTests {
|
|||
assertThat(bean.getName(), equalTo(P1_LOCAL_PROPS_VAL));
|
||||
}
|
||||
|
||||
/*
|
||||
@Test
|
||||
public void setSystemSystemPropertiesMode_toOverride_andResolveFromSystemProperties() {
|
||||
registerWithGeneratedName(p1BeanDef, bf);
|
||||
|
|
@ -145,7 +158,6 @@ public class PropertyPlaceholderConfigurerTests {
|
|||
TestBean bean = bf.getBean(TestBean.class);
|
||||
assertThat(bean.getName(), equalTo(P1_LOCAL_PROPS_VAL)); // has to resort to local props
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a scenario in which two PPCs are configured, each with different
|
||||
|
|
@ -231,34 +243,6 @@ public class PropertyPlaceholderConfigurerTests {
|
|||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 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<String, String> getModifiableSystemEnvironment() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
my.name=foo
|
||||
|
|
@ -800,7 +800,7 @@ public final class PropertyResourceConfigurerTests {
|
|||
Preferences.systemRoot().node("mySystemPath/mypath").remove("myName");
|
||||
}
|
||||
|
||||
/* TODO SPR-7508: uncomment after EnvironmentAwarePropertyPlaceholderConfigurer implementation
|
||||
/* TODO SPR-7508: uncomment after PropertySourcesPlaceholderConfigurer implementation
|
||||
@Test
|
||||
public void testPreferencesPlaceholderConfigurerWithCustomPropertiesInEnvironment() {
|
||||
factory.registerBeanDefinition("tb",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 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.
|
||||
|
|
@ -96,12 +96,13 @@ public interface ConfigurableApplicationContext extends ApplicationContext, Life
|
|||
void setParent(ApplicationContext parent);
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
* Return the Environment for this application context in configurable form.
|
||||
*/
|
||||
ConfigurableEnvironment getEnvironment();
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
* Set the {@code Environment} for this application context.
|
||||
* @param environment the new environment
|
||||
*/
|
||||
void setEnvironment(ConfigurableEnvironment environment);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,12 +19,17 @@ package org.springframework.context;
|
|||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
* TODO SPR-7515: document
|
||||
* Interface to be implemented by any bean that wishes to be notified
|
||||
* of the {@link Environment} that it runs in.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface EnvironmentAware {
|
||||
|
||||
/**
|
||||
* Set the {@code Environment} that this object runs in.
|
||||
*/
|
||||
void setEnvironment(Environment environment);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 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.
|
||||
|
|
@ -50,9 +50,9 @@ public class AnnotatedBeanDefinitionReader {
|
|||
|
||||
|
||||
/**
|
||||
* Create a new AnnotatedBeanDefinitionReader for the given bean factory.
|
||||
* @param registry the BeanFactory to load bean definitions into,
|
||||
* in the form of a BeanDefinitionRegistry
|
||||
* Create a new {@code AnnotatedBeanDefinitionReader} for the given bean factory.
|
||||
* @param registry the {@code BeanFactory} to load bean definitions into,
|
||||
* in the form of a {@code BeanDefinitionRegistry}
|
||||
*/
|
||||
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
|
||||
this.registry = registry;
|
||||
|
|
@ -68,8 +68,10 @@ public class AnnotatedBeanDefinitionReader {
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the Environment to use when registering classes.
|
||||
* Set the Environment to use when evaluating whether
|
||||
* {@link Profile @Profile}-annotated component classes should be registered.
|
||||
* <p>The default is a {@link DefaultEnvironment}.
|
||||
* @see #registerBean(Class, String, Class...)
|
||||
*/
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
|
|
@ -80,7 +82,8 @@ public class AnnotatedBeanDefinitionReader {
|
|||
* <p>The default is a {@link AnnotationBeanNameGenerator}.
|
||||
*/
|
||||
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
|
||||
this.beanNameGenerator = (beanNameGenerator != null ? beanNameGenerator : new AnnotationBeanNameGenerator());
|
||||
this.beanNameGenerator = (beanNameGenerator != null ?
|
||||
beanNameGenerator : new AnnotationBeanNameGenerator());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -88,7 +91,8 @@ public class AnnotatedBeanDefinitionReader {
|
|||
* <p>The default is an {@link AnnotationScopeMetadataResolver}.
|
||||
*/
|
||||
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
|
||||
this.scopeMetadataResolver = (scopeMetadataResolver != null ? scopeMetadataResolver : new AnnotationScopeMetadataResolver());
|
||||
this.scopeMetadataResolver = (scopeMetadataResolver != null ?
|
||||
scopeMetadataResolver : new AnnotationScopeMetadataResolver());
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -110,10 +114,8 @@ public class AnnotatedBeanDefinitionReader {
|
|||
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
|
||||
AnnotationMetadata metadata = abd.getMetadata();
|
||||
|
||||
if (metadata.hasAnnotation(Profile.class.getName())) {
|
||||
String[] specifiedProfiles =
|
||||
(String[])metadata.getAnnotationAttributes(Profile.class.getName()).get(Profile.CANDIDATE_PROFILES_ATTRIB_NAME);
|
||||
if (!this.environment.acceptsProfiles(specifiedProfiles)) {
|
||||
if (Profile.Helper.isProfileAnnotationPresent(metadata)) {
|
||||
if (!this.environment.acceptsProfiles(Profile.Helper.getCandidateProfiles(metadata))) {
|
||||
// TODO SPR-7508: log that this bean is being rejected on profile mismatch
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,17 +16,15 @@
|
|||
|
||||
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
|
||||
* {@link org.springframework.context.annotation.Configuration @Configuration}-annotated
|
||||
* classes, but also plain {@link org.springframework.stereotype.Component @Components}
|
||||
* and JSR-330 compliant classes using {@literal javax.inject} annotations. Allows for
|
||||
* and JSR-330 compliant classes using {@code javax.inject} annotations. Allows for
|
||||
* registering classes one by one ({@link #register}) as well as for classpath scanning
|
||||
* ({@link #scan}).
|
||||
*
|
||||
|
|
@ -49,15 +47,13 @@ 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
|
||||
* through {@link #register} calls and then manually {@link #refresh refreshed}.
|
||||
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
|
||||
*/
|
||||
public AnnotationConfigApplicationContext() {
|
||||
this.delegateEnvironment(super.getEnvironment());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -67,6 +63,7 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
|
|||
* e.g. {@link Configuration @Configuration} classes
|
||||
*/
|
||||
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
|
||||
this();
|
||||
register(annotatedClasses);
|
||||
refresh();
|
||||
}
|
||||
|
|
@ -77,16 +74,24 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
|
|||
* @param basePackages the packages to check for annotated classes
|
||||
*/
|
||||
public AnnotationConfigApplicationContext(String... basePackages) {
|
||||
this();
|
||||
scan(basePackages);
|
||||
refresh();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
* {@inheritDoc}
|
||||
* <p>Delegates given environment to underlying {@link AnnotatedBeanDefinitionReader}
|
||||
* and {@link ClassPathBeanDefinitionScanner} members.
|
||||
*/
|
||||
@Override
|
||||
public void setEnvironment(ConfigurableEnvironment environment) {
|
||||
super.setEnvironment(environment);
|
||||
delegateEnvironment(environment);
|
||||
}
|
||||
|
||||
private void delegateEnvironment(ConfigurableEnvironment environment) {
|
||||
this.reader.setEnvironment(environment);
|
||||
this.scanner.setEnvironment(environment);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,11 +27,11 @@ import org.springframework.beans.factory.annotation.Autowire;
|
|||
/**
|
||||
* Indicates that a method produces a bean to be managed by the Spring container. The
|
||||
* names and semantics of the attributes to this annotation are intentionally similar
|
||||
* to those of the {@literal <bean/>} element in the Spring XML schema.
|
||||
* to those of the {@code <bean/>} element in the Spring XML schema.
|
||||
*
|
||||
* <p>Note that the <code>@Bean</code> annotation does not provide attributes for scope,
|
||||
* primary or lazy. Rather, it should be used in conjunction with {@link Scope @Scope},
|
||||
* {@link Primary @Primary}, and {@link Lazy @Lazy} annotations to achieve
|
||||
* <p>Note that the {@code @Bean} annotation does not provide attributes for scope,
|
||||
* primary or lazy. Rather, it should be used in conjunction with {@link Scope @Scope},
|
||||
* {@link Primary @Primary}, and {@link Lazy @Lazy} annotations to achieve
|
||||
* those semantics. The same annotations can also be used at the type level, e.g. for
|
||||
* component scanning.
|
||||
*
|
||||
|
|
@ -96,7 +96,7 @@ public @interface Bean {
|
|||
|
||||
/**
|
||||
* The optional name of a method to call on the bean instance upon closing the
|
||||
* application context, for example a {@literal close()} method on a {@literal DataSource}.
|
||||
* application context, for example a {@code close()} method on a {@code DataSource}.
|
||||
* The method must have no arguments but may throw any exception.
|
||||
* <p>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
|
||||
|
|
|
|||
|
|
@ -116,15 +116,15 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
|||
}
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
* Set the Environment to use when resolving placeholders and evaluating
|
||||
* {@link Profile @Profile}-annotated component classes.
|
||||
* <p>The default is a {@link DefaultEnvironment}
|
||||
* @param environment the Environment to use
|
||||
*/
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
*/
|
||||
public Environment getEnvironment() {
|
||||
return this.environment;
|
||||
}
|
||||
|
|
@ -280,7 +280,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
|||
* @return the pattern specification to be used for package searching
|
||||
*/
|
||||
protected String resolveBasePackage(String basePackage) {
|
||||
return ClassUtils.convertClassNameToResourcePath(environment.resolveRequiredPlaceholders(basePackage));
|
||||
return ClassUtils.convertClassNameToResourcePath(environment.getPropertyResolver().resolveRequiredPlaceholders(basePackage));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -298,12 +298,11 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
|||
for (TypeFilter tf : this.includeFilters) {
|
||||
if (tf.match(metadataReader, this.metadataReaderFactory)) {
|
||||
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
|
||||
if (!metadata.hasAnnotation(Profile.class.getName())) {
|
||||
if (!Profile.Helper.isProfileAnnotationPresent(metadata)) {
|
||||
return true;
|
||||
}
|
||||
String[] specifiedProfiles =
|
||||
(String[])metadata.getAnnotationAttributes(Profile.class.getName()).get(Profile.CANDIDATE_PROFILES_ATTRIB_NAME);
|
||||
return this.environment.acceptsProfiles(specifiedProfiles);
|
||||
// TODO SPR-7508: log that this bean is being rejected on profile mismatch
|
||||
return this.environment.acceptsProfiles(Profile.Helper.getCandidateProfiles(metadata));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ 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.
|
||||
* {@code <context:component-scan>} element.
|
||||
*
|
||||
* TODO SPR-7508: complete documentation.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -101,16 +101,14 @@ class ConfigurationClassParser {
|
|||
}
|
||||
|
||||
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
|
||||
if (this.environment != null && configClass.getMetadata().hasAnnotation(Profile.class.getName())) {
|
||||
String[] specifiedProfiles =
|
||||
(String[])configClass.getMetadata().getAnnotationAttributes(Profile.class.getName()).get(Profile.CANDIDATE_PROFILES_ATTRIB_NAME);
|
||||
if (!this.environment.acceptsProfiles(specifiedProfiles)) {
|
||||
AnnotationMetadata metadata = configClass.getMetadata();
|
||||
if (this.environment != null && Profile.Helper.isProfileAnnotationPresent(metadata)) {
|
||||
if (!this.environment.acceptsProfiles(Profile.Helper.getCandidateProfiles(metadata))) {
|
||||
// TODO SPR-7508: log that this bean is being rejected on profile mismatch
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AnnotationMetadata metadata = configClass.getMetadata();
|
||||
while (metadata != null) {
|
||||
doProcessConfigurationClass(configClass, metadata);
|
||||
String superClassName = metadata.getSuperClassName();
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ import org.springframework.util.ClassUtils;
|
|||
* {@link BeanFactoryPostProcessor} used for bootstrapping processing of
|
||||
* {@link Configuration @Configuration} classes.
|
||||
*
|
||||
* <p>Registered by default when using {@literal <context:annotation-config/>} or
|
||||
* {@literal <context:component-scan/>}. Otherwise, may be declared manually as
|
||||
* <p>Registered by default when using {@code <context:annotation-config/>} or
|
||||
* {@code <context:component-scan/>}. Otherwise, may be declared manually as
|
||||
* with any other BeanFactoryPostProcessor.
|
||||
*
|
||||
* <p>This post processor is {@link Ordered#HIGHEST_PRECEDENCE} as it is important
|
||||
|
|
@ -100,7 +100,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
|||
/**
|
||||
* Set the {@link ProblemReporter} to use.
|
||||
* <p>Used to register any problems detected with {@link Configuration} or {@link Bean}
|
||||
* declarations. For instance, an @Bean method marked as {@literal final} is illegal
|
||||
* declarations. For instance, an @Bean method marked as {@code final} is illegal
|
||||
* and would be reported as a problem. Defaults to {@link FailFastProblemReporter}.
|
||||
*/
|
||||
public void setProblemReporter(ProblemReporter problemReporter) {
|
||||
|
|
@ -110,7 +110,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
|||
/**
|
||||
* Set the {@link MetadataReaderFactory} to use.
|
||||
* <p>Default is a {@link CachingMetadataReaderFactory} for the specified
|
||||
* {@link #setBeanClassLoader bean class loader}.
|
||||
* {@linkplain #setBeanClassLoader bean class loader}.
|
||||
*/
|
||||
public void setMetadataReaderFactory(MetadataReaderFactory metadataReaderFactory) {
|
||||
Assert.notNull(metadataReaderFactory, "MetadataReaderFactory must not be null");
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ import java.lang.annotation.Documented;
|
|||
* <p>Using {@link DependsOn} at the class level has no effect unless component-scanning
|
||||
* is being used. If a {@link DependsOn}-annotated class is declared via XML,
|
||||
* {@link DependsOn} annotation metadata is ignored, and
|
||||
* {@literal <bean depends-on="..."/>} is respected instead.
|
||||
* {@code <bean depends-on="..."/>} is respected instead.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
|
|
|
|||
|
|
@ -23,18 +23,18 @@ import java.lang.annotation.RetentionPolicy;
|
|||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates one or more {@link Configuration} classes to import.
|
||||
* Indicates one or more {@link Configuration @Configuration} classes to import.
|
||||
*
|
||||
* <p>Provides functionality equivalent to the {@literal <import/>} element in Spring XML.
|
||||
* Only supported for actual {@literal @Configuration}-annotated classes.
|
||||
* <p>Provides functionality equivalent to the {@code <import/>} element in Spring XML.
|
||||
* Only supported for actual {@code @Configuration}-annotated classes.
|
||||
*
|
||||
* <p>{@literal @Bean} definitions declared in imported {@literal @Configuration} classes
|
||||
* <p>{@code @Bean} definitions declared in imported {@code @Configuration} classes
|
||||
* should be accessed by using {@link Autowired @Autowired} injection. Either the bean
|
||||
* itself can be autowired, or the configuration class instance declaring the bean can be
|
||||
* autowired. The latter approach allows for explicit, IDE-friendly navigation between
|
||||
* {@literal @Configuration} class methods.
|
||||
* {@code @Configuration} class methods.
|
||||
*
|
||||
* <p>If XML or other non-{@literal @Configuration} bean definition resources need to be
|
||||
* <p>If XML or other non-{@code @Configuration} bean definition resources need to be
|
||||
* imported, use {@link ImportResource @ImportResource}
|
||||
*
|
||||
* @author Chris Beams
|
||||
|
|
|
|||
|
|
@ -30,14 +30,14 @@ import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
|||
* Indicates one or more resources containing bean definitions to import.
|
||||
*
|
||||
* <p>Like {@link Import @Import}, this annotation provides functionality similar to the
|
||||
* {@literal <import/>} element in Spring XML. It is typically used when
|
||||
* {@code <import/>} element in Spring XML. It is typically used when
|
||||
* designing {@link Configuration @Configuration} classes to be bootstrapped by
|
||||
* {@link AnnotationConfigApplicationContext}, but where some XML functionality such as
|
||||
* namespaces is still necessary.
|
||||
*
|
||||
* <p>By default, arguments to the {@link #value()} attribute will be processed using
|
||||
* an {@link XmlBeanDefinitionReader}, i.e. it is assumed that resources are Spring
|
||||
* {@literal <beans/>} XML files. Optionally, the {@link #reader()} attribute may be
|
||||
* {@code <beans/>} XML files. Optionally, the {@link #reader()} attribute may be
|
||||
* supplied, allowing the user to specify a different {@link BeanDefinitionReader}
|
||||
* implementation, such as
|
||||
* {@link org.springframework.beans.factory.support.PropertiesBeanDefinitionReader}.
|
||||
|
|
@ -53,8 +53,8 @@ import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
|||
public @interface ImportResource {
|
||||
|
||||
/**
|
||||
* Resource paths to import. Resource-loading prefixes such as {@literal classpath:} and
|
||||
* {@literal file:}, etc may be used.
|
||||
* Resource paths to import. Resource-loading prefixes such as {@code classpath:} and
|
||||
* {@code file:}, etc may be used.
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
|
|
|
|||
|
|
@ -25,25 +25,25 @@ import java.lang.annotation.Inherited;
|
|||
|
||||
/**
|
||||
* Indicates whether a bean is to be lazily initialized.
|
||||
*
|
||||
*
|
||||
* <p>May be used on any class directly or indirectly annotated with
|
||||
* {@link org.springframework.stereotype.Component} or on methods annotated with
|
||||
* {@link Bean}.
|
||||
*
|
||||
*
|
||||
* <p>If this annotation is not present on a Component or Bean definition, eager
|
||||
* initialization will occur. If present and set to {@literal true}, the
|
||||
* initialization will occur. If present and set to {@code true}, the
|
||||
* Bean/Component will not be initialized until referenced by another bean or
|
||||
* explicitly retrieved from the enclosing
|
||||
* {@link org.springframework.beans.factory.BeanFactory}. If present and set to
|
||||
* {@literal false}, the bean will be instantiated on startup by bean factories
|
||||
* {@code false}, the bean will be instantiated on startup by bean factories
|
||||
* that perform eager initialization of singletons.
|
||||
*
|
||||
* <p>If Lazy is present on a {@link Configuration} class, this indicates that all
|
||||
* {@link Bean} methods within that {@literal Configuration} should be lazily
|
||||
* initialized. If Lazy is present and false on a Bean method within a
|
||||
* Lazy-annotated Configuration class, this indicates overriding the 'default
|
||||
* lazy' behavior and that the bean should be eagerly initialized.
|
||||
*
|
||||
*
|
||||
* <p>If Lazy is present on a {@link Configuration @Configuration} class, this
|
||||
* indicates that all {@link Bean @Bean} methods within that {@code @Configuration}
|
||||
* should be lazily initialized. If Lazy is present and false on a Bean method
|
||||
* within a Lazy-annotated Configuration class, this indicates overriding the
|
||||
* 'default lazy' behavior and that the bean should be eagerly initialized.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.0
|
||||
* @see Primary
|
||||
|
|
|
|||
|
|
@ -27,16 +27,16 @@ import java.lang.annotation.Target;
|
|||
* Indicates that a bean should be given preference when multiple candidates
|
||||
* are qualified to autowire a single-valued dependency. If exactly one 'primary'
|
||||
* bean exists among the candidates, it will be the autowired value.
|
||||
*
|
||||
*
|
||||
* <p>May be used on any class directly or indirectly annotated with
|
||||
* {@link org.springframework.stereotype.Component} or on methods annotated
|
||||
* with {@link Bean}.
|
||||
*
|
||||
*
|
||||
* <p>Using {@link Primary} at the class level has no effect unless component-scanning
|
||||
* is being used. If a {@link Primary}-annotated class is declared via XML,
|
||||
* {@link Primary} annotation metadata is ignored, and
|
||||
* {@literal <bean primary="true|false"/>} is respected instead.
|
||||
*
|
||||
* {@code <bean primary="true|false"/>} is respected instead.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.0
|
||||
* @see Lazy
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 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,42 +16,78 @@
|
|||
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.core.env.AbstractEnvironment;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
*
|
||||
* Components not @Profile-annotated will always be registered
|
||||
* ConfigurableEnvironment.setActiveProfiles(String...) sets which profiles are active
|
||||
* 'spring.profile.active' sets which profiles are active (typically as a -D system property)
|
||||
servlet context/init param)
|
||||
* ConfigurableEnvironment.setDefaultProfiles(String...) or 'spring.profile.default' property specifies one
|
||||
or more default profiles, e.g., 'default'
|
||||
* if 'default' is specified as a default profile, @Profile({"xyz,default}) means that beans will be
|
||||
registered if 'xyz' is active or if no profile is active
|
||||
* Indicates that a component is eligible for registration when one or more {@linkplain #value
|
||||
* specified profiles} are active.
|
||||
*
|
||||
* <p>A <em>profile</em> is a named logical grouping that may be activated programatically via
|
||||
* {@link ConfigurableEnvironment#setActiveProfiles} or declaratively through setting the
|
||||
* {@link AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME spring.profile.active} property,
|
||||
* usually through JVM system properties, as an environment variable, or for web applications
|
||||
* as a Servlet context parameter in {@code web.xml}.
|
||||
*
|
||||
* <p>The {@code @Profile} annotation may be used in any of the following ways:
|
||||
* <ul>
|
||||
* <li>as a type-level annotation on any class directly or indirectly annotated with
|
||||
* {@code @Component}, including {@link Configuration @Configuration} classes
|
||||
* <li>as a meta-annotation, for the purpose of composing custom stereotype annotations
|
||||
* </ul>
|
||||
*
|
||||
* <p>If a {@code @Configuration} class is marked with {@code @Profile}, all of the
|
||||
* {@code @Bean} methods and {@link Import @Import} annotations associated with that class will
|
||||
* be bypassed unless one or more the specified profiles are active. This is very similar to
|
||||
* the behavior in Spring XML: if the {@code profile} attribute of the {@code beans} element is
|
||||
* supplied e.g., {@code <beans profile="p1,p2">}, the {@code beans} element will not be parsed unless
|
||||
* profiles 'p1' and/or 'p2' have been activated. Likewise, if a {@code @Component} or
|
||||
* {@code @Configuration} class is marked with <code>@Profile({"p1", "p2"})</code>, that class will
|
||||
* not be registered/processed unless profiles 'p1' and/or 'p2' have been activated.
|
||||
*
|
||||
* <p>If the {@code @Profile} annotation is omitted, registration will occur, regardless of which,
|
||||
* if any, profiles are active.
|
||||
*
|
||||
* <p>When defining Spring beans via XML, the {@code "profile"} attribute of the {@code <beans>}
|
||||
* element may be used. See the documentation in {@code spring-beans-3.1.xsd} for details.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see ConfigurableEnvironment#setActiveProfiles
|
||||
* @see ConfigurableEnvironment#setDefaultProfiles
|
||||
* @see AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME
|
||||
* @see AbstractEnvironment#DEFAULT_PROFILES_PROPERTY_NAME
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({
|
||||
ANNOTATION_TYPE, // @Profile may be used as a meta-annotation
|
||||
TYPE // In conjunction with @Component and its derivatives
|
||||
})
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface Profile {
|
||||
|
||||
/**
|
||||
* @see #value()
|
||||
*/
|
||||
static final String CANDIDATE_PROFILES_ATTRIB_NAME = "value";
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
* The set profiles for which this component should be registered.
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
|
||||
static class Helper {
|
||||
/**
|
||||
* Return whether the given metadata includes Profile information, whether directly or
|
||||
* through meta-annotation.
|
||||
*/
|
||||
static boolean isProfileAnnotationPresent(AnnotationMetadata metadata) {
|
||||
return metadata.isAnnotated(Profile.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the String[] of candidate profiles from {@link Profile#value()}.
|
||||
*/
|
||||
static String[] getCandidateProfiles(AnnotationMetadata metadata) {
|
||||
return (String[])metadata.getAnnotationAttributes(Profile.class.getName()).get("value");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import org.springframework.stereotype.Component;
|
|||
* the instance returned from the method.
|
||||
*
|
||||
* <p>In this context, scope means the lifecycle of an instance, such as
|
||||
* {@literal singleton}, {@literal prototype}, and so forth.
|
||||
* {@code singleton}, {@code prototype}, and so forth.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Chris Beams
|
||||
|
|
@ -59,7 +59,7 @@ public @interface Scope {
|
|||
* and if so, whether the proxy should be interface-based or subclass-based.
|
||||
* <p>Defaults to {@link ScopedProxyMode#NO}, indicating that no scoped
|
||||
* proxy should be created.
|
||||
* <p>Analogous to {@literal <aop:scoped-proxy/>} support in Spring XML.
|
||||
* <p>Analogous to {@code <aop:scoped-proxy/>} support in Spring XML.
|
||||
*/
|
||||
ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Annotation support for the Application Context, including JSR-250 "common"
|
||||
* annotations, component-scanning, and Java-based metadata for creating
|
||||
* Spring-managed objects.
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +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.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
|
@ -35,32 +35,24 @@ class PropertyPlaceholderBeanDefinitionParser extends AbstractPropertyLoadingBea
|
|||
|
||||
@Override
|
||||
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"))) {
|
||||
if (element.hasAttribute("system-properties-mode")) {
|
||||
return PropertyPlaceholderConfigurer.class;
|
||||
}
|
||||
|
||||
return EnvironmentAwarePropertyPlaceholderConfigurer.class;
|
||||
return PropertySourcesPlaceholderConfigurer.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, BeanDefinitionBuilder builder) {
|
||||
|
||||
super.doParse(element, builder);
|
||||
|
||||
builder.addPropertyValue("ignoreUnresolvablePlaceholders",
|
||||
Boolean.valueOf(element.getAttribute("ignore-unresolvable")));
|
||||
|
||||
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);
|
||||
}
|
||||
String systemPropertiesModeName = element.getAttribute("system-properties-mode");
|
||||
if (StringUtils.hasLength(systemPropertiesModeName)) {
|
||||
builder.addPropertyValue("systemPropertiesModeName", "SYSTEM_PROPERTIES_MODE_"+systemPropertiesModeName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,11 +44,11 @@ public class EnvironmentAccessor implements PropertyAccessor {
|
|||
}
|
||||
|
||||
/**
|
||||
* Access provided {@literal target} object by calling its {@link Environment#getProperty(String)}
|
||||
* method with the provided {@literal name}.
|
||||
* Access the given target object by resolving the given property name against the given target
|
||||
* environment.
|
||||
*/
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return new TypedValue(((Environment)target).getProperty(name));
|
||||
return new TypedValue(((Environment)target).getPropertyResolver().getProperty(name));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -206,8 +206,8 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
|||
/** Statically specified listeners */
|
||||
private Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();
|
||||
|
||||
/** TODO SPR-7508: document */
|
||||
private ConfigurableEnvironment environment = new DefaultEnvironment();
|
||||
/** Environment used by this context; initialized by {@link #createEnvironment()} */
|
||||
private ConfigurableEnvironment environment;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -224,6 +224,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
|||
public AbstractApplicationContext(ApplicationContext parent) {
|
||||
this.parent = parent;
|
||||
this.resourcePatternResolver = getResourcePatternResolver();
|
||||
this.environment = this.createEnvironment();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -279,6 +280,14 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
|||
return this.environment;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>Default value is determined by {@link #createEnvironment()}. Replacing the
|
||||
* default with this method is one option but configuration through {@link
|
||||
* #getEnvironment()} should also be considered. In either case, such modifications
|
||||
* should be performed <em>before</em> {@link #refresh()}.
|
||||
* @see org.springframework.context.support.AbstractApplicationContext#createEnvironment
|
||||
*/
|
||||
public void setEnvironment(ConfigurableEnvironment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
|
@ -400,6 +409,12 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
|||
return this.applicationListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new {@link DefaultEnvironment}.
|
||||
*/
|
||||
protected ConfigurableEnvironment createEnvironment() {
|
||||
return new DefaultEnvironment();
|
||||
}
|
||||
|
||||
public void refresh() throws BeansException, IllegalStateException {
|
||||
synchronized (this.startupShutdownMonitor) {
|
||||
|
|
@ -456,7 +471,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
|||
|
||||
/**
|
||||
* Prepare this context for refreshing, setting its startup date and
|
||||
* active flag.
|
||||
* active flag as well as performing any initialization of property sources.
|
||||
*/
|
||||
protected void prepareRefresh() {
|
||||
this.startupDate = System.currentTimeMillis();
|
||||
|
|
@ -468,6 +483,18 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
|||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Refreshing " + this);
|
||||
}
|
||||
|
||||
// Initialize any placeholder property sources in the context environment
|
||||
initPropertySources();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Replace any stub property sources with actual instances.
|
||||
* @see org.springframework.core.env.PropertySource.StubPropertySource
|
||||
* @see org.springframework.web.context.support.WebApplicationContextUtils#initSerlvetPropertySources
|
||||
*/
|
||||
protected void initPropertySources() {
|
||||
// For subclasses: do nothing by default.
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
|||
|
||||
/**
|
||||
* Base class for {@link org.springframework.context.ApplicationContext}
|
||||
* implementations which are supposed to support multiple calls to {@literal refresh},
|
||||
* implementations which are supposed to support multiple calls to {@link #refresh()},
|
||||
* creating a new internal bean factory instance every time.
|
||||
* Typically (but not necessarily), such a context will be driven by
|
||||
* a set of config locations to load bean definitions from.
|
||||
|
|
@ -50,7 +50,7 @@ import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
|||
* and {@link FileSystemXmlApplicationContext}, which both derive from the
|
||||
* common {@link AbstractXmlApplicationContext} base class;
|
||||
* {@link org.springframework.context.annotation.AnnotationConfigApplicationContext}
|
||||
* supports {@literal @Configuration}-annotated classes as a source of bean definitions.
|
||||
* supports {@code @Configuration}-annotated classes as a source of bean definitions.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
|
|
@ -182,7 +182,7 @@ public abstract class AbstractRefreshableApplicationContext extends AbstractAppl
|
|||
* Called for each {@link #refresh()} attempt.
|
||||
* <p>The default implementation creates a
|
||||
* {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
|
||||
* with the {@link #getInternalParentBeanFactory() internal bean factory} of this
|
||||
* with the {@linkplain #getInternalParentBeanFactory() internal bean factory} of this
|
||||
* context's parent as parent bean factory. Can be overridden in subclasses,
|
||||
* for example to customize DefaultListableBeanFactory's settings.
|
||||
* @return the bean factory for this context
|
||||
|
|
@ -199,8 +199,8 @@ public abstract class AbstractRefreshableApplicationContext extends AbstractAppl
|
|||
* Customize the internal bean factory used by this context.
|
||||
* Called for each {@link #refresh()} attempt.
|
||||
* <p>The default implementation applies this context's
|
||||
* {@link #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"}
|
||||
* and {@link #setAllowCircularReferences "allowCircularReferences"} settings,
|
||||
* {@linkplain #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"}
|
||||
* and {@linkplain #setAllowCircularReferences "allowCircularReferences"} settings,
|
||||
* if specified. Can be overridden in subclasses to customize any of
|
||||
* {@link DefaultListableBeanFactory}'s settings.
|
||||
* @param beanFactory the newly created bean factory for this context
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@
|
|||
package org.springframework.context.support;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.SystemPropertyUtils;
|
||||
|
||||
/**
|
||||
* {@link AbstractRefreshableApplicationContext} subclass that adds common handling
|
||||
|
|
@ -117,14 +117,9 @@ 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 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);
|
||||
return this.getEnvironment().getPropertyResolver().resolveRequiredPlaceholders(path);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
* 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<PropertySource<?>> 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<Environment> {
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -28,7 +28,6 @@ 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;
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@ public class GenericXmlApplicationContext extends GenericApplicationContext {
|
|||
|
||||
|
||||
/**
|
||||
* Create a new GenericXmlApplicationContext that needs to be populated
|
||||
* through {@link #load} calls and then manually {@link #refresh refreshed}.
|
||||
* Create a new GenericXmlApplicationContext that needs to be
|
||||
* {@linkplain #load loaded} and then manually {@link #refresh refreshed}.
|
||||
*/
|
||||
public GenericXmlApplicationContext() {
|
||||
reader.setEnvironment(this.getEnvironment());
|
||||
|
|
@ -91,8 +91,9 @@ public class GenericXmlApplicationContext extends GenericApplicationContext {
|
|||
}
|
||||
|
||||
/**
|
||||
* Set a custom environment. Should be called before any call to
|
||||
* {@link #load}. TODO SPR-7508: document
|
||||
* {@inheritDoc}
|
||||
* <p>Delegates the given environment to underlying {@link XmlBeanDefinitionReader}.
|
||||
* Should be called before any call to {@link #load}.
|
||||
*/
|
||||
@Override
|
||||
public void setEnvironment(ConfigurableEnvironment environment) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright 2002-2011 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.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanInitializationException;
|
||||
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.Environment;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.env.PropertiesPropertySource;
|
||||
import org.springframework.core.env.PropertyResolver;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.env.PropertySources;
|
||||
import org.springframework.core.env.PropertySourcesPropertyResolver;
|
||||
import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
|
||||
|
||||
/**
|
||||
* Specialization of {@link AbstractPropertyPlaceholderConfigurer}
|
||||
*
|
||||
* <p>Local properties are added as a property source in any case. Precedence is based
|
||||
* on the value of the {@link #setLocalOverride localOverride} property.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see AbstractPropertyPlaceholderConfigurer
|
||||
* @see PropertyPlaceholderConfigurer
|
||||
*/
|
||||
public class PropertySourcesPlaceholderConfigurer extends AbstractPropertyPlaceholderConfigurer
|
||||
implements EnvironmentAware {
|
||||
|
||||
/**
|
||||
* {@value} is the name given to the {@link PropertySource} for the set of
|
||||
* {@linkplain #mergeProperties() merged properties} supplied to this configurer.
|
||||
*/
|
||||
public static final String LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME = "localProperties";
|
||||
|
||||
private MutablePropertySources propertySources;
|
||||
|
||||
private PropertyResolver propertyResolver;
|
||||
|
||||
private Environment environment;
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>{@code PropertySources} from this environment will be searched when replacing ${...} placeholders
|
||||
* @see #setPropertySources
|
||||
* @see #postProcessBeanFactory
|
||||
*/
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize the set of {@link PropertySources} to be used by this configurer.
|
||||
* Setting this property indicates that environment property sources and local
|
||||
* properties should be ignored.
|
||||
* @see #postProcessBeanFactory
|
||||
*/
|
||||
public void setPropertySources(PropertySources propertySources) {
|
||||
this.propertySources = new MutablePropertySources(propertySources);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PlaceholderResolver getPlaceholderResolver(Properties props) {
|
||||
return new PlaceholderResolver() {
|
||||
public String resolvePlaceholder(String placeholderName) {
|
||||
return propertyResolver.getProperty(placeholderName);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>Processing occurs by replacing ${...} placeholders in bean definitions by resolving each
|
||||
* against this configurer's set of {@link PropertySources}, which includes:
|
||||
* <ul>
|
||||
* <li>all {@linkplain Environment#getPropertySources environment property sources}, if an
|
||||
* {@code Environment} {@linkplain #setEnvironment is present}
|
||||
* <li>{@linkplain #mergeProperties merged local properties}, if {@linkplain #setLocation any}
|
||||
* {@linkplain #setLocations have} {@linkplain #setProperties been}
|
||||
* {@linkplain #setPropertiesArray specified}
|
||||
* <li>any property sources set by calling {@link #setPropertySources}
|
||||
* </ul>
|
||||
* <p>If {@link #setPropertySources} is called, <strong>environment and local properties will be
|
||||
* ignored</strong>. This method is designed to give the user fine-grained control over property
|
||||
* sources, and once set, the configurer makes no assumptions about adding additional sources.
|
||||
*/
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
if (this.propertySources == null) {
|
||||
this.propertySources = new MutablePropertySources();
|
||||
if (this.environment != null) {
|
||||
this.propertySources.addAll(this.environment.getPropertySources());
|
||||
}
|
||||
try {
|
||||
PropertySource<?> localPropertySource =
|
||||
new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, this.mergeProperties());
|
||||
if (this.localOverride) {
|
||||
this.propertySources.addFirst(localPropertySource);
|
||||
} else {
|
||||
this.propertySources.addLast(localPropertySource);
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new BeanInitializationException("Could not load properties", ex);
|
||||
}
|
||||
}
|
||||
|
||||
this.propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);
|
||||
this.processProperties(beanFactory, this.propertyResolver.asProperties());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -30,8 +30,6 @@ 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;
|
||||
|
||||
|
|
@ -70,9 +68,6 @@ public class SimpleJndiBeanFactory extends JndiLocatorSupport implements BeanFac
|
|||
/** Cache of the types of nonshareable resources: bean name --> bean type */
|
||||
private final Map<String, Class> resourceTypes = new HashMap<String, Class>();
|
||||
|
||||
/** TODO SPR-7508: should be JNDI-specific environment */
|
||||
private ConfigurableEnvironment environment = new DefaultEnvironment();
|
||||
|
||||
|
||||
public SimpleJndiBeanFactory() {
|
||||
setResourceRef(true);
|
||||
|
|
|
|||
|
|
@ -90,42 +90,17 @@
|
|||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Activates replacement of ${...} placeholders, resolved against the specified properties file or
|
||||
Properties object (if any). Defines an EnvironmentAwarePropertyPlaceholderConfigurer within the context.
|
||||
Properties object (if any). Defines an PropertySourcesPlaceholderConfigurer within the context.
|
||||
For backward compatibility with versions earlier than Spring 3.1, a PropertyPlaceholderConfigurer will be
|
||||
registered if the 'system-properties-mode' attribute has been explicitly assigned a value.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation>
|
||||
<tool:exports
|
||||
type="org.springframework.beans.factory.config.AbstractPropertyPlaceholderConfigurer" />
|
||||
type="org.springframework.context.support.PropertySourcesPlaceholderConfigurer" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="propertyPlaceholder">
|
||||
<xsd:attribute name="system-properties-mode" default="DELEGATE">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
If set to any value other than DELEGATE, register a PropertyPlaceholderConfigurer bean and call
|
||||
its setSystemPropertiesModeName() method with the value. If set to DELEGATE (the default), register
|
||||
an EnvironmentAwarePropertyPlaceholderConfigurer and ignore the setting altogether, instead delegating
|
||||
to the enclosing application context's Environment object and its collection of PropertySource objects
|
||||
which may or may not include system properties and environment variables.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="DELEGATE"/>
|
||||
<xsd:enumeration value="NEVER"/>
|
||||
<xsd:enumeration value="FALLBACK"/>
|
||||
<xsd:enumeration value="OVERRIDE"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="property-override">
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
||||
package example.profilescan;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Profile(DevComponent.PROFILE_NAME)
|
||||
@Component
|
||||
public @interface DevComponent {
|
||||
|
||||
public static final String PROFILE_NAME = "dev";
|
||||
|
||||
String value() default "";
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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 example.profilescan;
|
||||
|
||||
|
||||
@DevComponent(ProfileMetaAnnotatedComponent.BEAN_NAME)
|
||||
public class ProfileMetaAnnotatedComponent {
|
||||
|
||||
public static final String BEAN_NAME = "profileMetaAnnotatedComponent";
|
||||
|
||||
}
|
||||
|
|
@ -39,7 +39,9 @@ import org.springframework.stereotype.Controller;
|
|||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import example.profilescan.DevComponent;
|
||||
import example.profilescan.ProfileAnnotatedComponent;
|
||||
import example.profilescan.ProfileMetaAnnotatedComponent;
|
||||
import example.scannable.FooDao;
|
||||
import example.scannable.FooService;
|
||||
import example.scannable.FooServiceImpl;
|
||||
|
|
@ -207,6 +209,15 @@ public class ClassPathScanningCandidateComponentProviderTests {
|
|||
assertThat(ctx.containsBean(ProfileAnnotatedComponent.BEAN_NAME), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntegrationWithAnnotationConfigApplicationContext_validMetaAnnotatedProfile() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.getEnvironment().setActiveProfiles(DevComponent.PROFILE_NAME);
|
||||
ctx.register(ProfileMetaAnnotatedComponent.class);
|
||||
ctx.refresh();
|
||||
assertThat(ctx.containsBean(ProfileMetaAnnotatedComponent.BEAN_NAME), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntegrationWithAnnotationConfigApplicationContext_invalidProfile() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
|
|
@ -216,6 +227,15 @@ public class ClassPathScanningCandidateComponentProviderTests {
|
|||
assertThat(ctx.containsBean(ProfileAnnotatedComponent.BEAN_NAME), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntegrationWithAnnotationConfigApplicationContext_invalidMetaAnnotatedProfile() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.getEnvironment().setActiveProfiles("other");
|
||||
ctx.register(ProfileMetaAnnotatedComponent.class);
|
||||
ctx.refresh();
|
||||
assertThat(ctx.containsBean(ProfileMetaAnnotatedComponent.BEAN_NAME), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntegrationWithAnnotationConfigApplicationContext_defaultProfile() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ import test.beans.TestBean;
|
|||
* particularly convenient syntax requiring no extra artifact for the aspect.
|
||||
*
|
||||
* <p>Currently it is assumed that the user is bootstrapping Configuration class processing via XML (using
|
||||
* annotation-config or component-scan), and thus will also use {@literal <aop:aspectj-autoproxy/>} to enable
|
||||
* annotation-config or component-scan), and thus will also use {@code <aop:aspectj-autoproxy/>} to enable
|
||||
* processing of the Aspect annotation.
|
||||
*
|
||||
* @author Chris Beams
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 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.
|
||||
|
|
@ -72,7 +72,7 @@ public class ContextNamespaceHandlerTests {
|
|||
|
||||
@Test
|
||||
public void propertyPlaceholderEnvironmentProperties() throws Exception {
|
||||
MockEnvironment env = MockEnvironment.withProperty("foo", "spam");
|
||||
MockEnvironment env = new MockEnvironment().withProperty("foo", "spam");
|
||||
GenericXmlApplicationContext applicationContext = new GenericXmlApplicationContext();
|
||||
applicationContext.setEnvironment(env);
|
||||
applicationContext.load(new ClassPathResource("contextNamespaceHandlerTests-simple.xml", getClass()));
|
||||
|
|
|
|||
|
|
@ -20,12 +20,11 @@ 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 org.springframework.mock.env.MockPropertySource;
|
||||
|
||||
import test.beans.TestBean;
|
||||
|
||||
|
|
@ -49,7 +48,7 @@ public class EnvironmentAccessorIntegrationTests {
|
|||
.getBeanDefinition());
|
||||
|
||||
GenericApplicationContext ctx = new GenericApplicationContext(bf);
|
||||
ctx.getEnvironment().addPropertySource("testMap", new HashMap() {{ put("my.name", "myBean"); }});
|
||||
ctx.getEnvironment().getPropertySources().addFirst(new MockPropertySource().withProperty("my.name", "myBean"));
|
||||
ctx.refresh();
|
||||
|
||||
assertThat(ctx.getBean(TestBean.class).getName(), equalTo("myBean"));
|
||||
|
|
|
|||
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* 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"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ import org.springframework.util.ClassUtils;
|
|||
|
||||
/**
|
||||
* Unit tests for {@link GenericXmlApplicationContext}.
|
||||
*
|
||||
*
|
||||
* See SPR-7530.
|
||||
*
|
||||
* @author Chris Beams
|
||||
|
|
|
|||
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* 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 java.util.Properties;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.mock.env.MockPropertySource;
|
||||
|
||||
import test.beans.TestBean;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link PropertySourcesPlaceholderConfigurer}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public class PropertySourcesPlaceholderConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void replacementFromEnvironmentProperties() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.registerBeanDefinition("testBean",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${my.name}")
|
||||
.getBeanDefinition());
|
||||
|
||||
MockEnvironment env = new MockEnvironment();
|
||||
env.setProperty("my.name", "myValue");
|
||||
|
||||
PropertySourcesPlaceholderConfigurer ppc =
|
||||
new PropertySourcesPlaceholderConfigurer();
|
||||
ppc.setEnvironment(env);
|
||||
ppc.postProcessBeanFactory(bf);
|
||||
assertThat(bf.getBean(TestBean.class).getName(), equalTo("myValue"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void localPropertiesViaResource() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.registerBeanDefinition("testBean",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${my.name}")
|
||||
.getBeanDefinition());
|
||||
|
||||
PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer();
|
||||
Resource resource = new ClassPathResource("PropertySourcesPlaceholderConfigurerTests.properties", this.getClass());
|
||||
pc.setLocation(resource);
|
||||
pc.postProcessBeanFactory(bf);
|
||||
assertThat(bf.getBean(TestBean.class).getName(), equalTo("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void localPropertiesOverrideFalse() {
|
||||
localPropertiesOverride(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void localPropertiesOverrideTrue() {
|
||||
localPropertiesOverride(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void explicitPropertySources() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.registerBeanDefinition("testBean",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${my.name}")
|
||||
.getBeanDefinition());
|
||||
|
||||
MutablePropertySources propertySources = new MutablePropertySources();
|
||||
propertySources.addLast(new MockPropertySource().withProperty("my.name", "foo"));
|
||||
|
||||
PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer();
|
||||
pc.setPropertySources(propertySources);
|
||||
pc.postProcessBeanFactory(bf);
|
||||
assertThat(bf.getBean(TestBean.class).getName(), equalTo("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void explicitPropertySourcesExcludesEnvironment() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.registerBeanDefinition("testBean",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${my.name}")
|
||||
.getBeanDefinition());
|
||||
|
||||
MutablePropertySources propertySources = new MutablePropertySources();
|
||||
propertySources.addLast(new MockPropertySource());
|
||||
|
||||
PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer();
|
||||
pc.setPropertySources(propertySources);
|
||||
pc.setEnvironment(new MockEnvironment().withProperty("my.name", "env"));
|
||||
pc.setIgnoreUnresolvablePlaceholders(true);
|
||||
pc.postProcessBeanFactory(bf);
|
||||
assertThat(bf.getBean(TestBean.class).getName(), equalTo("${my.name}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("serial")
|
||||
public void explicitPropertySourcesExcludesLocalProperties() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.registerBeanDefinition("testBean",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${my.name}")
|
||||
.getBeanDefinition());
|
||||
|
||||
MutablePropertySources propertySources = new MutablePropertySources();
|
||||
propertySources.addLast(new MockPropertySource());
|
||||
|
||||
PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer();
|
||||
pc.setPropertySources(propertySources);
|
||||
pc.setProperties(new Properties() {{ put("my.name", "local"); }});
|
||||
pc.setIgnoreUnresolvablePlaceholders(true);
|
||||
pc.postProcessBeanFactory(bf);
|
||||
assertThat(bf.getBean(TestBean.class).getName(), equalTo("${my.name}"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private void localPropertiesOverride(boolean override) {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.registerBeanDefinition("testBean",
|
||||
genericBeanDefinition(TestBean.class)
|
||||
.addPropertyValue("name", "${foo}")
|
||||
.getBeanDefinition());
|
||||
|
||||
PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
|
||||
|
||||
ppc.setLocalOverride(override);
|
||||
ppc.setProperties(new Properties() {{ setProperty("foo", "local"); }});
|
||||
ppc.setEnvironment(new 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"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
my.name=foo
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 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.
|
||||
|
|
@ -19,30 +19,41 @@ 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
|
||||
* @since 3.1
|
||||
* @see MockPropertySource
|
||||
*/
|
||||
public class MockEnvironment extends AbstractEnvironment {
|
||||
|
||||
private MockPropertySource propertySource = new MockPropertySource();
|
||||
|
||||
/**
|
||||
* Create a new {@code MockEnvironment} with a single {@link MockPropertySource}.
|
||||
*/
|
||||
public MockEnvironment() {
|
||||
getPropertySources().add(propertySource);
|
||||
getPropertySources().addLast(propertySource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a property on the underlying {@link MockPropertySource} for this environment.
|
||||
*/
|
||||
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;
|
||||
/**
|
||||
* Convenient synonym for {@link #setProperty} that returns the current instance.
|
||||
* Useful for method chaining and fluent-style use.
|
||||
* @return this {@link MockEnvironment} instance
|
||||
* @see MockPropertySource#withProperty(String, String)
|
||||
*/
|
||||
public MockEnvironment withProperty(String key, String value) {
|
||||
this.setProperty(key, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 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.
|
||||
|
|
@ -19,24 +19,85 @@ package org.springframework.mock.env;
|
|||
import java.util.Properties;
|
||||
|
||||
import org.springframework.core.env.PropertiesPropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
|
||||
/**
|
||||
* Simple {@link PropertySource} implementation for use in testing. Accepts
|
||||
* a user-provided {@link Properties} object, or if omitted during construction,
|
||||
* the implementation will initialize its own.
|
||||
*
|
||||
* The {@link #setProperty} and {@link #withProperty} methods are exposed for
|
||||
* convenience, for example:
|
||||
* <pre>
|
||||
* {@code
|
||||
* PropertySource<?> source = new MockPropertySource().withProperty("foo", "bar");
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see MockEnvironment
|
||||
*/
|
||||
public class MockPropertySource extends PropertiesPropertySource {
|
||||
|
||||
/**
|
||||
* {@value} is the default name for {@link MockPropertySource} instances not
|
||||
* otherwise given an explicit name.
|
||||
* @see #MockPropertySource()
|
||||
* @see #MockPropertySource(String)
|
||||
*/
|
||||
public static final String MOCK_PROPERTIES_PROPERTY_SOURCE_NAME = "mockProperties";
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} named {@value #MOCK_PROPERTIES_PROPERTY_SOURCE_NAME}
|
||||
* that will maintain its own internal {@link Properties} instance.
|
||||
*/
|
||||
public MockPropertySource() {
|
||||
this(new Properties());
|
||||
}
|
||||
|
||||
private MockPropertySource(Properties properties) {
|
||||
super("mockProperties", properties);
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} with the given name that will
|
||||
* maintain its own internal {@link Properties} instance.
|
||||
* @param name the {@linkplain #getName() name} of the property source
|
||||
*/
|
||||
public MockPropertySource(String name) {
|
||||
this(name, new Properties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} named {@value #MOCK_PROPERTIES_PROPERTY_SOURCE_NAME}
|
||||
* and backed by the given {@link Properties} object.
|
||||
* @param properties the properties to use
|
||||
*/
|
||||
public MockPropertySource(Properties properties) {
|
||||
this(MOCK_PROPERTIES_PROPERTY_SOURCE_NAME, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} with with the given name and backed by the given
|
||||
* {@link Properties} object
|
||||
* @param name the {@linkplain #getName() name} of the property source
|
||||
* @param properties the properties to use
|
||||
*/
|
||||
public MockPropertySource(String name, Properties properties) {
|
||||
super(name, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given property on the underlying {@link Properties} object.
|
||||
*/
|
||||
public void setProperty(String key, String value) {
|
||||
this.source.setProperty(key, value);
|
||||
this.source.put(key, value);
|
||||
}
|
||||
|
||||
public static MockPropertySource withProperty(String key, String value) {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(key, value);
|
||||
return new MockPropertySource(properties);
|
||||
/**
|
||||
* Convenient synonym for {@link #setProperty} that returns the current instance.
|
||||
* Useful for method chaining and fluent-style use.
|
||||
* @return this {@link MockPropertySource} instance
|
||||
*/
|
||||
public MockPropertySource withProperty(String key, String value) {
|
||||
this.setProperty(key, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.1.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">
|
||||
|
||||
<util:properties id="placeholderProps">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 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,39 +16,40 @@
|
|||
|
||||
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 java.security.AccessControlException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
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;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static java.lang.String.*;
|
||||
import static org.springframework.util.StringUtils.*;
|
||||
import static org.springframework.util.SystemPropertyUtils.*;
|
||||
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
* Abstract base class for {@link Environment} implementations.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see DefaultEnvironment
|
||||
*/
|
||||
public abstract class AbstractEnvironment implements ConfigurableEnvironment {
|
||||
|
||||
/**
|
||||
* Name of property to set to specify active profiles: {@value}. May be comma delimited.
|
||||
* @see ConfigurableEnvironment#setActiveProfiles
|
||||
*/
|
||||
public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profile.active";
|
||||
|
||||
/**
|
||||
* Name of property to set to specify default profiles: {@value}. May be comma delimited.
|
||||
* @see ConfigurableEnvironment#setDefaultProfiles
|
||||
*/
|
||||
public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profile.default";
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
|
@ -56,138 +57,22 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment {
|
|||
private Set<String> activeProfiles = new LinkedHashSet<String>();
|
||||
private Set<String> defaultProfiles = new LinkedHashSet<String>();
|
||||
|
||||
private LinkedList<PropertySource<?>> propertySources = new LinkedList<PropertySource<?>>();
|
||||
private ConversionService conversionService = ConversionServiceFactory.createDefaultConversionService();
|
||||
|
||||
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 MutablePropertySources propertySources = new MutablePropertySources();
|
||||
private ConfigurablePropertyResolver propertyResolver = new PropertySourcesPropertyResolver(propertySources);
|
||||
|
||||
|
||||
public ConversionService getConversionService() {
|
||||
return this.conversionService;
|
||||
public String[] getActiveProfiles() {
|
||||
return this.doGetActiveProfiles().toArray(new String[]{});
|
||||
}
|
||||
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
public void addPropertySource(PropertySource<?> propertySource) {
|
||||
propertySources.addFirst(propertySource);
|
||||
}
|
||||
|
||||
public void addPropertySource(String name, Properties properties) {
|
||||
addPropertySource(new PropertiesPropertySource(name, properties));
|
||||
}
|
||||
|
||||
public void addPropertySource(String name, Map<String, String> propertiesMap) {
|
||||
addPropertySource(new MapPropertySource(name, propertiesMap));
|
||||
}
|
||||
|
||||
public LinkedList<PropertySource<?>> 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> T getProperty(String key, Class<T> 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> T getRequiredProperty(String key, Class<T> 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();
|
||||
for (int i = propertySources.size() -1; i >= 0; i--) {
|
||||
PropertySource<?> propertySource = propertySources.get(i);
|
||||
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<String> getActiveProfiles() {
|
||||
protected Set<String> doGetActiveProfiles() {
|
||||
if (this.activeProfiles.isEmpty()) {
|
||||
String profiles = getProperty(ACTIVE_PROFILES_PROPERTY_NAME);
|
||||
String profiles = this.propertyResolver.getProperty(ACTIVE_PROFILES_PROPERTY_NAME);
|
||||
if (StringUtils.hasText(profiles)) {
|
||||
this.activeProfiles = commaDelimitedListToSet(trimAllWhitespace(profiles));
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableSet(activeProfiles);
|
||||
return this.activeProfiles;
|
||||
}
|
||||
|
||||
public void setActiveProfiles(String... profiles) {
|
||||
|
|
@ -195,14 +80,18 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment {
|
|||
this.activeProfiles.addAll(Arrays.asList(profiles));
|
||||
}
|
||||
|
||||
public Set<String> getDefaultProfiles() {
|
||||
public String[] getDefaultProfiles() {
|
||||
return this.doGetDefaultProfiles().toArray(new String[]{});
|
||||
}
|
||||
|
||||
protected Set<String> doGetDefaultProfiles() {
|
||||
if (this.defaultProfiles.isEmpty()) {
|
||||
String profiles = getProperty(DEFAULT_PROFILES_PROPERTY_NAME);
|
||||
String profiles = this.propertyResolver.getProperty(DEFAULT_PROFILES_PROPERTY_NAME);
|
||||
if (StringUtils.hasText(profiles)) {
|
||||
this.defaultProfiles = commaDelimitedListToSet(profiles);
|
||||
this.defaultProfiles = commaDelimitedListToSet(trimAllWhitespace(profiles));
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableSet(this.defaultProfiles);
|
||||
return this.defaultProfiles;
|
||||
}
|
||||
|
||||
public void setDefaultProfiles(String... profiles) {
|
||||
|
|
@ -210,6 +99,30 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment {
|
|||
this.defaultProfiles.addAll(Arrays.asList(profiles));
|
||||
}
|
||||
|
||||
public boolean acceptsProfiles(String... profiles) {
|
||||
Assert.notEmpty(profiles, "Must specify at least one profile");
|
||||
boolean activeProfileFound = false;
|
||||
Set<String> activeProfiles = this.doGetActiveProfiles();
|
||||
Set<String> defaultProfiles = this.doGetDefaultProfiles();
|
||||
for (String profile : profiles) {
|
||||
Assert.hasText(profile, "profile must not be empty");
|
||||
if (activeProfiles.contains(profile)
|
||||
|| (activeProfiles.isEmpty() && defaultProfiles.contains(profile))) {
|
||||
activeProfileFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return activeProfileFound;
|
||||
}
|
||||
|
||||
public MutablePropertySources getPropertySources() {
|
||||
return this.propertySources;
|
||||
}
|
||||
|
||||
public ConfigurablePropertyResolver getPropertyResolver() {
|
||||
return this.propertyResolver;
|
||||
}
|
||||
|
||||
public Map<String, String> getSystemEnvironment() {
|
||||
Map<String,String> systemEnvironment;
|
||||
try {
|
||||
|
|
@ -235,17 +148,6 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment {
|
|||
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<String, String> getSystemProperties() {
|
||||
Map systemProperties;
|
||||
|
|
@ -272,40 +174,10 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment {
|
|||
return systemProperties;
|
||||
}
|
||||
|
||||
public String resolvePlaceholders(String text) {
|
||||
return doResolvePlaceholders(text, nonStrictHelper);
|
||||
}
|
||||
|
||||
public String resolveRequiredPlaceholders(String text) {
|
||||
return doResolvePlaceholders(text, strictHelper);
|
||||
}
|
||||
|
||||
public boolean acceptsProfiles(String[] specifiedProfiles) {
|
||||
boolean activeProfileFound = false;
|
||||
Set<String> activeProfiles = this.getActiveProfiles();
|
||||
Set<String> defaultProfiles = this.getDefaultProfiles();
|
||||
for (String profile : specifiedProfiles) {
|
||||
if (activeProfiles.contains(profile)
|
||||
|| (activeProfiles.isEmpty() && defaultProfiles.contains(profile))) {
|
||||
activeProfileFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return activeProfileFound;
|
||||
}
|
||||
|
||||
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 String.format("%s [activeProfiles=%s, defaultProfiles=%s, propertySources=%s]",
|
||||
getClass().getSimpleName(), activeProfiles, defaultProfiles, propertySources);
|
||||
return format("%s [activeProfiles=%s, defaultProfiles=%s, propertySources=%s]",
|
||||
getClass().getSimpleName(), this.activeProfiles, this.defaultProfiles, this.propertySources);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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.SystemPropertyUtils.PLACEHOLDER_PREFIX;
|
||||
import static org.springframework.util.SystemPropertyUtils.PLACEHOLDER_SUFFIX;
|
||||
import static org.springframework.util.SystemPropertyUtils.VALUE_SEPARATOR;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* Abstract base class for resolving properties against any underlying source.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractPropertyResolver implements ConfigurablePropertyResolver {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
protected ConversionService conversionService = ConversionServiceFactory.createDefaultConversionService();
|
||||
|
||||
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);
|
||||
|
||||
|
||||
public ConversionService getConversionService() {
|
||||
return this.conversionService;
|
||||
}
|
||||
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
public String getRequiredProperty(String key) throws IllegalStateException {
|
||||
String value = getProperty(key);
|
||||
if (value == null) {
|
||||
throw new IllegalStateException(format("required key [%s] not found", key));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public <T> T getRequiredProperty(String key, Class<T> valueType) throws IllegalStateException {
|
||||
T value = getProperty(key, valueType);
|
||||
if (value == null) {
|
||||
throw new IllegalStateException(format("required key [%s] not found", key));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public int getPropertyCount() {
|
||||
return asProperties().size();
|
||||
}
|
||||
|
||||
public String resolvePlaceholders(String text) {
|
||||
return doResolvePlaceholders(text, this.nonStrictHelper);
|
||||
}
|
||||
|
||||
public String resolveRequiredPlaceholders(String text) {
|
||||
return doResolvePlaceholders(text, this.strictHelper);
|
||||
}
|
||||
|
||||
private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
|
||||
return helper.replacePlaceholders(text, new PlaceholderResolver() {
|
||||
public String resolvePlaceholder(String placeholderName) {
|
||||
return getProperty(placeholderName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,46 +16,45 @@
|
|||
|
||||
package org.springframework.core.env;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
* Configuration interface to be implemented by most if not all {@link Environment
|
||||
* Environments}. Provides facilities for setting active and default profiles as well
|
||||
* as specializing the return types for {@link #getPropertySources()} and
|
||||
* {@link #getPropertyResolver()} such that they return types that may be manipulated.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see DefaultEnvironment
|
||||
* @see org.springframework.context.ConfigurableApplicationContext#getEnvironment
|
||||
*/
|
||||
public interface ConfigurableEnvironment extends Environment {
|
||||
|
||||
/**
|
||||
* Specify the set of profiles active for this Environment. Profiles are
|
||||
* evaluated during container bootstrap to determine whether bean definitions
|
||||
* should be registered with the container.
|
||||
*
|
||||
* @see #setDefaultProfiles
|
||||
* @see org.springframework.context.annotation.Profile
|
||||
* @see AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME
|
||||
*/
|
||||
void setActiveProfiles(String... profiles);
|
||||
|
||||
/**
|
||||
* Specify the set of profiles to be made active by default if no other profiles
|
||||
* are explicitly made active through {@link #setActiveProfiles}.
|
||||
* @see AbstractEnvironment#DEFAULT_PROFILES_PROPERTY_NAME
|
||||
*/
|
||||
void setDefaultProfiles(String... profiles);
|
||||
|
||||
public ConversionService getConversionService();
|
||||
|
||||
public void setConversionService(ConversionService conversionService);
|
||||
|
||||
void addPropertySource(PropertySource<?> propertySource);
|
||||
|
||||
void addPropertySource(String name, Properties properties);
|
||||
|
||||
void addPropertySource(String name, Map<String, String> propertiesMap);
|
||||
/**
|
||||
* Return the {@link PropertySources} for this environment in mutable form
|
||||
*/
|
||||
MutablePropertySources getPropertySources();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Return the {@link PropertyResolver} for this environment in configurable form
|
||||
*/
|
||||
LinkedList<PropertySource<?>> getPropertySources();
|
||||
ConfigurablePropertyResolver getPropertyResolver();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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.springframework.core.convert.ConversionService;
|
||||
|
||||
|
||||
/**
|
||||
* Configuration interface to be implemented by most if not all {@link PropertyResolver
|
||||
* PropertyResolvers}. Provides facilities for accessing and customizing the
|
||||
* {@link ConversionService} used when converting property values from one type to
|
||||
* another.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface ConfigurablePropertyResolver extends PropertyResolver {
|
||||
|
||||
/**
|
||||
* @return the {@link ConversionService} used when performing type
|
||||
* conversions on properties.
|
||||
* @see PropertyResolver#getProperty(String, Class)
|
||||
*/
|
||||
ConversionService getConversionService();
|
||||
|
||||
/**
|
||||
* Set the {@link ConversionService} to be used when performing type
|
||||
* conversions on properties.
|
||||
* @see PropertyResolver#getProperty(String, Class)
|
||||
*/
|
||||
void setConversionService(ConversionService conversionService);
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 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,24 +16,85 @@
|
|||
|
||||
package org.springframework.core.env;
|
||||
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
* Default implementation of the {@link Environment} interface. Used throughout all non-Web*
|
||||
* ApplicationContext implementations.
|
||||
*
|
||||
* Explain why the default ordering of property sources is the way it is.
|
||||
* <p>In addition to the usual functions of a {@link ConfigurableEnvironment} such as property
|
||||
* resolution and profile-related operations, this implementation configures two default property
|
||||
* sources, to be searched in the following order:
|
||||
* <ol>
|
||||
* <li>{@linkplain AbstractEnvironment#getSystemProperties() system properties}
|
||||
* <li>{@linkplain AbstractEnvironment#getSystemEnvironment() system environment variables}
|
||||
* </ol>
|
||||
*
|
||||
* That is, if the key "xyz" is present both in the JVM system properties as well as in the
|
||||
* set of environment variables for the current process, the value of key "xyz" from system properties
|
||||
* will return from a call to {@code environment.getPropertyResolver().getProperty("xyz")}.
|
||||
* This ordering is chosen by default because system properties are per-JVM, while environment
|
||||
* variables may be the same across many JVMs on a given system. Giving system properties
|
||||
* precedence allows for overriding of environment variables on a per-JVM basis.
|
||||
*
|
||||
* <p>These default property sources may be removed, reordered, or replaced; and additional
|
||||
* property sources may be added using the {@link MutablePropertySources} instance available
|
||||
* from {@link #getPropertySources()}.
|
||||
*
|
||||
* <h4>Example: adding a new property source with highest search priority</h4>
|
||||
* <pre class="code">
|
||||
* ConfigurableEnvironment environment = new DefaultEnvironment();
|
||||
* MutablePropertySources propertySources = environment.getPropertySources();
|
||||
* Map<String, String> myMap = new HashMap<String, String>();
|
||||
* myMap.put("xyz", "myValue");
|
||||
* propertySources.addFirst(new MapPropertySource("MY_MAP", myMap));
|
||||
* </pre>
|
||||
*
|
||||
* <h4>Example: removing the default system properties property source</h4>
|
||||
* <pre class="code">
|
||||
* MutablePropertySources propertySources = environment.getPropertySources();
|
||||
* propertySources.remove(DefaultEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)
|
||||
* </pre>
|
||||
*
|
||||
* <h4>Example: mocking the system environment for testing purposes</h4>
|
||||
* <pre class="code">
|
||||
* MutablePropertySources propertySources = environment.getPropertySources();
|
||||
* MockPropertySource mockEnvVars = new MockPropertySource().withProperty("xyz", "myValue");
|
||||
* propertySources.replace(DefaultEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, mockEnvVars);
|
||||
* </pre>
|
||||
*
|
||||
* When an {@link Environment} is being used by an ApplicationContext, it is important
|
||||
* that any such PropertySource manipulations be performed <em>before</em> the context's {@link
|
||||
* org.springframework.context.support.AbstractApplicationContext#refresh() refresh()} method is
|
||||
* called. This ensures that all PropertySources are available during the container bootstrap process,
|
||||
* including use by {@link org.springframework.context.support.PropertySourcesPlaceholderConfigurer
|
||||
* property placeholder configurers}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see ConfigurableEnvironment
|
||||
* @see org.springframework.web.context.support.DefaultWebEnvironment
|
||||
*/
|
||||
public class DefaultEnvironment extends AbstractEnvironment {
|
||||
|
||||
/** System environment property source name: {@value} */
|
||||
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
|
||||
|
||||
/** JVM system properties property source name: {@value} */
|
||||
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code Environment} populated with property sources in the following order:
|
||||
* <ul>
|
||||
* <li>{@value #SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME}
|
||||
* <li>{@value #SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME}
|
||||
* </ul>
|
||||
*
|
||||
* <p>Properties present in {@value #SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME} will
|
||||
* take precedence over those in {@value #SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME}.
|
||||
*/
|
||||
public DefaultEnvironment() {
|
||||
addPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment());
|
||||
addPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties());
|
||||
this.getPropertySources().addFirst(new MapPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, this.getSystemEnvironment()));
|
||||
this.getPropertySources().addFirst(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, this.getSystemProperties()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -17,98 +17,131 @@
|
|||
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
|
||||
* Interface representing the environment in which the current application is running.
|
||||
* Models two key aspects of the application environment:
|
||||
* <ol>
|
||||
* <li>profiles</li>
|
||||
* <li>properties</li>
|
||||
* </ol>
|
||||
*
|
||||
* A <em>profile</em> is a named, logical group of bean definitions to be registered with the
|
||||
* container only if the given profile is <em>active</em>. Beans may be assigned to a profile
|
||||
* whether defined in XML or annotations; see the spring-beans 3.1 schema or the {@link
|
||||
* org.springframework.context.annotation.Profile @Profile} annotation for syntax details.
|
||||
* The role of the Environment object with relation to profiles is in determining which profiles
|
||||
* (if any) are currently {@linkplain #getActiveProfiles active}, and which profiles (if any)
|
||||
* should be {@linkplain #getDefaultProfiles active by default}.
|
||||
*
|
||||
* <p><em>Properties</em> play an important role in almost all applications, and may originate
|
||||
* from a variety of sources: properties files, JVM system properties, system environment
|
||||
* variables, JNDI, servlet context parameters, ad-hoc Properties objects, Maps, and so on.
|
||||
* The role of the environment object with relation to properties is to provide the user with a
|
||||
* convenient service interface for configuring property sources and resolving properties from them.
|
||||
*
|
||||
* <p>Beans managed within an ApplicationContext may register to be {@link
|
||||
* org.springframework.context.EnvironmentAware EnvironmentAware}, where they can query profile state
|
||||
* or resolve properties directly.
|
||||
*
|
||||
* <p>More commonly, beans will not interact with the Environment directly, but will have ${...}
|
||||
* property values replaced by a property placeholder configurer such as {@link
|
||||
* org.springframework.context.support.PropertySourcesPlaceholderConfigurer
|
||||
* PropertySourcesPlaceholderConfigurer}, which itself is EnvironmentAware, and as of Spring 3.1 is
|
||||
* registered by default when using {@code <context:property-placeholder/>}.
|
||||
*
|
||||
* <p>Configuration of the environment object must be done through the {@link ConfigurableEnvironment}
|
||||
* interface, returned from all AbstractApplicationContext subclass getEnvironment() methods. See
|
||||
* {@link DefaultEnvironment} for several examples of using the ConfigurableEnvironment interface
|
||||
* to manipulate property sources prior to application context refresh().
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see EnvironmentCapable
|
||||
* @see ConfigurableEnvironment
|
||||
* @see DefaultEnvironment
|
||||
* @see org.springframework.context.EnvironmentAware
|
||||
* @see org.springframework.context.ConfigurableApplicationContext#getEnvironment
|
||||
* @see org.springframework.context.ConfigurableApplicationContext#setEnvironment
|
||||
* @see org.springframework.context.support.AbstractApplicationContext#createEnvironment
|
||||
*/
|
||||
public interface Environment {
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
* Return the set of profiles explicitly made active for this environment. Profiles are used for
|
||||
* creating logical groupings of bean definitions to be registered conditionally, often based on
|
||||
* deployment environment. Profiles can be activated by setting {@linkplain
|
||||
* AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME "spring.profiles.active"} as a system property
|
||||
* or by calling {@link ConfigurableEnvironment#setActiveProfiles(String...)}.
|
||||
*
|
||||
* <p>If no profiles have explicitly been specified as active, then any 'default' profiles will implicitly
|
||||
* be considered active.
|
||||
*
|
||||
* @see #getDefaultProfiles
|
||||
* @see ConfigurableEnvironment#setActiveProfiles
|
||||
* @see AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME
|
||||
*/
|
||||
Set<String> getActiveProfiles();
|
||||
String[] getActiveProfiles();
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
* Return the set of profiles to be active by default when no active profiles have been set explicitly.
|
||||
*
|
||||
* @see #getActiveProfiles
|
||||
* @see ConfigurableEnvironment#setDefaultProfiles
|
||||
*/
|
||||
Set<String> getDefaultProfiles();
|
||||
String[] getDefaultProfiles();
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
* returns true if:
|
||||
* a) one or more of specifiedProfiles are active in the given environment - see {@link #getActiveProfiles()}
|
||||
* b) specifiedProfiles contains default profile - see {@link #getDefaultProfile()}
|
||||
* @return whether one or more of the given profiles is active, or in the case of no explicit active
|
||||
* profiles, whether one or more of the given profiles is included in the set of default profiles
|
||||
* @throws IllegalArgumentException unless at least one profile has been specified
|
||||
* @throws IllegalArgumentException if any profile is the empty string or consists only of whitespace
|
||||
* @see #getActiveProfiles
|
||||
* @see #getDefaultProfiles
|
||||
*/
|
||||
boolean acceptsProfiles(String[] specifiedProfiles);
|
||||
boolean acceptsProfiles(String... profiles);
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
* @return the {@link PropertyResolver} used for accessing properties.
|
||||
* @see PropertyResolver
|
||||
* @see #getPropertySources
|
||||
*/
|
||||
boolean containsProperty(String key);
|
||||
PropertyResolver getPropertyResolver();
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
* Return the set of {@link PropertySource} objects used by by this Environment's PropertyResolver
|
||||
* @see #getPropertyResolver
|
||||
*/
|
||||
String getProperty(String key);
|
||||
PropertySources getPropertySources();
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
*/
|
||||
<T> T getProperty(String key, Class<T> targetType);
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
*/
|
||||
String getRequiredProperty(String key);
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
*/
|
||||
<T> T getRequiredProperty(String key, Class<T> 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.
|
||||
* Return the value of {@link System#getenv()} if allowed by the current {@link SecurityManager},
|
||||
* otherwise return a map implementation that will attempt to access individual keys using calls to
|
||||
* {@link System#getenv(String)}.
|
||||
*
|
||||
* <p>Note that most {@link Environment} implementations will include this system environment map as
|
||||
* a default {@link PropertySource} to be searched. Therefore, it is recommended that this method not be
|
||||
* used directly unless bypassing other property sources is expressly intended.
|
||||
*
|
||||
* <p>Calls to {@link Map#get(Object)} on the Map returned will never throw {@link IllegalAccessException};
|
||||
* in cases where the SecurityManager forbids access to a property, {@code null} will be returned and an
|
||||
* INFO-level log message will be issued noting the exception.
|
||||
*/
|
||||
Map<String, String> 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()}
|
||||
* Return the value of {@link System#getProperties()} if allowed by the current {@link SecurityManager},
|
||||
* otherwise return a map implementation that will attempt to access individual keys using calls to
|
||||
* {@link System#getProperty(String)}.
|
||||
*
|
||||
* <p>Note that most {@code Environment} implementations will include this system properties map as a
|
||||
* default {@link PropertySource} to be searched. Therefore, it is recommended that this method not be
|
||||
* used directly unless bypassing other property sources is expressly intended.
|
||||
*
|
||||
* <p>Calls to {@link Map#get(Object)} on the Map returned will never throw {@link IllegalAccessException};
|
||||
* in cases where the SecurityManager forbids access to a property, {@code null} will be returned and an
|
||||
* INFO-level log message will be issued noting the exception.
|
||||
*/
|
||||
Map<String, String> 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);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,15 +18,32 @@ package org.springframework.core.env;
|
|||
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: document
|
||||
*
|
||||
* Interface indicating a component contains and makes available an {@link Environment} object.
|
||||
*
|
||||
* <p>All Spring application contexts are EnvironmentCapable, and the interface is used primarily
|
||||
* for performing {@code instanceof} checks in framework methods that accept BeanFactory
|
||||
* instances that may or may not actually be ApplicationContext instances in order to interact
|
||||
* with the environment if indeed it is available.
|
||||
*
|
||||
* <p>As mentioned, {@link org.springframework.context.ApplicationContext ApplicationContext}
|
||||
* extends EnvironmentCapable, and thus exposes a {@link #getEnvironment()} method; however,
|
||||
* {@link org.springframework.context.ConfigurableApplicationContext ConfigurableApplicationContext}
|
||||
* redefines {@link org.springframework.context.ConfigurableApplicationContext#getEnvironment
|
||||
* getEnvironment()} and narrows the signature to return a {@link ConfigurableEnvironment}. The effect
|
||||
* is that an Environment object is 'read-only' until it accessed from a ConfigurableApplicationContext,
|
||||
* at which point it too may be configured.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see Environment
|
||||
* @see ConfigurableEnvironmentCapable
|
||||
* @see ConfigurableEnvironment
|
||||
* @see org.springframework.context.ConfigurableApplicationContext#getEnvironment
|
||||
*/
|
||||
public interface EnvironmentCapable {
|
||||
|
||||
/**
|
||||
* Return the Environment for this object
|
||||
*/
|
||||
Environment getEnvironment();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -18,18 +18,12 @@ 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.
|
||||
* {@link PropertySource} that reads keys and values from a {@code Map<String,String>} object.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see PropertiesPropertySource
|
||||
*/
|
||||
public class MapPropertySource extends PropertySource<Map<String, String>> {
|
||||
|
||||
|
|
@ -37,17 +31,14 @@ public class MapPropertySource extends PropertySource<Map<String, String>> {
|
|||
super(name, source);
|
||||
}
|
||||
|
||||
public boolean containsProperty(String key) {
|
||||
return source.containsKey(key);
|
||||
}
|
||||
|
||||
public String getProperty(String key) {
|
||||
return source.get(key);
|
||||
@Override
|
||||
public String[] getPropertyNames() {
|
||||
return this.source.keySet().toArray(EMPTY_NAMES_ARRAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return source.size();
|
||||
public String getProperty(String key) {
|
||||
return this.source.get(key);
|
||||
}
|
||||
|
||||
}
|
||||
123
org.springframework.core/src/main/java/org/springframework/core/env/MutablePropertySources.java
vendored
Normal file
123
org.springframework.core/src/main/java/org/springframework/core/env/MutablePropertySources.java
vendored
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* 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.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
public class MutablePropertySources implements PropertySources {
|
||||
|
||||
private final LinkedList<PropertySource<?>> propertySourceList = new LinkedList<PropertySource<?>>();
|
||||
|
||||
static final String NON_EXISTENT_PROPERTY_SOURCE_MESSAGE = "PropertySource named [%s] does not exist";
|
||||
static final String ILLEGAL_RELATIVE_ADDITION_MESSAGE = "PropertySource named [%s] cannot be added relative to itself";
|
||||
|
||||
|
||||
public MutablePropertySources() {
|
||||
}
|
||||
|
||||
public MutablePropertySources(PropertySources propertySources) {
|
||||
this.addAll(propertySources);
|
||||
}
|
||||
|
||||
public void addAll(PropertySources propertySources) {
|
||||
for (PropertySource<?> propertySource : propertySources.asList()) {
|
||||
this.addLast(propertySource);
|
||||
}
|
||||
}
|
||||
|
||||
public void addFirst(PropertySource<?> propertySource) {
|
||||
removeIfPresent(propertySource);
|
||||
this.propertySourceList.addFirst(propertySource);
|
||||
}
|
||||
|
||||
public void addLast(PropertySource<?> propertySource) {
|
||||
removeIfPresent(propertySource);
|
||||
this.propertySourceList.addLast(propertySource);
|
||||
}
|
||||
|
||||
public void addBefore(String relativePropertySourceName, PropertySource<?> propertySource) {
|
||||
assertLegalRelativeAddition(relativePropertySourceName, propertySource);
|
||||
removeIfPresent(propertySource);
|
||||
int index = assertPresentAndGetIndex(relativePropertySourceName);
|
||||
addAtIndex(index, propertySource);
|
||||
}
|
||||
|
||||
public void addAfter(String relativePropertySourceName, PropertySource<?> propertySource) {
|
||||
assertLegalRelativeAddition(relativePropertySourceName, propertySource);
|
||||
removeIfPresent(propertySource);
|
||||
int index = assertPresentAndGetIndex(relativePropertySourceName);
|
||||
addAtIndex(index+1, propertySource);
|
||||
}
|
||||
|
||||
protected void assertLegalRelativeAddition(String relativePropertySourceName, PropertySource<?> propertySource) {
|
||||
String newPropertySourceName = propertySource.getName();
|
||||
Assert.isTrue(!relativePropertySourceName.equals(newPropertySourceName),
|
||||
String.format(ILLEGAL_RELATIVE_ADDITION_MESSAGE, newPropertySourceName));
|
||||
}
|
||||
|
||||
protected void addAtIndex(int index, PropertySource<?> propertySource) {
|
||||
removeIfPresent(propertySource);
|
||||
this.propertySourceList.add(index, propertySource);
|
||||
}
|
||||
|
||||
protected void removeIfPresent(PropertySource<?> propertySource) {
|
||||
if (this.propertySourceList.contains(propertySource)) {
|
||||
this.propertySourceList.remove(propertySource);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(String propertySourceName) {
|
||||
return propertySourceList.contains(PropertySource.named(propertySourceName));
|
||||
}
|
||||
|
||||
public PropertySource<?> remove(String propertySourceName) {
|
||||
int index = propertySourceList.indexOf(PropertySource.named(propertySourceName));
|
||||
if (index >= 0) {
|
||||
return propertySourceList.remove(index);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void replace(String propertySourceName, PropertySource<?> propertySource) {
|
||||
int index = assertPresentAndGetIndex(propertySourceName);
|
||||
this.propertySourceList.set(index, propertySource);
|
||||
}
|
||||
|
||||
protected int assertPresentAndGetIndex(String propertySourceName) {
|
||||
int index = this.propertySourceList.indexOf(PropertySource.named(propertySourceName));
|
||||
Assert.isTrue(index >= 0, String.format(NON_EXISTENT_PROPERTY_SOURCE_MESSAGE, propertySourceName));
|
||||
return index;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return propertySourceList.size();
|
||||
}
|
||||
|
||||
public List<PropertySource<?>> asList() {
|
||||
return Collections.unmodifiableList(this.propertySourceList);
|
||||
}
|
||||
|
||||
public PropertySource<?> get(String propertySourceName) {
|
||||
return propertySourceList.get(propertySourceList.indexOf(PropertySource.named(propertySourceName)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 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,39 +16,26 @@
|
|||
|
||||
package org.springframework.core.env;
|
||||
|
||||
import java.util.Map;
|
||||
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.
|
||||
* {@link PropertySource} implementation that extracts properties from a {@link java.util.Properties} object.
|
||||
*
|
||||
* Consider adding a TypeConvertingPropertiesPropertySource to accommodate
|
||||
* non-string keys and values (such as is technically possible with
|
||||
* System.getProperties())
|
||||
* <p>Note that because a {@code Properties} object is technically an {@code <Object, Object>}
|
||||
* {@link java.util.Hashtable Hashtable}, one may contain non-{@code String} keys or values. This
|
||||
* implementation, however is restricted to accessing only {@code String}-based keys and values, in
|
||||
* the same fashion as {@link Properties#getProperty} and {@link Properties#setProperty}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see org.springframework.mock.env.MockPropertySource
|
||||
*/
|
||||
public class PropertiesPropertySource extends PropertySource<Properties> {
|
||||
public class PropertiesPropertySource extends MapPropertySource {
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
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();
|
||||
super(name, (Map)source);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
96
org.springframework.core/src/main/java/org/springframework/core/env/PropertyResolver.java
vendored
Normal file
96
org.springframework.core/src/main/java/org/springframework/core/env/PropertyResolver.java
vendored
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
|
||||
/**
|
||||
* Interface for resolving properties against any underlying source.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see Environment#getPropertyResolver()
|
||||
*/
|
||||
public interface PropertyResolver {
|
||||
|
||||
/**
|
||||
* @return whether the given property key is available for resolution
|
||||
*/
|
||||
boolean containsProperty(String key);
|
||||
|
||||
/**
|
||||
* @return the property value associated with the given key
|
||||
* @see #getProperty(String, Class)
|
||||
*/
|
||||
String getProperty(String key);
|
||||
|
||||
/**
|
||||
* @return the property value associated with the given key, or {@code null}
|
||||
* if the key cannot be resolved
|
||||
*/
|
||||
<T> T getProperty(String key, Class<T> targetType);
|
||||
|
||||
/**
|
||||
* @return the property value associated with the given key, converted to the given
|
||||
* targetType (never {@code null})
|
||||
* @throws IllegalStateException if the key cannot be resolved
|
||||
* @see #getRequiredProperty(String, Class)
|
||||
*/
|
||||
String getRequiredProperty(String key) throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* @return the property value associated with the given key, converted to the given
|
||||
* targetType (never {@code null})
|
||||
* @throws IllegalStateException if the given key cannot be resolved
|
||||
*/
|
||||
<T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* @return the number of unique properties keys resolvable
|
||||
*/
|
||||
int getPropertyCount();
|
||||
|
||||
/**
|
||||
* @return all property key/value pairs as a {@link java.util.Properties} instance
|
||||
*/
|
||||
Properties asProperties();
|
||||
|
||||
/**
|
||||
* Resolve ${...} placeholders in the given text, replacing them with corresponding
|
||||
* property values as resolved by {@link #getProperty}. Unresolvable placeholders with
|
||||
* no default value are ignored and passed through unchanged.
|
||||
* @param text the String to resolve
|
||||
* @return the resolved String (never {@code null})
|
||||
* @throws IllegalArgumentException if given text is {@code null}
|
||||
* @see #resolveRequiredPlaceholders
|
||||
* @see org.springframework.util.SystemPropertyUtils#resolvePlaceholders(String)
|
||||
*/
|
||||
String resolvePlaceholders(String text);
|
||||
|
||||
/**
|
||||
* Resolve ${...} placeholders in the given text, replacing them with corresponding
|
||||
* property values as resolved by {@link #getProperty}. Unresolvable placeholders with
|
||||
* no default value will cause an IllegalArgumentException to be thrown.
|
||||
* @return the resolved String (never {@code null})
|
||||
* @throws IllegalArgumentException if given text is {@code null}
|
||||
* @throws IllegalArgumentException if any placeholders are unresolvable
|
||||
* @see org.springframework.util.SystemPropertyUtils#resolvePlaceholders(String, boolean)
|
||||
*/
|
||||
String resolveRequiredPlaceholders(String path) throws IllegalArgumentException;
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -18,43 +18,122 @@ package org.springframework.core.env;
|
|||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Abstract base class representing a source of key/value property pairs. The underlying
|
||||
* {@linkplain #getSource() source object} may be of any type {@code T} that encapsulates
|
||||
* properties. Examples include {@link java.util.Properties} objects, {@link java.util.Map}
|
||||
* objects, {@code ServletContext} and {@code ServletConfig} objects (for access to init parameters).
|
||||
* Explore the {@code PropertySource} type hierarchy to see provided implementations.
|
||||
*
|
||||
* <p>{@code PropertySource} objects are not typically used in isolation, but rather through a
|
||||
* {@link PropertySources} object, which aggregates property sources and in conjunction with
|
||||
* a {@link PropertyResolver} implementation that can perform precedence-based searches across
|
||||
* the set of {@code PropertySources}.
|
||||
*
|
||||
* <p>{@code PropertySource} identity is determined not based on the content of encapsulated
|
||||
* properties, but rather based on the {@link #getName() name} of the {@code PropertySource}
|
||||
* alone. This is useful for manipulating {@code PropertySource} objects when in collection
|
||||
* contexts. See operations in {@link MutablePropertySources} as well as the
|
||||
* {@link #named(String)} and {@link #toString()} methods for details.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see PropertySources
|
||||
* @see PropertyResolver
|
||||
* @see PropertySourcesPropertyResolver
|
||||
* @see MutablePropertySources
|
||||
*/
|
||||
public abstract class PropertySource<T> {
|
||||
|
||||
protected static final String[] EMPTY_NAMES_ARRAY = new String[0];
|
||||
|
||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
protected final String name;
|
||||
|
||||
protected final T source;
|
||||
|
||||
/**
|
||||
* Create a new {@code PropertySource} with the given name and source object.
|
||||
*/
|
||||
public PropertySource(String name, T source) {
|
||||
Assert.hasText(name, "Property source name must contain at least one character");
|
||||
Assert.notNull(source, "Property source must not be null");
|
||||
this.name = name;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of this {@code PropertySource}
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying source object for this {@code PropertySource}.
|
||||
*/
|
||||
public T getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public abstract boolean containsProperty(String key);
|
||||
/**
|
||||
* Return the names of all properties contained by the {@linkplain #getSource() source}
|
||||
* object (never {@code null}).
|
||||
*/
|
||||
public abstract String[] getPropertyNames();
|
||||
|
||||
/**
|
||||
* Return the value associated with the given key, {@code null} if not found.
|
||||
* @param key the property key to find
|
||||
* @see PropertyResolver#getRequiredProperty(String)
|
||||
*/
|
||||
public abstract String getProperty(String key);
|
||||
|
||||
public abstract int size();
|
||||
/**
|
||||
* Return whether this {@code PropertySource} contains a property with the given key.
|
||||
* @param key the property key to find
|
||||
*/
|
||||
public boolean containsProperty(String name) {
|
||||
Assert.notNull(name, "property name must not be null");
|
||||
for (String candidate : this.getPropertyNames()) {
|
||||
if (candidate.equals(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of unique property keys available to this {@code PropertySource}.
|
||||
*/
|
||||
public int size() {
|
||||
return this.getPropertyNames().length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hashcode derived from the {@code name} property of this {@code PropertySource}
|
||||
* object.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This {@code PropertySource} object is equal to the given object if:
|
||||
* <ul>
|
||||
* <li>they are the same instance
|
||||
* <li>the {@code name} properties for both objects are equal
|
||||
* </ul>
|
||||
*
|
||||
* <P>No properties other than {@code name} are evaluated.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
|
|
@ -64,10 +143,10 @@ public abstract class PropertySource<T> {
|
|||
if (!(obj instanceof PropertySource))
|
||||
return false;
|
||||
PropertySource<?> other = (PropertySource<?>) obj;
|
||||
if (name == null) {
|
||||
if (this.name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
} else if (!this.name.equals(other.name))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -87,17 +166,35 @@ public abstract class PropertySource<T> {
|
|||
public String toString() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
return String.format("%s@%s [name='%s', properties=%s]",
|
||||
getClass().getSimpleName(), System.identityHashCode(this), name, source);
|
||||
this.getClass().getSimpleName(), System.identityHashCode(this), this.name, this.source);
|
||||
}
|
||||
|
||||
return String.format("%s [name='%s', propertyCount=%d]",
|
||||
getClass().getSimpleName(), name, this.size());
|
||||
this.getClass().getSimpleName(), this.name, this.size());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* For collection comparison purposes
|
||||
* TODO SPR-7508: document
|
||||
* Return a {@code PropertySource} implementation intended for collection comparison purposes only.
|
||||
*
|
||||
* <p>Primarily for internal use, but given a collection of {@code PropertySource} objects, may be
|
||||
* used as follows:
|
||||
* <pre class="code">
|
||||
* {@code
|
||||
* List<PropertySource<?>> sources = new ArrayList<PropertySource<?>>();
|
||||
* sources.add(new MapPropertySource("sourceA", mapA));
|
||||
* sources.add(new MapPropertySource("sourceB", mapB));
|
||||
* assert sources.contains(PropertySource.named("sourceA"));
|
||||
* assert sources.contains(PropertySource.named("sourceB"));
|
||||
* assert !sources.contains(PropertySource.named("sourceC"));
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>The returned {@code PropertySource} will throw {@code UnsupportedOperationException}
|
||||
* if any methods other than {@code equals(Object)}, {@code hashCode()}, and {@code toString()}
|
||||
* are called.
|
||||
*
|
||||
* @param name the name of the comparison {@code PropertySource} to be created and returned.
|
||||
*/
|
||||
public static PropertySource<?> named(String name) {
|
||||
return new ComparisonPropertySource(name);
|
||||
|
|
@ -105,35 +202,69 @@ public abstract class PropertySource<T> {
|
|||
|
||||
|
||||
/**
|
||||
* TODO: SPR-7508: document
|
||||
* {@code PropertySource} to be used as a placeholder in cases where an actual
|
||||
* property source cannot be eagerly initialized at application context
|
||||
* creation time. For example, a {@code ServletContext}-based property source
|
||||
* must wait until the {@code ServletContext} object is available to its enclosing
|
||||
* {@code ApplicationContext}. In such cases, a stub should be used to hold the
|
||||
* intended default position/order of the property source, then be replaced
|
||||
* during context refresh.
|
||||
*
|
||||
* @see org.springframework.context.support.AbstractApplicationContext#initPropertySources()
|
||||
* @see org.springframework.web.context.support.DefaultWebEnvironment
|
||||
* @see org.springframework.web.context.support.ServletContextPropertySource
|
||||
*/
|
||||
public static class ComparisonPropertySource extends PropertySource<Void>{
|
||||
public static class StubPropertySource extends PropertySource<Object> {
|
||||
|
||||
public StubPropertySource(String name) {
|
||||
super(name, new Object());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProperty(String key) {
|
||||
// TODO SPR-7408: logging
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPropertyNames() {
|
||||
return EMPTY_NAMES_ARRAY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see PropertySource#named(String)
|
||||
*/
|
||||
static class ComparisonPropertySource extends StubPropertySource {
|
||||
|
||||
private static final String USAGE_ERROR =
|
||||
"ComparisonPropertySource instances are for collection comparison " +
|
||||
"use only";
|
||||
|
||||
public ComparisonPropertySource(String name) {
|
||||
super(name, null);
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void getSource() {
|
||||
public Object getSource() {
|
||||
throw new UnsupportedOperationException(USAGE_ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPropertyNames() {
|
||||
throw new UnsupportedOperationException(USAGE_ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
return String.format("%s [name='%s']", getClass().getSimpleName(), this.name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,16 +16,17 @@
|
|||
|
||||
package org.springframework.core.env;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 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";
|
||||
public interface PropertySources {
|
||||
|
||||
PropertySource<?> get(String propertySourceName);
|
||||
|
||||
List<PropertySource<?>> asList();
|
||||
|
||||
int size();
|
||||
|
||||
boolean contains(String propertySourceName);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright 2002-2011 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 java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* {@link PropertyResolver} implementation that resolves property values against
|
||||
* an underlying set of {@link PropertySources}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
|
||||
|
||||
private final PropertySources propertySources;
|
||||
|
||||
/**
|
||||
* Create a new resolver against the given property sources.
|
||||
* @param propertySources the set of {@link PropertySource} objects to use
|
||||
*/
|
||||
public PropertySourcesPropertyResolver(PropertySources propertySources) {
|
||||
this.propertySources = propertySources;
|
||||
}
|
||||
|
||||
|
||||
public boolean containsProperty(String key) {
|
||||
for (PropertySource<?> propertySource : this.propertySources.asList()) {
|
||||
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 this.getProperty(key, String.class);
|
||||
}
|
||||
|
||||
public <T> T getProperty(String key, Class<T> targetValueType) {
|
||||
boolean debugEnabled = logger.isDebugEnabled();
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(format("getProperty(\"%s\", %s)", key, targetValueType.getSimpleName()));
|
||||
}
|
||||
|
||||
for (PropertySource<?> propertySource : this.propertySources.asList()) {
|
||||
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 (!this.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 Properties asProperties() {
|
||||
Properties mergedProps = new Properties();
|
||||
List<PropertySource<?>> propertySourcesList = this.propertySources.asList();
|
||||
for (int i = propertySourcesList.size() -1; i >= 0; i--) {
|
||||
PropertySource<?> source = propertySourcesList.get(i);
|
||||
for (String key : source.getPropertyNames()) {
|
||||
mergedProps.put(key, source.getProperty(key));
|
||||
}
|
||||
}
|
||||
return mergedProps;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 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 java.util.Collection;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Read-only {@code Map<String, String>} implementation that is backed by system properties or environment
|
||||
|
|
@ -38,32 +39,16 @@ abstract class ReadOnlySystemAttributesMap implements Map<String, String> {
|
|||
return get(key) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key the name of the system attribute to retrieve
|
||||
* @throws IllegalArgumentException if given key is non-String
|
||||
*/
|
||||
public String get(Object key) {
|
||||
if (key instanceof String) {
|
||||
String attributeName = (String) key;
|
||||
return getSystemAttribute(attributeName);
|
||||
}
|
||||
else {
|
||||
// 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");
|
||||
}
|
||||
Assert.isInstanceOf(String.class, key,
|
||||
String.format("expected key [%s] to be of type String, got %s",
|
||||
key, key.getClass().getName()));
|
||||
|
||||
return this.getSystemAttribute((String) key);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
|
|
|
|||
|
|
@ -21,16 +21,16 @@ import java.io.IOException;
|
|||
|
||||
import org.springframework.core.env.DefaultEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.PropertyResolver;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
* {@link java.beans.PropertyEditor Editor} for {@link Resource}
|
||||
* descriptors, to automatically convert <code>String</code> locations
|
||||
* e.g. <code>"file:C:/myfile.txt"</code> or
|
||||
* <code>"classpath:myfile.txt"</code>) to <code>Resource</code>
|
||||
* properties instead of using a <code>String</code> location property.
|
||||
* descriptors, to automatically convert {@code String} locations
|
||||
* e.g. {@code file:C:/myfile.txt} or {@code classpath:myfile.txt} to
|
||||
* {@code Resource} properties instead of using a {@code String} location property.
|
||||
*
|
||||
* <p>The path may contain <code>${...}</code> placeholders, to be
|
||||
* resolved as {@link Environment} properties: e.g. <code>${user.dir}</code>.
|
||||
|
|
@ -46,7 +46,7 @@ import org.springframework.util.StringUtils;
|
|||
* @see Resource
|
||||
* @see ResourceLoader
|
||||
* @see DefaultResourceLoader
|
||||
* @see org.springframework.env.Environment#resolvePlaceholders
|
||||
* @see Environment#resolvePlaceholders
|
||||
*/
|
||||
public class ResourceEditor extends PropertyEditorSupport {
|
||||
|
||||
|
|
@ -137,9 +137,10 @@ public class ResourceEditor extends PropertyEditorSupport {
|
|||
* @see Environment#resolveRequiredPlaceholders
|
||||
*/
|
||||
protected String resolvePath(String path) {
|
||||
PropertyResolver resolver = environment.getPropertyResolver();
|
||||
return this.ignoreUnresolvablePlaceholders ?
|
||||
environment.resolvePlaceholders(path) :
|
||||
environment.resolveRequiredPlaceholders(path);
|
||||
resolver.resolvePlaceholders(path) :
|
||||
resolver.resolveRequiredPlaceholders(path);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ 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.env.PropertyResolver;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
|
|
@ -196,9 +197,10 @@ public class ResourceArrayPropertyEditor extends PropertyEditorSupport {
|
|||
* @see Environment#resolveRequiredPlaceholders
|
||||
*/
|
||||
protected String resolvePath(String path) {
|
||||
PropertyResolver resolver = environment.getPropertyResolver();
|
||||
return this.ignoreUnresolvablePlaceholders ?
|
||||
environment.resolvePlaceholders(path) :
|
||||
environment.resolveRequiredPlaceholders(path);
|
||||
resolver.resolvePlaceholders(path) :
|
||||
resolver.resolveRequiredPlaceholders(path);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
|
|
@ -301,7 +302,20 @@ public abstract class CollectionUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Adapts an enumeration to an iterator.
|
||||
* Marshal the elements from the given enumeration into an array of the given type.
|
||||
* Enumeration elements must be assignable to the type of the given array. The array
|
||||
* returned will be a different instance than the array given.
|
||||
*/
|
||||
public static <A,E extends A> A[] toArray(Enumeration<E> enumeration, A[] array) {
|
||||
ArrayList<A> elements = new ArrayList<A>();
|
||||
while (enumeration.hasMoreElements()) {
|
||||
elements.add(enumeration.nextElement());
|
||||
}
|
||||
return elements.toArray(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapt an enumeration to an iterator.
|
||||
* @param enumeration the enumeration
|
||||
* @return the iterator
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -25,12 +25,6 @@ import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
|
|||
* <code>${user.dir}</code>. 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
|
||||
|
|
|
|||
|
|
@ -16,412 +16,22 @@
|
|||
|
||||
package org.springframework.core.env;
|
||||
|
||||
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 static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.internal.matchers.TypeSafeMatcher;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.matchers.JUnitMatchers.*;
|
||||
import static org.springframework.core.env.AbstractEnvironment.*;
|
||||
import static org.springframework.core.env.DefaultEnvironmentTests.CollectionMatchers.*;
|
||||
|
||||
/**
|
||||
* 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<PropertySource<?>> propertySources = env.getPropertySources();
|
||||
propertySources.addFirst(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<PropertySource<?>> 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<String, String> nullableProperties = new HashMap<String, String>();
|
||||
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<String> 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(ACTIVE_PROFILES_PROPERTY_NAME, "");
|
||||
assertThat(environment.getActiveProfiles(), isEmpty());
|
||||
|
||||
System.getProperties().remove(ACTIVE_PROFILES_PROPERTY_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void systemPropertiesResoloutionOfProfiles() {
|
||||
assertThat(environment.getActiveProfiles(), isEmpty());
|
||||
|
||||
System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, "foo");
|
||||
assertThat(environment.getActiveProfiles(), hasItem("foo"));
|
||||
|
||||
// clean up
|
||||
System.getProperties().remove(ACTIVE_PROFILES_PROPERTY_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void systemPropertiesResoloutionOfMultipleProfiles() {
|
||||
assertThat(environment.getActiveProfiles(), isEmpty());
|
||||
System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, "foo,bar");
|
||||
assertThat(environment.getActiveProfiles(), hasItems("foo", "bar"));
|
||||
System.getProperties().remove(ACTIVE_PROFILES_PROPERTY_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void systemPropertiesResolutionOfMulitpleProfiles_withWhitespace() {
|
||||
assertThat(environment.getActiveProfiles(), isEmpty());
|
||||
System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, " bar , baz "); // notice whitespace
|
||||
assertThat(environment.getActiveProfiles(), hasItems("bar", "baz"));
|
||||
System.getProperties().remove(ACTIVE_PROFILES_PROPERTY_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void environmentResolutionOfDefaultSpringProfileProperty_noneSet() {
|
||||
assertThat(environment.getDefaultProfiles(), isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void environmentResolutionOfDefaultSpringProfileProperty_isSet() {
|
||||
testProperties.setProperty(DEFAULT_PROFILES_PROPERTY_NAME, "custom-default");
|
||||
assertTrue(environment.getDefaultProfiles().contains("custom-default"));
|
||||
}
|
||||
|
||||
@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<String, String> 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<String, String> 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'"));
|
||||
}
|
||||
}
|
||||
|
||||
public static class CollectionMatchers {
|
||||
public static Matcher<Collection<?>> isEmpty() {
|
||||
|
||||
return new TypeSafeMatcher<Collection<?>>() {
|
||||
|
||||
@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<String, String> getModifiableSystemEnvironment() throws Exception {
|
||||
Class<?>[] classes = Collections.class.getDeclaredClasses();
|
||||
Map<String, String> 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<String, String>) obj;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
public void propertySourceOrder() {
|
||||
ConfigurableEnvironment env = new DefaultEnvironment();
|
||||
List<PropertySource<?>> sources = env.getPropertySources().asList();
|
||||
assertThat(sources.size(), is(2));
|
||||
assertThat(sources.get(0).getName(), equalTo(DefaultEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME));
|
||||
assertThat(sources.get(1).getName(), equalTo(DefaultEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
}
|
||||
}
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* 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<String, String> 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<String, String> getModifiableSystemEnvironment() throws Exception {
|
||||
Class<?>[] classes = Collections.class.getDeclaredClasses();
|
||||
Map<String, String> 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<String, String>) obj;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
}
|
||||
288
org.springframework.core/src/test/java/org/springframework/core/env/EnvironmentTests.java
vendored
Normal file
288
org.springframework.core/src/test/java/org/springframework/core/env/EnvironmentTests.java
vendored
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
* 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.ACTIVE_PROFILES_PROPERTY_NAME;
|
||||
import static org.springframework.core.env.AbstractEnvironment.DEFAULT_PROFILES_PROPERTY_NAME;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.security.AccessControlException;
|
||||
import java.security.Permission;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.env.MockPropertySource;
|
||||
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DefaultEnvironment}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public class EnvironmentTests {
|
||||
|
||||
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 = new DefaultEnvironment();
|
||||
|
||||
@Test
|
||||
public void activeProfiles() {
|
||||
assertThat(environment.getActiveProfiles().length, is(0));
|
||||
environment.setActiveProfiles("local", "embedded");
|
||||
String[] activeProfiles = environment.getActiveProfiles();
|
||||
assertThat(Arrays.asList(activeProfiles), hasItems("local", "embedded"));
|
||||
assertThat(activeProfiles.length, is(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getActiveProfiles_systemPropertiesEmpty() {
|
||||
assertThat(environment.getActiveProfiles().length, is(0));
|
||||
System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, "");
|
||||
assertThat(environment.getActiveProfiles().length, is(0));
|
||||
System.getProperties().remove(ACTIVE_PROFILES_PROPERTY_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getActiveProfiles_fromSystemProperties() {
|
||||
assertThat(environment.getActiveProfiles().length, is(0));
|
||||
System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, "foo");
|
||||
assertThat(Arrays.asList(environment.getActiveProfiles()), hasItem("foo"));
|
||||
System.getProperties().remove(ACTIVE_PROFILES_PROPERTY_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getActiveProfiles_fromSystemProperties_withMultipleProfiles() {
|
||||
assertThat(environment.getActiveProfiles().length, is(0));
|
||||
System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, "foo,bar");
|
||||
assertThat(Arrays.asList(environment.getActiveProfiles()), hasItems("foo", "bar"));
|
||||
System.getProperties().remove(ACTIVE_PROFILES_PROPERTY_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getActiveProfiles_fromSystemProperties_withMulitpleProfiles_withWhitespace() {
|
||||
assertThat(environment.getActiveProfiles().length, is(0));
|
||||
System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, " bar , baz "); // notice whitespace
|
||||
assertThat(Arrays.asList(environment.getActiveProfiles()), hasItems("bar", "baz"));
|
||||
System.getProperties().remove(ACTIVE_PROFILES_PROPERTY_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDefaultProfiles() {
|
||||
assertThat(environment.getDefaultProfiles().length, is(0));
|
||||
environment.getPropertySources().addFirst(new MockPropertySource().withProperty(DEFAULT_PROFILES_PROPERTY_NAME, "pd1"));
|
||||
assertThat(environment.getDefaultProfiles().length, is(1));
|
||||
assertThat(Arrays.asList(environment.getDefaultProfiles()), hasItem("pd1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setDefaultProfiles() {
|
||||
environment.setDefaultProfiles();
|
||||
assertThat(environment.getDefaultProfiles().length, is(0));
|
||||
environment.setDefaultProfiles("pd1");
|
||||
assertThat(Arrays.asList(environment.getDefaultProfiles()), hasItem("pd1"));
|
||||
environment.setDefaultProfiles("pd2", "pd3");
|
||||
assertThat(Arrays.asList(environment.getDefaultProfiles()), not(hasItem("pd1")));
|
||||
assertThat(Arrays.asList(environment.getDefaultProfiles()), hasItems("pd2", "pd3"));
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void acceptsProfiles_mustSpecifyAtLeastOne() {
|
||||
environment.acceptsProfiles();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void acceptsProfiles_activeProfileSetProgrammatically() {
|
||||
assertThat(environment.acceptsProfiles("p1", "p2"), is(false));
|
||||
environment.setActiveProfiles("p1");
|
||||
assertThat(environment.acceptsProfiles("p1", "p2"), is(true));
|
||||
environment.setActiveProfiles("p2");
|
||||
assertThat(environment.acceptsProfiles("p1", "p2"), is(true));
|
||||
environment.setActiveProfiles("p1", "p2");
|
||||
assertThat(environment.acceptsProfiles("p1", "p2"), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void acceptsProfiles_activeProfileSetViaProperty() {
|
||||
assertThat(environment.acceptsProfiles("p1"), is(false));
|
||||
environment.getPropertySources().addFirst(new MockPropertySource().withProperty(ACTIVE_PROFILES_PROPERTY_NAME, "p1"));
|
||||
assertThat(environment.acceptsProfiles("p1"), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void acceptsProfiles_defaultProfile() {
|
||||
assertThat(environment.acceptsProfiles("pd"), is(false));
|
||||
environment.setDefaultProfiles("pd");
|
||||
assertThat(environment.acceptsProfiles("pd"), is(true));
|
||||
environment.setActiveProfiles("p1");
|
||||
assertThat(environment.acceptsProfiles("pd"), is(false));
|
||||
assertThat(environment.acceptsProfiles("p1"), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSystemProperties_withAndWithoutSecurityManager() {
|
||||
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 IllegalArgumentException when searching with non-string key against ReadOnlySystemAttributesMap");
|
||||
} catch (IllegalArgumentException 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 getSystemEnvironment_withAndWithoutSecurityManager() throws Exception {
|
||||
getModifiableSystemEnvironment().put(ALLOWED_PROPERTY_NAME, ALLOWED_PROPERTY_VALUE);
|
||||
getModifiableSystemEnvironment().put(DISALLOWED_PROPERTY_NAME, DISALLOWED_PROPERTY_VALUE);
|
||||
|
||||
{
|
||||
Map<String, String> 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<String, String> 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);
|
||||
}
|
||||
|
||||
// TODO SPR-7508: duplicated from EnvironmentPropertyResolutionSearchTests
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Map<String, String> getModifiableSystemEnvironment() throws Exception {
|
||||
Class<?>[] classes = Collections.class.getDeclaredClasses();
|
||||
Map<String, String> 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<String, String>) obj;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
282
org.springframework.core/src/test/java/org/springframework/core/env/PropertyResolverTests.java
vendored
Normal file
282
org.springframework.core/src/test/java/org/springframework/core/env/PropertyResolverTests.java
vendored
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
* 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.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.env.MockPropertySource;
|
||||
|
||||
|
||||
/**
|
||||
* Unit tests for {@link PropertyResolver}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see PropertySourcesPropertyResolver
|
||||
*/
|
||||
public class PropertyResolverTests {
|
||||
private Properties testProperties;
|
||||
private MutablePropertySources propertySources;
|
||||
private ConfigurablePropertyResolver propertyResolver;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
propertySources = new MutablePropertySources();
|
||||
propertyResolver = new PropertySourcesPropertyResolver(propertySources);
|
||||
testProperties = new Properties();
|
||||
propertySources.addFirst(new PropertiesPropertySource("testProperties", testProperties));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void containsProperty() {
|
||||
assertThat(propertyResolver.containsProperty("foo"), is(false));
|
||||
testProperties.put("foo", "bar");
|
||||
assertThat(propertyResolver.containsProperty("foo"), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getProperty() {
|
||||
assertThat(propertyResolver.getProperty("foo"), nullValue());
|
||||
testProperties.put("foo", "bar");
|
||||
assertThat(propertyResolver.getProperty("foo"), is("bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getProperty_propertySourceSearchOrderIsFIFO() {
|
||||
MutablePropertySources sources = new MutablePropertySources();
|
||||
PropertyResolver resolver = new PropertySourcesPropertyResolver(sources);
|
||||
sources.addFirst(new MockPropertySource("ps1").withProperty("pName", "ps1Value"));
|
||||
assertThat(resolver.getProperty("pName"), equalTo("ps1Value"));
|
||||
sources.addFirst(new MockPropertySource("ps2").withProperty("pName", "ps2Value"));
|
||||
assertThat(resolver.getProperty("pName"), equalTo("ps2Value"));
|
||||
sources.addFirst(new MockPropertySource("ps3").withProperty("pName", "ps3Value"));
|
||||
assertThat(resolver.getProperty("pName"), equalTo("ps3Value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getProperty_withExplicitNullValue() {
|
||||
// java.util.Properties does not allow null values (because Hashtable does not)
|
||||
Map<String, String> nullableProperties = new HashMap<String, String>();
|
||||
propertySources.addLast(new MapPropertySource("nullableProperties", nullableProperties));
|
||||
nullableProperties.put("foo", null);
|
||||
assertThat(propertyResolver.getProperty("foo"), nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getProperty_withStringArrayConversion() {
|
||||
testProperties.put("foo", "bar,baz");
|
||||
assertThat(propertyResolver.getProperty("foo", String[].class), equalTo(new String[] { "bar", "baz" }));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void getProperty_withNonConvertibleTargetType() {
|
||||
testProperties.put("foo", "bar");
|
||||
|
||||
class TestType { }
|
||||
|
||||
try {
|
||||
propertyResolver.getProperty("foo", TestType.class);
|
||||
fail("Expected IllegalArgumentException due to non-convertible types");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getProperty_doesNotCache_replaceExistingKeyPostConstruction() {
|
||||
String key = "foo";
|
||||
String value1 = "bar";
|
||||
String value2 = "biz";
|
||||
|
||||
HashMap<String, String> map = new HashMap<String, String>();
|
||||
map.put(key, value1); // before construction
|
||||
MutablePropertySources propertySources = new MutablePropertySources();
|
||||
propertySources.addFirst(new MapPropertySource("testProperties", map));
|
||||
PropertyResolver propertyResolver = new PropertySourcesPropertyResolver(propertySources);
|
||||
assertThat(propertyResolver.getProperty(key), equalTo(value1));
|
||||
map.put(key, value2); // after construction and first resolution
|
||||
assertThat(propertyResolver.getProperty(key), equalTo(value2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getProperty_doesNotCache_addNewKeyPostConstruction() {
|
||||
HashMap<String, String> map = new HashMap<String, String>();
|
||||
MutablePropertySources propertySources = new MutablePropertySources();
|
||||
propertySources.addFirst(new MapPropertySource("testProperties", map));
|
||||
PropertyResolver propertyResolver = new PropertySourcesPropertyResolver(propertySources);
|
||||
assertThat(propertyResolver.getProperty("foo"), equalTo(null));
|
||||
map.put("foo", "42");
|
||||
assertThat(propertyResolver.getProperty("foo"), equalTo("42"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPropertySources_replacePropertySource() {
|
||||
propertySources = new MutablePropertySources();
|
||||
propertyResolver = new PropertySourcesPropertyResolver(propertySources);
|
||||
propertySources.addLast(new MockPropertySource("local").withProperty("foo", "localValue"));
|
||||
propertySources.addLast(new MockPropertySource("system").withProperty("foo", "systemValue"));
|
||||
|
||||
// 'local' was added first so has precedence
|
||||
assertThat(propertyResolver.getProperty("foo"), equalTo("localValue"));
|
||||
|
||||
// replace 'local' with new property source
|
||||
propertySources.replace("local", new MockPropertySource("new").withProperty("foo", "newValue"));
|
||||
|
||||
// 'system' now has precedence
|
||||
assertThat(propertyResolver.getProperty("foo"), equalTo("newValue"));
|
||||
|
||||
assertThat(propertySources.size(), is(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRequiredProperty() {
|
||||
testProperties.put("exists", "xyz");
|
||||
assertThat(propertyResolver.getRequiredProperty("exists"), is("xyz"));
|
||||
|
||||
try {
|
||||
propertyResolver.getRequiredProperty("bogus");
|
||||
fail("expected IllegalStateException");
|
||||
} catch (IllegalStateException ex) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRequiredProperty_withStringArrayConversion() {
|
||||
testProperties.put("exists", "abc,123");
|
||||
assertThat(propertyResolver.getRequiredProperty("exists", String[].class), equalTo(new String[] { "abc", "123" }));
|
||||
|
||||
try {
|
||||
propertyResolver.getRequiredProperty("bogus", String[].class);
|
||||
fail("expected IllegalStateException");
|
||||
} catch (IllegalStateException ex) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asProperties() {
|
||||
propertySources = new MutablePropertySources();
|
||||
propertyResolver = new PropertySourcesPropertyResolver(propertySources);
|
||||
assertThat(propertyResolver.asProperties(), notNullValue());
|
||||
|
||||
propertySources.addLast(new MockPropertySource("highestPrecedence").withProperty("common", "highCommon").withProperty("highKey", "highVal"));
|
||||
propertySources.addLast(new MockPropertySource("middlePrecedence").withProperty("common", "midCommon").withProperty("midKey", "midVal"));
|
||||
propertySources.addLast(new MockPropertySource("lowestPrecedence").withProperty("common", "lowCommon").withProperty("lowKey", "lowVal"));
|
||||
|
||||
Properties props = propertyResolver.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 asProperties_withMixedPropertySourceTypes() {
|
||||
class Foo { }
|
||||
class FooPropertySource extends PropertySource<Foo> {
|
||||
public FooPropertySource() { super("fooProperties", new Foo()); }
|
||||
public String[] getPropertyNames() { return new String[] {"pName"}; }
|
||||
public String getProperty(String key) { return "fooValue"; }
|
||||
}
|
||||
propertySources = new MutablePropertySources();
|
||||
propertyResolver = new PropertySourcesPropertyResolver(propertySources);
|
||||
assertThat(propertyResolver.asProperties(), notNullValue());
|
||||
|
||||
propertySources.addLast(new MockPropertySource());
|
||||
propertySources.addLast(new FooPropertySource());
|
||||
|
||||
Properties props = propertyResolver.asProperties();
|
||||
assertThat(props.getProperty("pName"), is("fooValue"));
|
||||
assertThat(props.size(), is(1));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void resolvePlaceholders() {
|
||||
MutablePropertySources propertySources = new MutablePropertySources();
|
||||
propertySources.addFirst(new MockPropertySource().withProperty("key", "value"));
|
||||
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
|
||||
assertThat(resolver.resolvePlaceholders("Replace this ${key}"), equalTo("Replace this value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePlaceholders_withUnresolvable() {
|
||||
MutablePropertySources propertySources = new MutablePropertySources();
|
||||
propertySources.addFirst(new MockPropertySource().withProperty("key", "value"));
|
||||
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
|
||||
assertThat(resolver.resolvePlaceholders("Replace this ${key} plus ${unknown}"),
|
||||
equalTo("Replace this value plus ${unknown}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvePlaceholders_withDefault() {
|
||||
MutablePropertySources propertySources = new MutablePropertySources();
|
||||
propertySources.addFirst(new MockPropertySource().withProperty("key", "value"));
|
||||
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
|
||||
assertThat(resolver.resolvePlaceholders("Replace this ${key} plus ${unknown:defaultValue}"),
|
||||
equalTo("Replace this value plus defaultValue"));
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void resolvePlaceholders_withNullInput() {
|
||||
new PropertySourcesPropertyResolver(new MutablePropertySources()).resolvePlaceholders(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveRequiredPlaceholders() {
|
||||
MutablePropertySources propertySources = new MutablePropertySources();
|
||||
propertySources.addFirst(new MockPropertySource().withProperty("key", "value"));
|
||||
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
|
||||
assertThat(resolver.resolveRequiredPlaceholders("Replace this ${key}"), equalTo("Replace this value"));
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void resolveRequiredPlaceholders_withUnresolvable() {
|
||||
MutablePropertySources propertySources = new MutablePropertySources();
|
||||
propertySources.addFirst(new MockPropertySource().withProperty("key", "value"));
|
||||
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
|
||||
resolver.resolveRequiredPlaceholders("Replace this ${key} plus ${unknown}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveRequiredPlaceholders_withDefault() {
|
||||
MutablePropertySources propertySources = new MutablePropertySources();
|
||||
propertySources.addFirst(new MockPropertySource().withProperty("key", "value"));
|
||||
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
|
||||
assertThat(resolver.resolveRequiredPlaceholders("Replace this ${key} plus ${unknown:defaultValue}"),
|
||||
equalTo("Replace this value plus defaultValue"));
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void resolveRequiredPlaceholders_withNullInput() {
|
||||
new PropertySourcesPropertyResolver(new MutablePropertySources()).resolveRequiredPlaceholders(null);
|
||||
}
|
||||
}
|
||||
|
|
@ -20,8 +20,9 @@ import static org.hamcrest.CoreMatchers.equalTo;
|
|||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
|
|
@ -66,7 +67,7 @@ public class PropertySourceTests {
|
|||
|
||||
PropertySource<?> ps1 = new MapPropertySource("ps1", map1);
|
||||
ps1.getSource();
|
||||
LinkedList<PropertySource<?>> propertySources = new LinkedList<PropertySource<?>>();
|
||||
List<PropertySource<?>> propertySources = new ArrayList<PropertySource<?>>();
|
||||
assertThat(propertySources.add(ps1), equalTo(true));
|
||||
assertThat(propertySources.contains(ps1), is(true));
|
||||
assertThat(propertySources.contains(PropertySource.named("ps1")), is(true));
|
||||
|
|
|
|||
149
org.springframework.core/src/test/java/org/springframework/core/env/PropertySourcesTests.java
vendored
Normal file
149
org.springframework.core/src/test/java/org/springframework/core/env/PropertySourcesTests.java
vendored
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* 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.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.env.MockPropertySource;
|
||||
|
||||
public class PropertySourcesTests {
|
||||
@Test
|
||||
public void test() {
|
||||
MutablePropertySources sources = new MutablePropertySources();
|
||||
sources.addLast(new MockPropertySource("b").withProperty("p1", "bValue"));
|
||||
sources.addLast(new MockPropertySource("d").withProperty("p1", "dValue"));
|
||||
sources.addLast(new MockPropertySource("f").withProperty("p1", "fValue"));
|
||||
|
||||
assertThat(sources.size(), equalTo(3));
|
||||
assertThat(sources.contains("a"), is(false));
|
||||
assertThat(sources.contains("b"), is(true));
|
||||
assertThat(sources.contains("c"), is(false));
|
||||
assertThat(sources.contains("d"), is(true));
|
||||
assertThat(sources.contains("e"), is(false));
|
||||
assertThat(sources.contains("f"), is(true));
|
||||
assertThat(sources.contains("g"), is(false));
|
||||
|
||||
assertThat(sources.get("b"), not(nullValue()));
|
||||
assertThat(sources.get("b").getProperty("p1"), equalTo("bValue"));
|
||||
assertThat(sources.get("d"), not(nullValue()));
|
||||
assertThat(sources.get("d").getProperty("p1"), equalTo("dValue"));
|
||||
|
||||
sources.addBefore("b", new MockPropertySource("a"));
|
||||
sources.addAfter("b", new MockPropertySource("c"));
|
||||
|
||||
assertThat(sources.size(), equalTo(5));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("a")), is(0));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("b")), is(1));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("c")), is(2));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("d")), is(3));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("f")), is(4));
|
||||
|
||||
sources.addBefore("f", new MockPropertySource("e"));
|
||||
sources.addAfter("f", new MockPropertySource("g"));
|
||||
|
||||
assertThat(sources.size(), equalTo(7));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("a")), is(0));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("b")), is(1));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("c")), is(2));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("d")), is(3));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("e")), is(4));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("f")), is(5));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("g")), is(6));
|
||||
|
||||
sources.addLast(new MockPropertySource("a"));
|
||||
assertThat(sources.size(), equalTo(7));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("b")), is(0));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("c")), is(1));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("d")), is(2));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("e")), is(3));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("f")), is(4));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("g")), is(5));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("a")), is(6));
|
||||
|
||||
sources.addFirst(new MockPropertySource("a"));
|
||||
assertThat(sources.size(), equalTo(7));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("a")), is(0));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("b")), is(1));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("c")), is(2));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("d")), is(3));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("e")), is(4));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("f")), is(5));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("g")), is(6));
|
||||
|
||||
assertEquals(sources.remove("a"), PropertySource.named("a"));
|
||||
assertThat(sources.size(), equalTo(6));
|
||||
assertThat(sources.contains("a"), is(false));
|
||||
|
||||
assertEquals(sources.remove("a"), null);
|
||||
assertThat(sources.size(), equalTo(6));
|
||||
|
||||
String bogusPS = "bogus";
|
||||
try {
|
||||
sources.addAfter(bogusPS, new MockPropertySource("h"));
|
||||
fail("expected non-existent PropertySource exception");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertThat(ex.getMessage(),
|
||||
equalTo(String.format(MutablePropertySources.NON_EXISTENT_PROPERTY_SOURCE_MESSAGE, bogusPS)));
|
||||
}
|
||||
|
||||
sources.addFirst(new MockPropertySource("a"));
|
||||
assertThat(sources.size(), equalTo(7));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("a")), is(0));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("b")), is(1));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("c")), is(2));
|
||||
|
||||
sources.replace("a", new MockPropertySource("a-replaced"));
|
||||
assertThat(sources.size(), equalTo(7));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("a-replaced")), is(0));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("b")), is(1));
|
||||
assertThat(sources.asList().indexOf(PropertySource.named("c")), is(2));
|
||||
|
||||
sources.replace("a-replaced", new MockPropertySource("a"));
|
||||
|
||||
try {
|
||||
sources.replace(bogusPS, new MockPropertySource("bogus-replaced"));
|
||||
fail("expected non-existent PropertySource exception");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertThat(ex.getMessage(),
|
||||
equalTo(String.format(MutablePropertySources.NON_EXISTENT_PROPERTY_SOURCE_MESSAGE, bogusPS)));
|
||||
}
|
||||
|
||||
try {
|
||||
sources.addBefore("b", new MockPropertySource("b"));
|
||||
fail("expected exception");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertThat(ex.getMessage(),
|
||||
equalTo(String.format(MutablePropertySources.ILLEGAL_RELATIVE_ADDITION_MESSAGE, "b")));
|
||||
}
|
||||
|
||||
try {
|
||||
sources.addAfter("b", new MockPropertySource("b"));
|
||||
fail("expected exception");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertThat(ex.getMessage(),
|
||||
equalTo(String.format(MutablePropertySources.ILLEGAL_RELATIVE_ADDITION_MESSAGE, "b")));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
103
org.springframework.core/src/test/java/org/springframework/mock/env/MockPropertySource.java
vendored
Normal file
103
org.springframework.core/src/test/java/org/springframework/mock/env/MockPropertySource.java
vendored
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright 2002-2011 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;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
|
||||
/**
|
||||
* Simple {@link PropertySource} implementation for use in testing. Accepts
|
||||
* a user-provided {@link Properties} object, or if omitted during construction,
|
||||
* the implementation will initialize its own.
|
||||
*
|
||||
* The {@link #setProperty} and {@link #withProperty} methods are exposed for
|
||||
* convenience, for example:
|
||||
* <pre>
|
||||
* {@code
|
||||
* PropertySource<?> source = new MockPropertySource().withProperty("foo", "bar");
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see MockEnvironment
|
||||
*/
|
||||
public class MockPropertySource extends PropertiesPropertySource {
|
||||
|
||||
/**
|
||||
* {@value} is the default name for {@link MockPropertySource} instances not
|
||||
* otherwise given an explicit name.
|
||||
* @see #MockPropertySource()
|
||||
* @see #MockPropertySource(String)
|
||||
*/
|
||||
public static final String MOCK_PROPERTIES_PROPERTY_SOURCE_NAME = "mockProperties";
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} named {@value #MOCK_PROPERTIES_PROPERTY_SOURCE_NAME}
|
||||
* that will maintain its own internal {@link Properties} instance.
|
||||
*/
|
||||
public MockPropertySource() {
|
||||
this(new Properties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} with the given name that will
|
||||
* maintain its own internal {@link Properties} instance.
|
||||
* @param name the {@linkplain #getName() name} of the property source
|
||||
*/
|
||||
public MockPropertySource(String name) {
|
||||
this(name, new Properties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} named {@value #MOCK_PROPERTIES_PROPERTY_SOURCE_NAME}
|
||||
* and backed by the given {@link Properties} object.
|
||||
* @param properties the properties to use
|
||||
*/
|
||||
public MockPropertySource(Properties properties) {
|
||||
this(MOCK_PROPERTIES_PROPERTY_SOURCE_NAME, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} with with the given name and backed by the given
|
||||
* {@link Properties} object
|
||||
* @param name the {@linkplain #getName() name} of the property source
|
||||
* @param properties the properties to use
|
||||
*/
|
||||
public MockPropertySource(String name, Properties properties) {
|
||||
super(name, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given property on the underlying {@link Properties} object.
|
||||
*/
|
||||
public void setProperty(String key, String value) {
|
||||
this.source.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient synonym for {@link #setProperty} that returns the current instance.
|
||||
* Useful for method chaining and fluent-style use.
|
||||
* @return this {@link MockPropertySource} instance
|
||||
*/
|
||||
public MockPropertySource withProperty(String key, String value) {
|
||||
this.setProperty(key, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
103
org.springframework.expression/src/test/java/org/springframework/mock/env/MockPropertySource.java
vendored
Normal file
103
org.springframework.expression/src/test/java/org/springframework/mock/env/MockPropertySource.java
vendored
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright 2002-2011 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;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
|
||||
/**
|
||||
* Simple {@link PropertySource} implementation for use in testing. Accepts
|
||||
* a user-provided {@link Properties} object, or if omitted during construction,
|
||||
* the implementation will initialize its own.
|
||||
*
|
||||
* The {@link #setProperty} and {@link #withProperty} methods are exposed for
|
||||
* convenience, for example:
|
||||
* <pre>
|
||||
* {@code
|
||||
* PropertySource<?> source = new MockPropertySource().withProperty("foo", "bar");
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see MockEnvironment
|
||||
*/
|
||||
public class MockPropertySource extends PropertiesPropertySource {
|
||||
|
||||
/**
|
||||
* {@value} is the default name for {@link MockPropertySource} instances not
|
||||
* otherwise given an explicit name.
|
||||
* @see #MockPropertySource()
|
||||
* @see #MockPropertySource(String)
|
||||
*/
|
||||
public static final String MOCK_PROPERTIES_PROPERTY_SOURCE_NAME = "mockProperties";
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} named {@value #MOCK_PROPERTIES_PROPERTY_SOURCE_NAME}
|
||||
* that will maintain its own internal {@link Properties} instance.
|
||||
*/
|
||||
public MockPropertySource() {
|
||||
this(new Properties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} with the given name that will
|
||||
* maintain its own internal {@link Properties} instance.
|
||||
* @param name the {@linkplain #getName() name} of the property source
|
||||
*/
|
||||
public MockPropertySource(String name) {
|
||||
this(name, new Properties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} named {@value #MOCK_PROPERTIES_PROPERTY_SOURCE_NAME}
|
||||
* and backed by the given {@link Properties} object.
|
||||
* @param properties the properties to use
|
||||
*/
|
||||
public MockPropertySource(Properties properties) {
|
||||
this(MOCK_PROPERTIES_PROPERTY_SOURCE_NAME, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} with with the given name and backed by the given
|
||||
* {@link Properties} object
|
||||
* @param name the {@linkplain #getName() name} of the property source
|
||||
* @param properties the properties to use
|
||||
*/
|
||||
public MockPropertySource(String name, Properties properties) {
|
||||
super(name, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given property on the underlying {@link Properties} object.
|
||||
*/
|
||||
public void setProperty(String key, String value) {
|
||||
this.source.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient synonym for {@link #setProperty} that returns the current instance.
|
||||
* Useful for method chaining and fluent-style use.
|
||||
* @return this {@link MockPropertySource} instance
|
||||
*/
|
||||
public MockPropertySource withProperty(String key, String value) {
|
||||
this.setProperty(key, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -18,9 +18,7 @@ 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;
|
||||
|
|
@ -37,8 +35,6 @@ import static org.springframework.core.env.EnvironmentIntegrationTests.Constants
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
|
@ -64,16 +60,19 @@ 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.env.MockPropertySource;
|
||||
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.DefaultWebEnvironment;
|
||||
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.DefaultPortletEnvironment;
|
||||
import org.springframework.web.portlet.context.StaticPortletApplicationContext;
|
||||
import org.springframework.web.portlet.context.XmlPortletApplicationContext;
|
||||
|
||||
|
|
@ -433,34 +432,33 @@ public class EnvironmentIntegrationTests {
|
|||
|
||||
ConfigurableEnvironment environment = ctx.getEnvironment();
|
||||
assertThat(environment, instanceOf(DefaultWebEnvironment.class));
|
||||
LinkedList<PropertySource<?>> 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));
|
||||
MutablePropertySources propertySources = environment.getPropertySources();
|
||||
PropertyResolver propertyResolver = environment.getPropertyResolver();
|
||||
assertThat(propertySources.contains(DefaultWebEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME), is(true));
|
||||
assertThat(propertySources.contains(DefaultWebEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME), is(true));
|
||||
|
||||
// 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))));
|
||||
assertThat(propertyResolver.getProperty("pCommon"), is("pCommonConfigValue"));
|
||||
assertThat(propertySources.asList().indexOf(PropertySource.named(DefaultWebEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME)),
|
||||
lessThan(propertySources.asList().indexOf(PropertySource.named(DefaultWebEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME))));
|
||||
|
||||
// but all params are available
|
||||
assertThat(environment.getProperty("pContext1"), is("pContext1Value"));
|
||||
assertThat(environment.getProperty("pConfig1"), is("pConfig1Value"));
|
||||
assertThat(propertyResolver.getProperty("pContext1"), is("pContext1Value"));
|
||||
assertThat(propertyResolver.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))));
|
||||
assertThat(propertySources.asList().indexOf(PropertySource.named(DefaultWebEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME)),
|
||||
lessThan(propertySources.asList().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);
|
||||
propertySources.replace(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"));
|
||||
// assert that servletconfig params resolve with higher precedence than sysprops
|
||||
assertThat(propertyResolver.getProperty("pCommon"), is("pCommonConfigValue"));
|
||||
assertThat(propertyResolver.getProperty("pSysProps1"), is("pSysProps1Value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -475,29 +473,27 @@ public class EnvironmentIntegrationTests {
|
|||
|
||||
ConfigurableEnvironment environment = ctx.getEnvironment();
|
||||
assertThat(environment, instanceOf(DefaultWebEnvironment.class));
|
||||
LinkedList<PropertySource<?>> 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)));
|
||||
MutablePropertySources propertySources = environment.getPropertySources();
|
||||
PropertyResolver propertyResolver = environment.getPropertyResolver();
|
||||
assertThat(propertySources.contains(DefaultWebEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME), is(true));
|
||||
|
||||
// ServletContext params are available
|
||||
assertThat(environment.getProperty("pCommon"), is("pCommonContextValue"));
|
||||
assertThat(environment.getProperty("pContext1"), is("pContext1Value"));
|
||||
assertThat(propertyResolver.getProperty("pCommon"), is("pCommonContextValue"));
|
||||
assertThat(propertyResolver.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))));
|
||||
assertThat(propertySources.asList().indexOf(PropertySource.named(DefaultWebEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME)),
|
||||
lessThan(propertySources.asList().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);
|
||||
propertySources.replace(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"));
|
||||
assertThat(propertyResolver.getProperty("pCommon"), is("pCommonContextValue"));
|
||||
assertThat(propertyResolver.getProperty("pSysProps1"), is("pSysProps1Value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -515,48 +511,33 @@ public class EnvironmentIntegrationTests {
|
|||
ctx.refresh();
|
||||
|
||||
ConfigurableEnvironment environment = ctx.getEnvironment();
|
||||
LinkedList<PropertySource<?>> 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));
|
||||
MutablePropertySources propertySources = environment.getPropertySources();
|
||||
PropertyResolver propertyResolver = environment.getPropertyResolver();
|
||||
assertThat(propertySources.contains(DefaultWebEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME), is(true));
|
||||
assertThat(propertySources.contains(DefaultWebEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME), is(true));
|
||||
|
||||
// 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))));
|
||||
assertThat(propertyResolver.getProperty("pCommon"), is("pCommonConfigValue"));
|
||||
assertThat(propertySources.asList().indexOf(PropertySource.named(DefaultWebEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME)),
|
||||
lessThan(propertySources.asList().indexOf(PropertySource.named(DefaultWebEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME))));
|
||||
|
||||
// but all params are available
|
||||
assertThat(environment.getProperty("pContext1"), is("pContext1Value"));
|
||||
assertThat(environment.getProperty("pConfig1"), is("pConfig1Value"));
|
||||
assertThat(propertyResolver.getProperty("pContext1"), is("pContext1Value"));
|
||||
assertThat(propertyResolver.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))));
|
||||
assertThat(propertySources.asList().indexOf(PropertySource.named(DefaultWebEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME)),
|
||||
lessThan(propertySources.asList().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);
|
||||
propertySources.replace(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);
|
||||
}
|
||||
// assert that servletconfig params resolve with higher precedence than sysprops
|
||||
assertThat(propertyResolver.getProperty("pCommon"), is("pCommonConfigValue"));
|
||||
assertThat(propertyResolver.getProperty("pSysProps1"), is("pSysProps1Value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -580,8 +561,7 @@ public class EnvironmentIntegrationTests {
|
|||
public void staticPortletApplicationContext() {
|
||||
StaticPortletApplicationContext ctx = new StaticPortletApplicationContext();
|
||||
|
||||
// TODO SPR-7508: should be a Portlet-specific environment?
|
||||
assertHasDefaultWebEnvironment(ctx);
|
||||
assertHasDefaultPortletEnvironment(ctx);
|
||||
|
||||
registerEnvironmentBeanDefinition(ctx);
|
||||
|
||||
|
|
@ -638,6 +618,12 @@ public class EnvironmentIntegrationTests {
|
|||
assertThat(defaultEnv, instanceOf(DefaultWebEnvironment.class));
|
||||
}
|
||||
|
||||
private void assertHasDefaultPortletEnvironment(WebApplicationContext ctx) {
|
||||
Environment defaultEnv = ctx.getEnvironment();
|
||||
assertThat(defaultEnv, notNullValue());
|
||||
assertThat(defaultEnv, instanceOf(DefaultPortletEnvironment.class));
|
||||
}
|
||||
|
||||
private void assertHasEnvironment(ApplicationContext ctx, Environment expectedEnv) {
|
||||
// ensure the custom environment took
|
||||
Environment actualEnv = ctx.getEnvironment();
|
||||
|
|
|
|||
|
|
@ -103,7 +103,6 @@ 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);
|
||||
|
|
|
|||
103
org.springframework.test/src/main/java/org/springframework/mock/env/MockPropertySource.java
vendored
Normal file
103
org.springframework.test/src/main/java/org/springframework/mock/env/MockPropertySource.java
vendored
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright 2002-2011 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;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
|
||||
/**
|
||||
* Simple {@link PropertySource} implementation for use in testing. Accepts
|
||||
* a user-provided {@link Properties} object, or if omitted during construction,
|
||||
* the implementation will initialize its own.
|
||||
*
|
||||
* The {@link #setProperty} and {@link #withProperty} methods are exposed for
|
||||
* convenience, for example:
|
||||
* <pre>
|
||||
* {@code
|
||||
* PropertySource<?> source = new MockPropertySource().withProperty("foo", "bar");
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see MockEnvironment
|
||||
*/
|
||||
public class MockPropertySource extends PropertiesPropertySource {
|
||||
|
||||
/**
|
||||
* {@value} is the default name for {@link MockPropertySource} instances not
|
||||
* otherwise given an explicit name.
|
||||
* @see #MockPropertySource()
|
||||
* @see #MockPropertySource(String)
|
||||
*/
|
||||
public static final String MOCK_PROPERTIES_PROPERTY_SOURCE_NAME = "mockProperties";
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} named {@value #MOCK_PROPERTIES_PROPERTY_SOURCE_NAME}
|
||||
* that will maintain its own internal {@link Properties} instance.
|
||||
*/
|
||||
public MockPropertySource() {
|
||||
this(new Properties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} with the given name that will
|
||||
* maintain its own internal {@link Properties} instance.
|
||||
* @param name the {@linkplain #getName() name} of the property source
|
||||
*/
|
||||
public MockPropertySource(String name) {
|
||||
this(name, new Properties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} named {@value #MOCK_PROPERTIES_PROPERTY_SOURCE_NAME}
|
||||
* and backed by the given {@link Properties} object.
|
||||
* @param properties the properties to use
|
||||
*/
|
||||
public MockPropertySource(Properties properties) {
|
||||
this(MOCK_PROPERTIES_PROPERTY_SOURCE_NAME, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} with with the given name and backed by the given
|
||||
* {@link Properties} object
|
||||
* @param name the {@linkplain #getName() name} of the property source
|
||||
* @param properties the properties to use
|
||||
*/
|
||||
public MockPropertySource(String name, Properties properties) {
|
||||
super(name, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given property on the underlying {@link Properties} object.
|
||||
*/
|
||||
public void setProperty(String key, String value) {
|
||||
this.source.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient synonym for {@link #setProperty} that returns the current instance.
|
||||
* Useful for method chaining and fluent-style use.
|
||||
* @return this {@link MockPropertySource} instance
|
||||
*/
|
||||
public MockPropertySource withProperty(String key, String value) {
|
||||
this.setProperty(key, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -166,7 +166,6 @@ 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);
|
||||
|
|
@ -185,7 +184,6 @@ 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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2011 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.
|
||||
|
|
@ -33,12 +33,13 @@ 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.context.EnvironmentAware;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceEditor;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.portlet.context.DefaultPortletEnvironment;
|
||||
import org.springframework.web.portlet.context.PortletContextResourceLoader;
|
||||
|
||||
/**
|
||||
|
|
@ -64,7 +65,7 @@ import org.springframework.web.portlet.context.PortletContextResourceLoader;
|
|||
* @see #processAction
|
||||
* @see FrameworkPortlet
|
||||
*/
|
||||
public abstract class GenericPortletBean extends GenericPortlet {
|
||||
public abstract class GenericPortletBean extends GenericPortlet implements EnvironmentAware {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
|
@ -75,10 +76,7 @@ public abstract class GenericPortletBean extends GenericPortlet {
|
|||
*/
|
||||
private final Set<String> requiredProperties = new HashSet<String>();
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: think about making this overridable {@link EnvironmentAware}?
|
||||
*/
|
||||
private Environment environment = new DefaultWebEnvironment();
|
||||
private Environment environment = new DefaultPortletEnvironment();
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -167,6 +165,15 @@ public abstract class GenericPortletBean extends GenericPortlet {
|
|||
protected void initPortletBean() throws PortletException {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>Any environment set here overrides the {@link DefaultPortletEnvironment}
|
||||
* provided by default.
|
||||
*/
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* PropertyValues implementation created from PortletConfig init parameters.
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ 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.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
|
|
@ -150,6 +151,14 @@ public abstract class AbstractRefreshablePortletApplicationContext extends Abstr
|
|||
beanFactory, this.servletContext, this.portletContext, this.portletConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new {@link DefaultPortletEnvironment}.
|
||||
*/
|
||||
@Override
|
||||
protected ConfigurableEnvironment createEnvironment() {
|
||||
return new DefaultPortletEnvironment();
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation supports file paths beneath the root of the PortletContext.
|
||||
* @see PortletContextResource
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright 2002-2011 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.portlet.context;
|
||||
|
||||
import javax.portlet.PortletConfig;
|
||||
import javax.portlet.PortletContext;
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.core.env.DefaultEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.env.PropertySource.StubPropertySource;
|
||||
import org.springframework.web.context.support.DefaultWebEnvironment;
|
||||
|
||||
/**
|
||||
* {@link Environment} implementation to be used by {@code Servlet}-based web
|
||||
* applications. All Portlet-related {@code ApplicationContext} classes initialize an instance
|
||||
* by default.
|
||||
*
|
||||
* <p>Contributes {@code ServletContext}-, {@code PortletContext}-, and {@code PortletConfig}-based
|
||||
* {@link PropertySource} instances. See the {@link #DefaultPortletEnvironment()} constructor
|
||||
* for details.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see DefaultEnvironment
|
||||
* @see DefaultWebEnvironment
|
||||
*/
|
||||
public class DefaultPortletEnvironment extends DefaultEnvironment {
|
||||
|
||||
/** Portlet context init parameters property source name: {@value} */
|
||||
public static final String PORTLET_CONTEXT_PROPERTY_SOURCE_NAME = "portletContextInitParams";
|
||||
|
||||
/** Portlet config init parameters property source name: {@value} */
|
||||
public static final String PORTLET_CONFIG_PROPERTY_SOURCE_NAME = "portletConfigInitParams";
|
||||
|
||||
/**
|
||||
* Create a new {@code Environment} populated with the property sources contributed by
|
||||
* superclasses as well as:
|
||||
* <ul>
|
||||
* <li>{@value #PORTLET_CONFIG_PROPERTY_SOURCE_NAME}
|
||||
* <li>{@value #PORTLET_CONTEXT_PROPERTY_SOURCE_NAME}
|
||||
* <li>{@linkplain DefaultWebEnvironment#SERVLET_CONTEXT_PROPERTY_SOURCE_NAME "servletContextInitParams"}
|
||||
* </ul>
|
||||
* <p>Properties present in {@value #PORTLET_CONFIG_PROPERTY_SOURCE_NAME} will
|
||||
* take precedence over those in {@value #PORTLET_CONTEXT_PROPERTY_SOURCE_NAME},
|
||||
* which takes precedence over those in .
|
||||
* Properties in either will take precedence over system properties and environment
|
||||
* variables.
|
||||
* <p>The property sources are added as stubs for now, and will be
|
||||
* {@linkplain PortletApplicationContextUtils#initPortletPropertySources fully initialized}
|
||||
* once the actual {@link PortletConfig}, {@link PortletContext}, and {@link ServletContext}
|
||||
* objects are available.
|
||||
* @see DefaultEnvironment#DefaultEnvironment
|
||||
* @see PortletConfigPropertySource
|
||||
* @see PortletContextPropertySource
|
||||
* @see AbstractRefreshablePortletApplicationContext#initPropertySources
|
||||
* @see PortletApplicationContextUtils#initPortletPropertySources
|
||||
*/
|
||||
public DefaultPortletEnvironment() {
|
||||
this.getPropertySources().addFirst(new StubPropertySource(DefaultWebEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
|
||||
this.getPropertySources().addFirst(new StubPropertySource(PORTLET_CONTEXT_PROPERTY_SOURCE_NAME));
|
||||
this.getPropertySources().addFirst(new StubPropertySource(PORTLET_CONFIG_PROPERTY_SOURCE_NAME));
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ import java.util.Collections;
|
|||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.portlet.PortletConfig;
|
||||
import javax.portlet.PortletContext;
|
||||
import javax.portlet.PortletRequest;
|
||||
|
|
@ -30,6 +31,7 @@ import javax.servlet.ServletContext;
|
|||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
|
|
@ -37,6 +39,7 @@ import org.springframework.web.context.request.RequestContextHolder;
|
|||
import org.springframework.web.context.request.RequestScope;
|
||||
import org.springframework.web.context.request.SessionScope;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
|
||||
/**
|
||||
* Convenience methods for retrieving the root WebApplicationContext for a given
|
||||
|
|
@ -184,6 +187,29 @@ public abstract class PortletApplicationContextUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace {@code Servlet}- and {@code Portlet}-based stub property sources
|
||||
* with actual instances populated with the given context and config objects.
|
||||
* @see org.springframework.core.env.PropertySource.StubPropertySource
|
||||
* @see org.springframework.core.env.ConfigurableEnvironment#getPropertySources()
|
||||
* @see org.springframework.web.context.support.WebApplicationContextUtils#initServletPropertySources(MutablePropertySources, ServletContext)
|
||||
*/
|
||||
public static void initPortletPropertySources(MutablePropertySources propertySources, ServletContext servletContext,
|
||||
PortletContext portletContext, PortletConfig portletConfig) {
|
||||
Assert.notNull(propertySources, "propertySources must not be null");
|
||||
|
||||
WebApplicationContextUtils.initServletPropertySources(propertySources, servletContext);
|
||||
|
||||
if(portletContext != null && propertySources.contains(DefaultPortletEnvironment.PORTLET_CONTEXT_PROPERTY_SOURCE_NAME)) {
|
||||
propertySources.replace(DefaultPortletEnvironment.PORTLET_CONTEXT_PROPERTY_SOURCE_NAME,
|
||||
new PortletContextPropertySource(DefaultPortletEnvironment.PORTLET_CONTEXT_PROPERTY_SOURCE_NAME, portletContext));
|
||||
}
|
||||
if(portletConfig != null && propertySources.contains(DefaultPortletEnvironment.PORTLET_CONFIG_PROPERTY_SOURCE_NAME)) {
|
||||
propertySources.replace(DefaultPortletEnvironment.PORTLET_CONFIG_PROPERTY_SOURCE_NAME,
|
||||
new PortletConfigPropertySource(DefaultPortletEnvironment.PORTLET_CONFIG_PROPERTY_SOURCE_NAME, portletConfig));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current RequestAttributes instance as PortletRequestAttributes.
|
||||
* @see RequestContextHolder#currentRequestAttributes()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2002-2011 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.portlet.context;
|
||||
|
||||
import javax.portlet.PortletConfig;
|
||||
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* {@link PropertySource} that reads init parameters from a {@link PortletConfig} object.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see PortletContextPropertySource
|
||||
*/
|
||||
public class PortletConfigPropertySource extends PropertySource<PortletConfig> {
|
||||
|
||||
public PortletConfigPropertySource(String name, PortletConfig portletConfig) {
|
||||
super(name, portletConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPropertyNames() {
|
||||
return CollectionUtils.toArray(this.source.getInitParameterNames(), EMPTY_NAMES_ARRAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProperty(String name) {
|
||||
return this.source.getInitParameter(name);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2002-2011 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.portlet.context;
|
||||
|
||||
import javax.portlet.PortletContext;
|
||||
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* {@link PropertySource} that reads init parameters from a {@link PortletContext} object.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
* @see PortletConfigPropertySource
|
||||
*/
|
||||
public class PortletContextPropertySource extends PropertySource<PortletContext> {
|
||||
|
||||
public PortletContextPropertySource(String name, PortletContext portletContext) {
|
||||
super(name, portletContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPropertyNames() {
|
||||
return CollectionUtils.toArray(this.source.getInitParameterNames(), EMPTY_NAMES_ARRAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProperty(String name) {
|
||||
return this.source.getInitParameter(name);
|
||||
}
|
||||
}
|
||||
|
|
@ -23,7 +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.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
|
@ -61,10 +61,29 @@ public class StaticPortletApplicationContext extends StaticApplicationContext
|
|||
|
||||
public StaticPortletApplicationContext() {
|
||||
setDisplayName("Root Portlet ApplicationContext");
|
||||
setEnvironment(new DefaultWebEnvironment()); // TODO SPR-7508: create custom portlet env?
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a new {@link DefaultPortletEnvironment}
|
||||
*/
|
||||
@Override
|
||||
protected ConfigurableEnvironment createEnvironment() {
|
||||
return new DefaultPortletEnvironment();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>Replace {@code Portlet}- and {@code Servlet}-related property sources.
|
||||
*/
|
||||
@Override
|
||||
protected void initPropertySources() {
|
||||
super.initPropertySources();
|
||||
PortletApplicationContextUtils.initPortletPropertySources(
|
||||
this.getEnvironment().getPropertySources(), this.servletContext,
|
||||
this.portletContext, this.portletConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParent(ApplicationContext parent) {
|
||||
super.setParent(parent);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2011 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.
|
||||
|
|
@ -35,12 +35,12 @@ 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;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.support.DefaultWebEnvironment;
|
||||
import org.springframework.web.context.support.ServletContextResourceLoader;
|
||||
|
||||
/**
|
||||
|
|
@ -75,7 +75,8 @@ import org.springframework.web.context.support.ServletContextResourceLoader;
|
|||
* @see #doGet
|
||||
* @see #doPost
|
||||
*/
|
||||
public abstract class HttpServletBean extends HttpServlet {
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class HttpServletBean extends HttpServlet implements EnvironmentAware {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
|
@ -86,9 +87,6 @@ public abstract class HttpServletBean extends HttpServlet {
|
|||
*/
|
||||
private final Set<String> requiredProperties = new HashSet<String>();
|
||||
|
||||
/**
|
||||
* TODO SPR-7508: think about making this overridable {@link EnvironmentAware}?
|
||||
*/
|
||||
private Environment environment = new DefaultWebEnvironment();
|
||||
|
||||
|
||||
|
|
@ -182,6 +180,15 @@ public abstract class HttpServletBean extends HttpServlet {
|
|||
protected void initServletBean() throws ServletException {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>Any environment set here overrides the {@link DefaultWebEnvironment}
|
||||
* provided by default.
|
||||
*/
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* PropertyValues implementation created from ServletConfig init parameters.
|
||||
|
|
|
|||
|
|
@ -35,9 +35,9 @@ import org.springframework.web.servlet.support.WebContentGenerator;
|
|||
/**
|
||||
* {@link HttpRequestHandler} that serves static resources optimized for superior browser performance
|
||||
* (according to the guidelines of Page Speed, YSlow, etc.) by allowing for flexible cache settings
|
||||
* ({@link #setCacheSeconds "cacheSeconds" property}, last-modified support).
|
||||
* ({@linkplain #setCacheSeconds "cacheSeconds" property}, last-modified support).
|
||||
*
|
||||
* <p>The {@link #setLocations "locations" property takes a list of Spring {@link Resource} locations
|
||||
* <p>The {@linkplain #setLocations "locations" property} takes a list of Spring {@link Resource} locations
|
||||
* from which static resources are allowed to be served by this handler. For a given request, the
|
||||
* list of locations will be consulted in order for the presence of the requested resource, and the
|
||||
* first found match will be written to the response, with {@code Expires} and {@code Cache-Control}
|
||||
|
|
@ -54,7 +54,7 @@ import org.springframework.web.servlet.support.WebContentGenerator;
|
|||
* using Spring EL. See the reference manual for further examples of this approach.
|
||||
*
|
||||
* <p>Rather than being directly configured as a bean, this handler will typically be configured
|
||||
* through use of the <code><mvc:resources/></code> XML configuration element.
|
||||
* through use of the {@code <mvc:resources/>} XML configuration element.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Jeremy Grelle
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue