Browse Source

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
pull/41/merge
Chris Beams 14 years ago
parent
commit
37d547c506
  1. 30
      spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java
  2. 36
      spring-context/src/test/java/org/springframework/context/annotation/PropertySourceAnnotationTests.java
  3. 3
      spring-context/src/test/java/org/springframework/context/annotation/p1.properties
  4. 3
      spring-context/src/test/java/org/springframework/context/annotation/p2.properties
  5. 73
      spring-core/src/main/java/org/springframework/core/env/AbstractEnvironment.java
  6. 65
      spring-core/src/main/java/org/springframework/core/env/CompositePropertySource.java
  7. 3
      spring-jms/src/main/java/org/springframework/jms/config/JcaListenerContainerParser.java
  8. 13
      spring-jms/src/main/java/org/springframework/jms/config/JmsListenerContainerParser.java
  9. 8
      spring-jms/src/main/resources/org/springframework/jms/config/spring-jms-3.1.xsd
  10. 5
      spring-jms/src/test/java/org/springframework/jms/config/jmsNamespaceHandlerTests.xml
  11. 15
      src/dist/changelog.txt

30
spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java

@ -38,6 +38,7 @@ import org.springframework.beans.factory.support.BeanDefinitionReader; @@ -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 { @@ -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);
}
}
}

36
spring-context/src/test/java/org/springframework/context/annotation/PropertySourceAnnotationTests.java

@ -118,6 +118,25 @@ public class PropertySourceAnnotationTests { @@ -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 { @@ -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 {
}
}

3
spring-context/src/test/java/org/springframework/context/annotation/p1.properties

@ -1 +1,2 @@ @@ -1 +1,2 @@
testbean.name=p1TestBean
testbean.name=p1TestBean
from.p1=p1Value

3
spring-context/src/test/java/org/springframework/context/annotation/p2.properties

@ -1 +1,2 @@ @@ -1 +1,2 @@
testbean.name=p2TestBean
testbean.name=p2TestBean
from.p2=p2Value

73
spring-core/src/main/java/org/springframework/core/env/AbstractEnvironment.java vendored

@ -1,5 +1,5 @@ @@ -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 @@ @@ -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; @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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

@ -0,0 +1,65 @@ @@ -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);
}
}

3
spring-jms/src/main/java/org/springframework/jms/config/JcaListenerContainerParser.java

@ -1,5 +1,5 @@ @@ -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 { @@ -108,6 +108,7 @@ class JcaListenerContainerParser extends AbstractListenerContainerParser {
return containerDef;
}
@Override
protected boolean indicatesPubSub(BeanDefinition containerDef) {
BeanDefinition configDef =
(BeanDefinition) containerDef.getPropertyValues().getPropertyValue("activationSpecConfig").getValue();

13
spring-jms/src/main/java/org/springframework/jms/config/JmsListenerContainerParser.java

@ -1,5 +1,5 @@ @@ -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 { @@ -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 { @@ -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 { @@ -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");
}

8
spring-jms/src/main/resources/org/springframework/jms/config/spring-jms-3.1.xsd

@ -233,6 +233,14 @@ @@ -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[

5
spring-jms/src/test/java/org/springframework/jms/config/jmsNamespaceHandlerTests.xml

@ -3,11 +3,12 @@ @@ -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

@ -3,10 +3,10 @@ SPRING FRAMEWORK CHANGELOG @@ -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) @@ -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
* improved @SessionAttributes handling to provide better support for clustered sessions
* added property to RedirectView to disable expanding URI variables in redirect URL
* 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
* 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
* improved @SessionAttributes handling to provide better support for clustered sessions
* added property to RedirectView to disable expanding URI variables in redirect URL
Changes in version 3.1 GA (2011-12-12)

Loading…
Cancel
Save