Sync with 3.1.x
* 3.1.x:
Warn re Environment construction and instance vars
Disallow empty @PropertySource(value = {})
Fix @PropertySource bug with multiple values
final preparations for 3.1.1 release
added "receive-timeout" attribute to "jms:listener-container" element
This commit is contained in:
@@ -38,6 +38,7 @@ import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
@@ -179,13 +180,30 @@ class ConfigurationClassParser {
|
||||
if (propertySource != null) {
|
||||
String name = propertySource.getString("name");
|
||||
String[] locations = propertySource.getStringArray("value");
|
||||
int nLocations = locations.length;
|
||||
if (nLocations == 0) {
|
||||
throw new IllegalArgumentException("At least one @PropertySource(value) location is required");
|
||||
}
|
||||
for (int i = 0; i < nLocations; i++) {
|
||||
locations[0] = this.environment.resolveRequiredPlaceholders(locations[0]);
|
||||
}
|
||||
ClassLoader classLoader = this.resourceLoader.getClassLoader();
|
||||
for (String location : locations) {
|
||||
location = this.environment.resolveRequiredPlaceholders(location);
|
||||
ResourcePropertySource ps = StringUtils.hasText(name) ?
|
||||
new ResourcePropertySource(name, location, classLoader) :
|
||||
new ResourcePropertySource(location, classLoader);
|
||||
this.propertySources.push(ps);
|
||||
if (!StringUtils.hasText(name)) {
|
||||
for (String location : locations) {
|
||||
this.propertySources.push(new ResourcePropertySource(location, classLoader));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (nLocations == 1) {
|
||||
this.propertySources.push(new ResourcePropertySource(name, locations[0], classLoader));
|
||||
}
|
||||
else {
|
||||
CompositePropertySource ps = new CompositePropertySource(name);
|
||||
for (String location : locations) {
|
||||
ps.addPropertySource(new ResourcePropertySource(location, classLoader));
|
||||
}
|
||||
this.propertySources.push(ps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -118,6 +118,25 @@ public class PropertySourceAnnotationTests {
|
||||
System.clearProperty("path.to.properties");
|
||||
}
|
||||
|
||||
/**
|
||||
* Corner bug reported in SPR-9127.
|
||||
*/
|
||||
@Test
|
||||
public void withNameAndMultipleResourceLocations() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ConfigWithNameAndMultipleResourceLocations.class);
|
||||
ctx.refresh();
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p1"), is(true));
|
||||
assertThat(ctx.getEnvironment().containsProperty("from.p2"), is(true));
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void withEmptyResourceLocations() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(ConfigWithEmptyResourceLocations.class);
|
||||
ctx.refresh();
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@PropertySource(value="classpath:${unresolvable}/p1.properties")
|
||||
@@ -178,4 +197,21 @@ public class PropertySourceAnnotationTests {
|
||||
@PropertySource("classpath:org/springframework/context/annotation/p2.properties")
|
||||
static class P2Config {
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@PropertySource(
|
||||
name = "psName",
|
||||
value = {
|
||||
"classpath:org/springframework/context/annotation/p1.properties",
|
||||
"classpath:org/springframework/context/annotation/p2.properties"
|
||||
})
|
||||
static class ConfigWithNameAndMultipleResourceLocations {
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@PropertySource(value = {})
|
||||
static class ConfigWithEmptyResourceLocations {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
testbean.name=p1TestBean
|
||||
testbean.name=p1TestBean
|
||||
from.p1=p1Value
|
||||
@@ -1 +1,2 @@
|
||||
testbean.name=p2TestBean
|
||||
testbean.name=p2TestBean
|
||||
from.p2=p2Value
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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,11 +16,8 @@
|
||||
|
||||
package org.springframework.core.env;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.springframework.util.StringUtils.commaDelimitedListToStringArray;
|
||||
import static org.springframework.util.StringUtils.trimAllWhitespace;
|
||||
|
||||
import java.security.AccessControlException;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
@@ -28,10 +25,14 @@ import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.convert.support.ConfigurableConversionService;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static java.lang.String.*;
|
||||
import static org.springframework.util.StringUtils.*;
|
||||
|
||||
/**
|
||||
* Abstract base class for {@link Environment} implementations. Supports the notion of
|
||||
* reserved default profile names and enables specifying active and default profiles
|
||||
@@ -89,19 +90,39 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment {
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private Set<String> activeProfiles = new LinkedHashSet<String>();
|
||||
private Set<String> defaultProfiles = new LinkedHashSet<String>(this.getReservedDefaultProfiles());
|
||||
|
||||
private final MutablePropertySources propertySources = new MutablePropertySources(logger);
|
||||
private final ConfigurablePropertyResolver propertyResolver = new PropertySourcesPropertyResolver(propertySources);
|
||||
private Set<String> defaultProfiles =
|
||||
new LinkedHashSet<String>(this.getReservedDefaultProfiles());
|
||||
|
||||
private final MutablePropertySources propertySources =
|
||||
new MutablePropertySources(this.logger);
|
||||
|
||||
private final ConfigurablePropertyResolver propertyResolver =
|
||||
new PropertySourcesPropertyResolver(this.propertySources);
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code Environment} instance, calling back to
|
||||
* {@link #customizePropertySources(MutablePropertySources)} during construction to
|
||||
* allow subclasses to contribute or manipulate {@link PropertySource} instances as
|
||||
* appropriate.
|
||||
* @see #customizePropertySources(MutablePropertySources)
|
||||
*/
|
||||
public AbstractEnvironment() {
|
||||
String name = this.getClass().getSimpleName();
|
||||
logger.debug(String.format("Initializing new %s", name));
|
||||
this.customizePropertySources(propertySources);
|
||||
logger.debug(String.format("Initialized %s with PropertySources %s", name, propertySources));
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug(format("Initializing new %s", name));
|
||||
}
|
||||
|
||||
this.customizePropertySources(this.propertySources);
|
||||
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug(format(
|
||||
"Initialized %s with PropertySources %s", name, this.propertySources));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Customize the set of {@link PropertySource} objects to be searched by this
|
||||
* {@code Environment} during calls to {@link #getProperty(String)} and related
|
||||
@@ -163,6 +184,17 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment {
|
||||
* env.getPropertySources().addLast(new PropertySourceX(...));
|
||||
* </pre>
|
||||
*
|
||||
* <h2>A warning about instance variable access</h2>
|
||||
* Instance variables declared in subclasses and having default initial values should
|
||||
* <em>not</em> be accessed from within this method. Due to Java object creation
|
||||
* lifecycle constraints, any initial value will not yet be assigned when this
|
||||
* callback is invoked by the {@link #AbstractEnvironment()} constructor, which may
|
||||
* lead to a {@code NullPointerException} or other problems. If you need to access
|
||||
* default values of instance variables, leave this method as a no-op and perform
|
||||
* property source manipulation and instance variable access directly within the
|
||||
* subclass constructor. Note that <em>assigning</em> values to instance variables is
|
||||
* not problematic; it is only attempting to read default values that must be avoided.
|
||||
*
|
||||
* @see MutablePropertySources
|
||||
* @see PropertySourcesPropertyResolver
|
||||
* @see org.springframework.context.ApplicationContextInitializer
|
||||
@@ -217,7 +249,9 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment {
|
||||
}
|
||||
|
||||
public void addActiveProfile(String profile) {
|
||||
logger.debug(String.format("Activating profile '%s'", profile));
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug(format("Activating profile '%s'", profile));
|
||||
}
|
||||
this.validateProfile(profile);
|
||||
this.activeProfiles.add(profile);
|
||||
}
|
||||
@@ -312,8 +346,10 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment {
|
||||
}
|
||||
catch (AccessControlException ex) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(format("Caught AccessControlException when accessing system environment variable " +
|
||||
"[%s]; its value will be returned [null]. Reason: %s", variableName, ex.getMessage()));
|
||||
logger.info(format("Caught AccessControlException when " +
|
||||
"accessing system environment variable [%s]; its " +
|
||||
"value will be returned [null]. Reason: %s",
|
||||
variableName, ex.getMessage()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -338,8 +374,10 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment {
|
||||
}
|
||||
catch (AccessControlException ex) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(format("Caught AccessControlException when accessing system property " +
|
||||
"[%s]; its value will be returned [null]. Reason: %s", propertyName, ex.getMessage()));
|
||||
logger.info(format("Caught AccessControlException when " +
|
||||
"accessing system property [%s]; its value will be " +
|
||||
"returned [null]. Reason: %s",
|
||||
propertyName, ex.getMessage()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -428,7 +466,8 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment {
|
||||
@Override
|
||||
public String toString() {
|
||||
return format("%s {activeProfiles=%s, defaultProfiles=%s, propertySources=%s}",
|
||||
getClass().getSimpleName(), this.activeProfiles, this.defaultProfiles, this.propertySources);
|
||||
getClass().getSimpleName(), this.activeProfiles, this.defaultProfiles,
|
||||
this.propertySources);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
65
spring-core/src/main/java/org/springframework/core/env/CompositePropertySource.java
vendored
Normal file
65
spring-core/src/main/java/org/springframework/core/env/CompositePropertySource.java
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Composite {@link PropertySource} implementation that iterates over a set of
|
||||
* {@link PropertySource} instances. Necessary in cases where multiple property sources
|
||||
* share the same name, e.g. when multiple values are supplied to {@code @PropertySource}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public class CompositePropertySource extends PropertySource<Object> {
|
||||
|
||||
private Set<PropertySource<?>> propertySources = new LinkedHashSet<PropertySource<?>>();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code CompositePropertySource}.
|
||||
*
|
||||
* @param name the name of the property source
|
||||
*/
|
||||
public CompositePropertySource(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object getProperty(String name) {
|
||||
for (PropertySource<?> propertySource : this.propertySources) {
|
||||
Object candidate = propertySource.getProperty(name);
|
||||
if (candidate != null) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addPropertySource(PropertySource<?> propertySource) {
|
||||
this.propertySources.add(propertySource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s [name='%s', propertySources=%s]",
|
||||
this.getClass().getSimpleName(), this.name, this.propertySources);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -108,6 +108,7 @@ class JcaListenerContainerParser extends AbstractListenerContainerParser {
|
||||
return containerDef;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean indicatesPubSub(BeanDefinition containerDef) {
|
||||
BeanDefinition configDef =
|
||||
(BeanDefinition) containerDef.getPropertyValues().getPropertyValue("activationSpecConfig").getValue();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -47,6 +47,8 @@ class JmsListenerContainerParser extends AbstractListenerContainerParser {
|
||||
|
||||
private static final String CACHE_ATTRIBUTE = "cache";
|
||||
|
||||
private static final String RECEIVE_TIMEOUT_ATTRIBUTE = "receive-timeout";
|
||||
|
||||
|
||||
protected BeanDefinition parseContainer(Element listenerEle, Element containerEle, ParserContext parserContext) {
|
||||
RootBeanDefinition containerDef = new RootBeanDefinition();
|
||||
@@ -156,6 +158,13 @@ class JmsListenerContainerParser extends AbstractListenerContainerParser {
|
||||
}
|
||||
}
|
||||
|
||||
String receiveTimeout = containerEle.getAttribute(RECEIVE_TIMEOUT_ATTRIBUTE);
|
||||
if (StringUtils.hasText(receiveTimeout)) {
|
||||
if (containerType.startsWith("default")) {
|
||||
containerDef.getPropertyValues().add("receiveTimeout", new Integer(receiveTimeout));
|
||||
}
|
||||
}
|
||||
|
||||
String phase = containerEle.getAttribute(PHASE_ATTRIBUTE);
|
||||
if (StringUtils.hasText(phase)) {
|
||||
containerDef.getPropertyValues().add("phase", phase);
|
||||
@@ -164,10 +173,12 @@ class JmsListenerContainerParser extends AbstractListenerContainerParser {
|
||||
return containerDef;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean indicatesPubSub(BeanDefinition containerDef) {
|
||||
return indicatesPubSubConfig(containerDef);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean indicatesJms102(BeanDefinition containerDef) {
|
||||
return containerDef.getBeanClassName().endsWith("102");
|
||||
}
|
||||
|
||||
@@ -233,6 +233,14 @@
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="receive-timeout" type="xsd:int">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The timeout to use for receive calls (in milliseconds).
|
||||
The default is 1000 ms (1 sec); -1 indicates no timeout at all.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="phase" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:jms="http://www.springframework.org/schema/jms"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms.xsd">
|
||||
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.1.xsd">
|
||||
|
||||
<jms:listener-container connection-factory="testConnectionFactory" task-executor="testTaskExecutor"
|
||||
destination-resolver="testDestinationResolver" message-converter="testMessageConverter"
|
||||
transaction-manager="testTransactionManager" error-handler="testErrorHandler" concurrency="1-2" phase="99">
|
||||
transaction-manager="testTransactionManager" error-handler="testErrorHandler"
|
||||
concurrency="1-2" prefetch="50" receive-timeout="100" phase="99">
|
||||
<jms:listener id="listener1" destination="testDestination" ref="testBean1" method="setName"/>
|
||||
<jms:listener id="listener2" destination="testDestination" ref="testBean2" method="setName" response-destination="responseDestination"/>
|
||||
</jms:listener-container>
|
||||
|
||||
15
src/dist/changelog.txt
vendored
15
src/dist/changelog.txt
vendored
@@ -3,10 +3,10 @@ SPRING FRAMEWORK CHANGELOG
|
||||
http://www.springsource.org
|
||||
|
||||
|
||||
Changes in version 3.1.1 (2012-02-15)
|
||||
Changes in version 3.1.1 (2012-02-16)
|
||||
-------------------------------------
|
||||
|
||||
* official support for Hibernate 4.0 GA as well as Hibernate 4.1
|
||||
* official support for Hibernate 4.0.0/4.0.1 as well as Hibernate 4.1
|
||||
* JBossNativeJdbcExtractor is compatible with JBoss AS 7 as well
|
||||
* restored JBossLoadTimeWeaver compatibility with JBoss AS 5.1
|
||||
* Provider injection works with generically typed collections of beans as well
|
||||
@@ -34,20 +34,21 @@ Changes in version 3.1.1 (2012-02-15)
|
||||
* fixed QuartzJobBean and MethodInvokingJobDetailFactoryBean for compatibility with Quartz 2.0/2.1
|
||||
* JMS CachingConnectionFactory never caches consumers for temporary queues and topics
|
||||
* JMS SimpleMessageListenerContainer silently falls back to lazy registration of consumers
|
||||
* Servlet/PortletContextResource's "isReadable()" implementation returns false for directories
|
||||
* added "receive-timeout" attribute to jms:listener-container element in JMS namespace
|
||||
* ServletServerHttpRequest/Response fall back on the Content-Type and encoding of the request
|
||||
* preserve quotes in MediaType parameters
|
||||
* added "normalize()" method to UriComponents
|
||||
* remove empty path segments from input to UriComponentsBuilder
|
||||
* added "fromRequestUri(request)" and "fromCurrentRequestUri()" methods to ServletUriComponentsBuilder
|
||||
* Servlet/PortletContextResource's "isReadable()" implementation returns false for directories
|
||||
* allow adding flash attributes in methods with a ModelAndView return value
|
||||
* make flash attributes available in the model of Parameterizable/UrlFilenameViewController
|
||||
* revised the FlashMapManager contract and implementation to address a flaw in its design
|
||||
* removed check for HTTP POST when resolving multipart request controller method arguments
|
||||
* fixed request mapping bug involving direct vs pattern path matches with HTTP methods
|
||||
* updated @RequestMapping and reference docs wrt differences between @MVC 3.1 and @MVC 2.5-3.0
|
||||
* improved @SessionAttributes handling to provide better support for clustered sessions
|
||||
* added property to RedirectView to disable expanding URI variables in redirect URL
|
||||
* fixed request mapping bug involving direct vs pattern path matches with HTTP methods
|
||||
* removed check for HTTP "POST" when resolving multipart request controller method arguments
|
||||
* updated @RequestMapping and reference docs wrt differences between @MVC 3.1 and @MVC 2.5-3.0
|
||||
* ServletServerHttpRequest/Response fall back on the Content-Type and encoding of the request
|
||||
|
||||
|
||||
Changes in version 3.1 GA (2011-12-12)
|
||||
|
||||
Reference in New Issue
Block a user