diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBean.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBean.java index 2a682a67559..ef479927dc7 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBean.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBean.java @@ -16,7 +16,10 @@ package org.springframework.beans.factory.config; +import java.io.Serializable; + import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ObjectFactory; import org.springframework.util.Assert; @@ -41,7 +44,7 @@ import org.springframework.util.Assert; *
<beans>
  *
  *   <!-- Prototype bean since we have state -->
- *   <bean id="myService" class="a.b.c.MyService" singleton="false"/>
+ *   <bean id="myService" class="a.b.c.MyService" scope="prototype"/>
  *
  *   <bean id="myServiceFactory"
  *       class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
@@ -63,9 +66,9 @@ import org.springframework.util.Assert;
  *
  * public class MyClientBean {
  *
- *   private ObjectFactory myServiceFactory;
+ *   private ObjectFactory<MyService> myServiceFactory;
  *
- *   public void setMyServiceFactory(ObjectFactory myServiceFactory) {
+ *   public void setMyServiceFactory(ObjectFactory<MyService> myServiceFactory) {
  *     this.myServiceFactory = myServiceFactory;
  *   }
  *
@@ -98,13 +101,10 @@ public class ObjectFactoryCreatingFactoryBean extends AbstractFactoryBeanThe target does not have to be a prototype bean, but realisticially
-	 * always will be (because if the target bean were a singleton, then said
-	 * singleton bean could simply be injected straight into the dependent object,
-	 * thus obviating the need for the extra level of indirection afforded by
-	 * the approach encapsulated by this class). Please note that no exception
-	 * will be thrown if the supplied targetBeanName does not
-	 * reference a prototype bean.
+	 * 

The target does not have to be a non-singleton bean, but realisticially + * always will be (because if the target bean were a singleton, then said singleton + * bean could simply be injected straight into the dependent object, thus obviating + * the need for the extra level of indirection afforded by this factory approach). */ public void setTargetBeanName(String targetBeanName) { this.targetBeanName = targetBeanName; @@ -124,21 +124,27 @@ public class ObjectFactoryCreatingFactoryBean extends AbstractFactoryBeangetObject() method. - * @param targetBeanName the name of the target bean - * @return the target bean instance + * Independent inner class - for serialization purposes. */ - protected Object getTargetBean(String targetBeanName) { - return getBeanFactory().getBean(targetBeanName); + private static class TargetBeanObjectFactory implements ObjectFactory, Serializable { + + private final BeanFactory beanFactory; + + private final String targetBeanName; + + public TargetBeanObjectFactory(BeanFactory beanFactory, String targetBeanName) { + this.beanFactory = beanFactory; + this.targetBeanName = targetBeanName; + } + + public Object getObject() throws BeansException { + return this.beanFactory.getBean(this.targetBeanName); + } } } diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ProviderCreatingFactoryBean.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ProviderCreatingFactoryBean.java new file mode 100644 index 00000000000..657d4e7bb23 --- /dev/null +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ProviderCreatingFactoryBean.java @@ -0,0 +1,95 @@ +/* + * Copyright 2002-2010 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.config; + +import java.io.Serializable; +import javax.inject.Provider; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.util.Assert; + +/** + * A {@link org.springframework.beans.factory.FactoryBean} implementation that + * returns a value which is a JSR-330 {@link javax.inject.Provider} that in turn + * returns a bean sourced from a {@link org.springframework.beans.factory.BeanFactory}. + * + *

This is basically a JSR-330 compliant variant of Spring's good old + * {@link ObjectFactoryCreatingFactoryBean}. It can be used for traditional + * external dependency injection configuration that targets a property or + * constructor argument of type javax.inject.Provider, as an + * alternative to JSR-330's @Inject annotation-driven approach. + * + * @author Juergen Hoeller + * @since 3.0.2 + * @see javax.inject.Provider + * @see ObjectFactoryCreatingFactoryBean + */ +public class ProviderCreatingFactoryBean extends AbstractFactoryBean { + + private String targetBeanName; + + + /** + * Set the name of the target bean. + *

The target does not have to be a non-singleton bean, but realisticially + * always will be (because if the target bean were a singleton, then said singleton + * bean could simply be injected straight into the dependent object, thus obviating + * the need for the extra level of indirection afforded by this factory approach). + */ + public void setTargetBeanName(String targetBeanName) { + this.targetBeanName = targetBeanName; + } + + @Override + public void afterPropertiesSet() throws Exception { + Assert.hasText(this.targetBeanName, "Property 'targetBeanName' is required"); + super.afterPropertiesSet(); + } + + + @Override + public Class getObjectType() { + return Provider.class; + } + + @Override + protected Provider createInstance() { + return new TargetBeanProvider(getBeanFactory(), this.targetBeanName); + } + + + /** + * Independent inner class - for serialization purposes. + */ + private static class TargetBeanProvider implements Provider, Serializable { + + private final BeanFactory beanFactory; + + private final String targetBeanName; + + public TargetBeanProvider(BeanFactory beanFactory, String targetBeanName) { + this.beanFactory = beanFactory; + this.targetBeanName = targetBeanName; + } + + public Object get() throws BeansException { + return this.beanFactory.getBean(this.targetBeanName); + } + } + +} diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests-context.xml b/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests-context.xml index 92a011c3437..3f0b9e5fc6a 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests-context.xml +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests-context.xml @@ -1,19 +1,24 @@ - - - + + - - + + - + + + + + + + + + diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests.java index f6649ddb73c..41c9ce811f1 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests.java +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBeanTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2010 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,43 +16,49 @@ package org.springframework.beans.factory.config; -import static org.easymock.EasyMock.*; -import static org.junit.Assert.*; -import static test.util.TestResourceUtils.qualifiedResource; - import java.util.Date; +import javax.inject.Provider; +import static org.easymock.EasyMock.*; +import org.junit.After; +import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; -import org.springframework.beans.BeansException; +import static test.util.TestResourceUtils.*; + import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.Resource; +import org.springframework.util.SerializationTestUtils; /** - * Unit tests for {@link ObjectFactoryCreatingFactoryBean}. - * * @author Colin Sampaleanu + * @author Juergen Hoeller * @author Rick Evans * @author Chris Beams - * @since 2004-05-11 */ -public final class ObjectFactoryCreatingFactoryBeanTests { +public class ObjectFactoryCreatingFactoryBeanTests { private static final Resource CONTEXT = qualifiedResource(ObjectFactoryCreatingFactoryBeanTests.class, "context.xml"); - private BeanFactory beanFactory; + private XmlBeanFactory beanFactory; @Before public void setUp() { this.beanFactory = new XmlBeanFactory(CONTEXT); + this.beanFactory.setSerializationId("test"); + } + + @After + public void tearDown() { + this.beanFactory.setSerializationId(null); } @Test - public void testBasicOperation() throws BeansException { - TestBean testBean = (TestBean) beanFactory.getBean("testBean"); + public void testFactoryOperation() throws Exception { + FactoryTestBean testBean = beanFactory.getBean("factoryTestBean", FactoryTestBean.class); ObjectFactory objectFactory = testBean.getObjectFactory(); Date date1 = (Date) objectFactory.getObject(); @@ -60,6 +66,40 @@ public final class ObjectFactoryCreatingFactoryBeanTests { assertTrue(date1 != date2); } + @Test + public void testFactorySerialization() throws Exception { + FactoryTestBean testBean = beanFactory.getBean("factoryTestBean", FactoryTestBean.class); + ObjectFactory objectFactory = testBean.getObjectFactory(); + + objectFactory = (ObjectFactory) SerializationTestUtils.serializeAndDeserialize(objectFactory); + + Date date1 = (Date) objectFactory.getObject(); + Date date2 = (Date) objectFactory.getObject(); + assertTrue(date1 != date2); + } + + @Test + public void testProviderOperation() throws Exception { + ProviderTestBean testBean = beanFactory.getBean("providerTestBean", ProviderTestBean.class); + Provider provider = testBean.getProvider(); + + Date date1 = (Date) provider.get(); + Date date2 = (Date) provider.get(); + assertTrue(date1 != date2); + } + + @Test + public void testProviderSerialization() throws Exception { + ProviderTestBean testBean = beanFactory.getBean("providerTestBean", ProviderTestBean.class); + Provider provider = testBean.getProvider(); + + provider = (Provider) SerializationTestUtils.serializeAndDeserialize(provider); + + Date date1 = (Date) provider.get(); + Date date2 = (Date) provider.get(); + assertTrue(date1 != date2); + } + @Test public void testDoesNotComplainWhenTargetBeanNameRefersToSingleton() throws Exception { final String targetBeanName = "singleton"; @@ -78,7 +118,6 @@ public final class ObjectFactoryCreatingFactoryBeanTests { assertSame(expectedSingleton, actualSingleton); verify(beanFactory); - } @Test @@ -119,10 +158,9 @@ public final class ObjectFactoryCreatingFactoryBeanTests { } - public static class TestBean { - - public ObjectFactory objectFactory; + public static class FactoryTestBean { + private ObjectFactory objectFactory; public ObjectFactory getObjectFactory() { return objectFactory; @@ -131,7 +169,20 @@ public final class ObjectFactoryCreatingFactoryBeanTests { public void setObjectFactory(ObjectFactory objectFactory) { this.objectFactory = objectFactory; } + } + + public static class ProviderTestBean { + + private Provider provider; + + public Provider getProvider() { + return provider; + } + + public void setProvider(Provider provider) { + this.provider = provider; + } } }