Announcement Announcement Module
Collapse
No announcement yet.
A factory that takes an argument Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • A factory that takes an argument

    Our application includes a factory that returns an instance based on a parameter passed to the factory method. Something like this:

    Code:
    InterestingThing thing = ThingFactory.getThing(23);
    InterestingThing other = ThingFactory.getThing(99);
    How would this factory be implemented in spring? In my limited experience w/Spring I always get an object from the BeanFactory simply by name... Hoping the solution isn't a unqiue named <bean> entry for every possible "thing" implementation; there are 250+ and counting.

    Thanks!

  • #2
    Re: A factory that takes an argument

    Originally posted by jlindwall
    Our application includes a factory that returns an instance based on a parameter passed to the factory method. Something like this:

    Code:
    InterestingThing thing = ThingFactory.getThing&#40;23&#41;;
    InterestingThing other = ThingFactory.getThing&#40;99&#41;;
    How would this factory be implemented in spring? In my limited experience w/Spring I always get an object from the BeanFactory simply by name... Hoping the solution isn't a unqiue named <bean> entry for every possible "thing" implementation; there are 250+ and counting.

    Thanks!
    I don`t think this can be done at the moment. But what you could do is let the beanfactory return your ThingFactory (this is a 'technique' I use myself). The problem is that the beans created by your ThingFactory can`t use features of the Spring container.

    Comment


    • #3
      Creating your own factories is really the only answer atm.

      If you make your factory BeanFactoryAware you get access to the underlying bean factory so you can specify a target bean name in your factory and use Spring to create new instances, then setting the property you passed into the factory invocation. Like this:

      Code:
      public class MyFactory implements FactoryBeanAware &#123;
        private BeanFactory beanFactory;
        private Map thingMap = new HashMap&#40;&#41;;
        private String targetBeanName;
        public void setBeanFactory&#40;BeanFactory beanFactory&#41; throws BeansException &#123;
          this.beanFactory = beanFactory;
        &#125;
        
        /**
         * Sets targetBeanName property.
         * @param targetBeanName String
         * Name of bean to retrieve.  Should be prototype.
         */
        public void setTargetBeanName&#40;String targetBeanName&#41; &#123;
          this.targetBeanName = targetBeanName;
        &#125;
        
        public Thing getThing&#40;int arg1&#41; &#123;
          Integer key = new Integer&#40;arg1&#41;;
          Thing result = &#40;Thing&#41;thingMap.get&#40;key&#41;;
          if &#40;result == null&#41; &#123;
            Thing thing = beanFactory.getBean&#40;targetBeanName&#41;;
            thing.setThingArg1&#40;arg1&#41;;
            // Call init-method here &#40;or afterPropertySet if Thing is an InitializingBean&#41; if Thing requires more initialization after arg1 is set.
            thingMap.put&#40;key, thing&#41;;
            result = thing;
          &#125;
          return result;
        &#125;
      &#125;
      The targetBeanName has to be a prototype since getThing needs it create a new bean if necessary.

      Keep in mind if the init-method (such as afterPropertySet) depends on arg1, you'll ned to make a call to thing after setThingArg1 is called.

      Comment


      • #4
        Re: A factory that takes an argument

        Originally posted by Alarmnummer
        I don`t think this can be done at the moment.
        Whatchoo talkin' bout, Willis?

        Code:
        	<bean id="thing" class="com.thingcorp.ThingFactory" factory-method="getThing">
        		<constructor-arg value="23"/>
        	</bean> 
        
        	<bean id="other" class="com.thingcorp.ThingFactory" factory-method="getThing">
        		<constructor-arg value="99"/>
        	</bean>

        Comment


        • #5
          He needs to do it in code. Yes, you can code his example in an XML file, but he wants to get a bean, passing any value he wants at runtime.

          Comment


          • #6
            Re: A factory that takes an argument

            Originally posted by cepage
            Originally posted by Alarmnummer
            I don`t think this can be done at the moment.
            Whatchoo talkin' bout, Willis?
            Check what the topic starter wants. He doesn`t want to give the arguments in the Spring context, but want add add those arguments when he retrieves the beans. I think this would be a nice addon to Spring.

            example:
            Button button = (Button)appContext.getBean("buttonFactory","SWT");

            Comment


            • #7
              Trying to follow

              I'm trying to grok the replies. Not sure if I get it just yet, but I'll study the posts more closely. In the meantime, here's a little more detail on the factory I'm dealing with.

              This is a legacy system BTW; I possible could change the existing design but would rather not if possible.

              As I mentioned it accepts an integer ID which is used by the factory to return an appropriate type of Thing. The factory actually uses a database table to map the integer ID to a classname. An instance of the classname if Class.forName().newInstance()d and returned to the caller. You could imagine it as something like this (not the actual implementation but gives you the gist):

              Code:
              Thing getThing&#40;int id&#41;
              &#123;
                   switch id&#58;
                        case 1&#58;
                             return new Thing1&#40;&#41;; break;
                        case 2&#58;
                             return new Thing2&#40;&#41;; break;
                        ...
              I hope that clarifies my situation. The integer is used to perform the lookup; I do not need to store that ID in the returned object.

              Thanks for the responses!

              Comment


              • #8
                Re: A factory that takes an argument

                Originally posted by Alarmnummer
                I think this would be a nice addon to Spring.

                example:
                Button button = (Button)appContext.getBean("buttonFactory","SWT");
                This works from an API standpoint, but I'm not sure it makes sense in the Spring scheme of things. The point of the BeanFactory is to provide a mechanism for allowing push, or DI, configuration. But this is an explicitly pull form of configuration that would always require a code-level dependency on the BeanFactory.

                Spring's approach to dynamic configuration needs is usually to rely on the AOP framework. I could outline an approach using HotSwappableTargetSource, but I don't think it would buy him anything over his existing solution of ThingFactory.getThing(id).

                Comment


                • #9
                  Re: A factory that takes an argument

                  Originally posted by cepage
                  This works from an API standpoint, but I'm not sure it makes sense in the Spring scheme of things.
                  I don`t see why not The difference between no argument and a argument shouldn`t be that big a difference.

                  The point of the BeanFactory is to provide a mechanism for allowing push, or DI, configuration. But this is an explicitly pull form of configuration that would always require a code-level dependency on the BeanFactory.
                  I agree. If I need something like this I create a Factory in the app context and everybody can use the factory and parametrize it however they want it.

                  But there are cases where objects just are not created by Spring. And then you have to access the beanfactory.. in such cases it could be a nice addon (although this isn`t normal practice)

                  Comment


                  • #10
                    Use the ContextSingletonBeanFactoryLocator

                    I had some similar requirements in the application I was building and finally resolved this by using a ContextSingletonBeanFactoryLocator.

                    The idea is to create a separate applicationcontext.xml file containing all the bean instances maintained by the factory class. The beanRefContext.xml would then refer to this xml file.

                    example :

                    beanRefContext.xml
                    Code:
                    <beans>
                    
                    	<bean id="properties-context"
                    		class="org.springframework.context.support.ClassPathXmlApplicationContext">
                    		<constructor-arg>
                    			<list>
                    				<value>/META-INF/properties-applicationContext.xml</value>
                    			</list>
                    		</constructor-arg>
                    	</bean>
                    	
                    </beans>
                    properties-applicationcontext.xml
                    Code:
                    <beans>
                    
                    	<!-- Mapper implementation for the Party class -->
                    	<bean id="partyPropertyMapper"
                    		class="be.titan.hesperus.general.persistence.XMLPropertyMapper">
                    		<constructor-arg>
                    			<value>
                    				/var/workspace/Hesperus/PropertyMaps/PartyProperties.xml
                    			</value>
                    		</constructor-arg>
                    	</bean>
                    .....
                    And using this stuff within your code that requires the factory :

                    Code:
                    	public void setPropertyMapper&#40;String propertyMapper&#41; &#123;
                    		// this method uses a Spring ContextSingletonBeanLocator
                    		// for retrieving the propertyMapper to associate with this 
                    		// handler
                    		BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance&#40;"/META-INF/beanRefContext.xml"&#41;;
                    		BeanFactoryReference bfr = locator.useBeanFactory&#40;"properties-context"&#41;;		
                    		BeanFactory factory = bfr.getFactory&#40;&#41;;
                    		this.setPropertyMapper&#40;&#40;PropertyMapper&#41; factory.getBean&#40;propertyMapper&#41;&#41;;
                    		bfr.release&#40;&#41;;
                    		
                    	&#125;
                    Hopes this is helpfull since I'm also rather new to Spring coming from an EJB background :lol:

                    Comment


                    • #11
                      Similar topic here:
                      http://forum.springframework.org/showthread.php?t=16163
                      Last edited by robyn; May 15th, 2006, 06:59 PM.

                      Comment

                      Working...
                      X