Support by-type lookup/injection of primitive types

Allowing beans of primitive type to be looked up via getBean(Class), or
to be injected using @Autowired or @Injected or @Resource. Prior to
these changes, an attempt to lookup or inject a bean of, for example,
type boolean would fail because all spring beans are Objects, regardless
of initial type due to the way that ObjectFactory works.

Now these attempts to lookup or inject primitive types work, thanks to
simple changes in AbstractBeanFactory using ClassUtils#isAssignable
methods instead of the built-in Class#isAssignableFrom. The former takes
into account primitives and their object wrapper types, whereas the
latter does not.

The need to declare, look up or inject primitive-typed beans is probably
low -- how often does one need a bean of type boolean or int after all?.
Prior to the introduction of @Bean methods in Spring 3.0, it was not
possible in practice to register primitive beans, so this issue never
came up. Now that one can declare primitive-typed beans, it does make
sense that we properly support by-type lookup and injection without
forcing the user to work with object wrappers.

Issue: SPR-8874
master
Chris Beams 13 years ago
parent ca3d774f5c
commit 0113ea91a3
  1. 6
      org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java
  2. 107
      org.springframework.context/src/test/java/org/springframework/context/annotation/PrimitiveBeanLookupAndAutowiringTests.java

@ -469,15 +469,15 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
if (beanInstance instanceof FactoryBean) {
if (!BeanFactoryUtils.isFactoryDereference(name)) {
Class type = getTypeForFactoryBean((FactoryBean) beanInstance);
return (type != null && typeToMatch.isAssignableFrom(type));
return (type != null && ClassUtils.isAssignable(typeToMatch, type));
}
else {
return typeToMatch.isAssignableFrom(beanInstance.getClass()) ;
return ClassUtils.isAssignableValue(typeToMatch, beanInstance);
}
}
else {
return !BeanFactoryUtils.isFactoryDereference(name) &&
typeToMatch.isAssignableFrom(beanInstance.getClass());
ClassUtils.isAssignableValue(typeToMatch, beanInstance);
}
}
else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {

@ -0,0 +1,107 @@
/*
* 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.equalTo;
import static org.junit.Assert.assertThat;
import javax.annotation.Resource;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Tests changes introduced for SPR-8874, allowing beans of primitive types to be looked
* up via getBean(Class), or to be injected using @Autowired or @Injected or @Resource.
* Prior to these changes, an attempt to lookup or inject a bean of type boolean would
* fail because all spring beans are Objects, regardless of initial type due to the way
* that ObjectFactory works.
*
* Now these attempts to lookup or inject primitive types work, thanks to simple changes
* in AbstractBeanFactory using ClassUtils#isAssignable methods instead of the built-in
* Class#isAssignableFrom. The former takes into account primitives and their object
* wrapper types, whereas the latter does not.
*
* @author Chris Beams
* @since 3.1
*/
public class PrimitiveBeanLookupAndAutowiringTests {
@Test
public void primitiveLookupByName() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
boolean b = ctx.getBean("b", boolean.class);
assertThat(b, equalTo(true));
int i = ctx.getBean("i", int.class);
assertThat(i, equalTo(42));
}
@Test
public void primitiveLookupByType() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
boolean b = ctx.getBean(boolean.class);
assertThat(b, equalTo(true));
int i = ctx.getBean(int.class);
assertThat(i, equalTo(42));
}
@Test
public void primitiveAutowiredInjection() {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(Config.class, AutowiredComponent.class);
assertThat(ctx.getBean(AutowiredComponent.class).b, equalTo(true));
assertThat(ctx.getBean(AutowiredComponent.class).i, equalTo(42));
}
@Test
public void primitiveResourceInjection() {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(Config.class, ResourceComponent.class);
assertThat(ctx.getBean(ResourceComponent.class).b, equalTo(true));
assertThat(ctx.getBean(ResourceComponent.class).i, equalTo(42));
}
@Configuration
static class Config {
@Bean
public boolean b() {
return true;
}
@Bean
public int i() {
return 42;
}
}
static class AutowiredComponent {
@Autowired boolean b;
@Autowired int i;
}
static class ResourceComponent {
@Resource boolean b;
@Autowired int i;
}
}
Loading…
Cancel
Save