Browse Source
Previously errors were being raised when trying to inject @Value annotated paramaters such as: @Feature public FeatureSpec feature(@Value("#{environment['foo']}") String foo) { return new FeatureSpec(foo); } This is not so much because dependency resolution of @Value-annotated types was failing, but rather because the 'early bean reference' proxying mechanism was throwing an exception if any final type was detected as a parameter. This is of course because final types are non-subclassable by CGLIB. On review, however, it's obvious that certain final types must be allowed for injection. @Value injection is an obvious one, but the rarer case of a Spring bean of type String or int is another. The explicit guard against final types as parameters to @Feature methods has been removed. Final types are still checked for, however, and if found, no proxing is attempted. The dependency is immediately resolved against the current BeanFactory and injected into the @Feature method. This means that @Value injection, @Qualifier injection, etc all work as expected, but does mean that premature bean instantiation may occur if a user unwittingly injects non-String, non-primitive final bean types as @Feature method parameters. Issue: SPR-7974pull/7/head
4 changed files with 164 additions and 35 deletions
@ -0,0 +1,135 @@
@@ -0,0 +1,135 @@
|
||||
/* |
||||
* 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.annotation; |
||||
|
||||
import static org.hamcrest.CoreMatchers.is; |
||||
import static org.junit.Assert.assertThat; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.beans.factory.annotation.Qualifier; |
||||
import org.springframework.beans.factory.annotation.Value; |
||||
import org.springframework.context.annotation.configuration.StubSpecification; |
||||
|
||||
/** |
||||
* Tests ensuring that @Feature methods can accept @Value-annoted |
||||
* parameters, particularly String types. SPR-7974 revealed this |
||||
* was failing due to attempting to proxy objects of type String, |
||||
* which cannot be done. |
||||
* |
||||
* @author Chris Beams |
||||
*/ |
||||
public class FeatureMethodValueInjectionTests { |
||||
|
||||
@Test |
||||
public void control() { |
||||
System.setProperty("foo", "bar"); |
||||
System.setProperty("num", "2"); |
||||
Config config = new AnnotationConfigApplicationContext(Config.class).getBean(Config.class); |
||||
System.clearProperty("foo"); |
||||
System.clearProperty("num"); |
||||
assertThat(config.foo, is("bar")); |
||||
assertThat(config.num, is(2)); |
||||
} |
||||
|
||||
@Test |
||||
public void spelValueInjection() { |
||||
System.setProperty("foo", "bar"); |
||||
new AnnotationConfigApplicationContext(SpelValueInjectionFeatureConfig.class); |
||||
System.clearProperty("foo"); |
||||
} |
||||
|
||||
@Test |
||||
public void spelIntValueInjection() { |
||||
System.setProperty("num", "5"); |
||||
new AnnotationConfigApplicationContext(SpelIntValueInjectionFeatureConfig.class); |
||||
System.clearProperty("num"); |
||||
} |
||||
|
||||
@Test |
||||
public void stringBeanInjection() { |
||||
new AnnotationConfigApplicationContext(StringBeanConfig.class, StringBeanInjectionByTypeFeatureConfig.class); |
||||
} |
||||
|
||||
@Test |
||||
public void qualifiedStringBeanInjection() { |
||||
new AnnotationConfigApplicationContext(StringBeanSubConfig.class, StringBeanInjectionByQualifierFeatureConfig.class); |
||||
} |
||||
|
||||
|
||||
@FeatureConfiguration |
||||
static class SpelValueInjectionFeatureConfig { |
||||
@Feature |
||||
public StubSpecification feature(@Value("#{environment['foo']}") String foo) { |
||||
return new StubSpecification(); |
||||
} |
||||
} |
||||
|
||||
|
||||
@FeatureConfiguration |
||||
static class SpelIntValueInjectionFeatureConfig { |
||||
@Feature |
||||
public StubSpecification feature(@Value("#{environment['num']}") int num) { |
||||
assertThat(num, is(5)); |
||||
return new StubSpecification(); |
||||
} |
||||
} |
||||
|
||||
|
||||
@Configuration |
||||
static class StringBeanConfig { |
||||
@Bean |
||||
public String stringBean() { |
||||
return "sb"; |
||||
} |
||||
} |
||||
|
||||
|
||||
@Configuration |
||||
static class StringBeanSubConfig extends StringBeanConfig { |
||||
@Bean |
||||
public String stringBean2() { |
||||
return "sb2"; |
||||
} |
||||
} |
||||
|
||||
|
||||
@FeatureConfiguration |
||||
static class StringBeanInjectionByTypeFeatureConfig { |
||||
@Feature |
||||
public StubSpecification feature(String string) { |
||||
assertThat(string, is("sb")); |
||||
return new StubSpecification(); |
||||
} |
||||
} |
||||
|
||||
|
||||
@FeatureConfiguration |
||||
static class StringBeanInjectionByQualifierFeatureConfig { |
||||
@Feature |
||||
public StubSpecification feature(@Qualifier("stringBean2") String string) { |
||||
assertThat(string, is("sb2")); |
||||
return new StubSpecification(); |
||||
} |
||||
} |
||||
|
||||
|
||||
@Configuration |
||||
static class Config { |
||||
@Value("#{environment['foo']}") String foo; |
||||
@Value("#{environment['num']}") int num; |
||||
} |
||||
} |
Loading…
Reference in new issue