From b343ca1e864f5f7638f8b208b7cd7c935d73ecca Mon Sep 17 00:00:00 2001 From: Tomasz Nurkiewicz Date: Fri, 25 May 2012 00:09:12 +0200 Subject: [PATCH] Passing lookup-method args to bean constructor should allow specifying any number of parameters. These parameters should be passed directly to the constructor of the newly created bean. Previously had to be parameterless. Now if you provide any parameters to that method, they are passes directly (1 to 1) to the bean constructor, just like if they were declared using . The idea was originally suggested here: http://nurkiewicz.blogspot.com/2010/08/creating-prototype-spring-beans-on.html This change is based entirely on a patch provided by Karl Pietrzak. Issue: SPR-7431 --- .../beans/factory/BeanFactory.java | 2 +- ...CglibSubclassingInstantiationStrategy.java | 2 +- .../beans/factory/support/LookupOverride.java | 2 +- .../factory/support/LookupMethodTests.java | 89 +++++++++++++++++++ .../test/java/test/beans/AbstractBean.java | 19 ++++ .../factory/xml/lookupMethodBeanTests.xml | 15 ++++ 6 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 spring-beans/src/test/java/org/springframework/beans/factory/support/LookupMethodTests.java create mode 100644 spring-beans/src/test/java/test/beans/AbstractBean.java create mode 100644 spring-beans/src/test/resources/org/springframework/beans/factory/xml/lookupMethodBeanTests.xml diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java index 58bba15a4f0a..e14203a50d14 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java @@ -170,7 +170,7 @@ public interface BeanFactory { * overriding the specified default arguments (if any) in the bean definition. * @param name the name of the bean to retrieve * @param args arguments to use if creating a prototype using explicit arguments to a - * static factory method. It is invalid to use a non-null args value in any other case. + * static factory method. * @return an instance of the bean * @throws NoSuchBeanDefinitionException if there's no such bean definition * @throws BeanDefinitionStoreException if arguments have been given but diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java index c174976a39b7..c6372de35dbd 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java @@ -157,7 +157,7 @@ private class LookupOverrideMethodInterceptor extends CglibIdentitySupport imple public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable { // Cast is safe, as CallbackFilter filters are used selectively. LookupOverride lo = (LookupOverride) beanDefinition.getMethodOverrides().getOverride(method); - return owner.getBean(lo.getBeanName()); + return owner.getBean(lo.getBeanName(), args); } } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/LookupOverride.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/LookupOverride.java index 2a34093cf6ae..e165a5479ca0 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/LookupOverride.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/LookupOverride.java @@ -61,7 +61,7 @@ public String getBeanName() { */ @Override public boolean matches(Method method) { - return (method.getName().equals(getMethodName()) && method.getParameterTypes().length == 0); + return (method.getName().equals(getMethodName())); } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/LookupMethodTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/LookupMethodTests.java new file mode 100644 index 000000000000..bbfde74d9754 --- /dev/null +++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/LookupMethodTests.java @@ -0,0 +1,89 @@ +/* + * Copyright 2002-2009 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.beans.factory.support; + +import junit.framework.TestCase; + +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.ClassPathResource; + +import test.beans.AbstractBean; +import test.beans.TestBean; + +/** + * Tests the use of lookup-method + * @author Karl Pietrzak + */ +public class LookupMethodTests extends TestCase { + + + private DefaultListableBeanFactory beanFactory; + + protected void setUp() throws Exception { + final ClassPathResource resource = new ClassPathResource("/org/springframework/beans/factory/xml/lookupMethodBeanTests.xml", getClass()); + this.beanFactory = new DefaultListableBeanFactory(); + final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.beanFactory); + reader.loadBeanDefinitions(resource); + } + + /** + * lookup method's bean has no constructor arguments + */ + public void testWithoutConstructorArg() { + AbstractBean bean = (AbstractBean)this.beanFactory.getBean("abstractBean"); + assertNotNull(bean); + final Object expected = bean.get(); + assertEquals(TestBean.class, expected.getClass()); + } + + /** + * Creates a new instance of {@link TestBean} using the constructor which takes a single String + */ + public void testWithOneConstructorArg() { + AbstractBean bean = (AbstractBean)this.beanFactory.getBean("abstractBean"); + assertNotNull(bean); + final TestBean expected = bean.getOneArgument("haha"); + assertEquals(TestBean.class, expected.getClass()); + assertEquals("haha", expected.getName()); + } + + /** + * Creates a new instance of {@link TestBean} using the constructor which takes a String and an int + */ + public void testWithTwoConstructorArg() { + AbstractBean bean = (AbstractBean)this.beanFactory.getBean("abstractBean"); + assertNotNull(bean); + final TestBean expected = bean.getTwoArguments("haha", 72); + assertEquals(TestBean.class, expected.getClass()); + assertEquals("haha", expected.getName()); + assertEquals(72, expected.getAge()); + } + + /** + * {@link TestBean} doesn't have a constructor that takes a String and two int's + */ + public void testWithThreeArgsShouldFail() { + AbstractBean bean = (AbstractBean)this.beanFactory.getBean("abstractBean"); + assertNotNull(bean); + try { + bean.getThreeArguments("name", 1, 2); + fail("TestBean does not have a three arg constructor so this should not have worked"); + } catch (AbstractMethodError e) { + + } + } +} diff --git a/spring-beans/src/test/java/test/beans/AbstractBean.java b/spring-beans/src/test/java/test/beans/AbstractBean.java new file mode 100644 index 000000000000..c6dfea1e0286 --- /dev/null +++ b/spring-beans/src/test/java/test/beans/AbstractBean.java @@ -0,0 +1,19 @@ +package test.beans; + +import org.springframework.beans.factory.support.LookupMethodTests; + +/** + * A simple bean used for testing lookup-method constructors. + * + * The actual test class which uses this bean is {@link LookupMethodTests} + * @author kpietrzak + * + */ +public abstract class AbstractBean { + + public abstract TestBean get(); + public abstract TestBean getOneArgument(String name); + public abstract TestBean getTwoArguments(String name, int age); + public abstract TestBean getThreeArguments(String name, int age, int anotherArg); + +} diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/xml/lookupMethodBeanTests.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/lookupMethodBeanTests.xml new file mode 100644 index 000000000000..9d57bac011f2 --- /dev/null +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/xml/lookupMethodBeanTests.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + +