Results 1 to 6 of 6

Thread: Creating dependent prototype beans

  1. #1

    Default Creating dependent prototype beans

    Can't quite figure out how to do this.

    I have two prototype beans A and B. B holds a reference to A but A does not know about B.

    B {
    A a;
    public void setA(A a);
    }

    I need to create these beans as related pairs, ie. I want to create a new instance of A and a new instance of B which has the new A injected, at the same time.

    (1) I would like this to happen when I request a new instance A from beanfactory. Client code would receive new A, and new B would be created (and injected the correct A) "behind the scenes". Client would not need to be aware of this or even of the existence of B, but the B object being created and injected with A is required for the A to work properly. (B registers itself as an Observer to A when A injected to it)

    It would be easy to request a new B from beanfactory get A from it, but I would rather not as B.getA returns super interface for A and I would need to cast it to the actual AImpl I need to use, and this is a little bit added indirection/complexity. I could also add a new "container bean" C which holds both A and B but I would rather not add that extra structure either.

    Can it (1) be done?

    The actual use case is model-view-presenter example where presenter holds view instance but view does not know about the presenter.

    A = View (impl)
    B = Presenter

  2. #2
    Join Date
    Jun 2007
    Location
    Dublin, Ireland
    Posts
    72

    Default

    I'm a little confused as to what exactly you are asking (especially around the casting point). Perhaps some of your configuration etc. might help convey the point.


    If I need more flexibility around the bean creation process, I create a Factory class and use method injection (look at Spring user guide for more info) to return a prototype bean. I can then invoke this method from within the factory and modify the bean in whatever way I want.

    Something like this:

    Code:
    public abstract class MyFactory {
      public abstract MyPrototype createMyPrototype();
      
      public MyPrototype createMySpecialPrototype(....) {
        MyPrototype mySpecialPrototype = createMyPrototype();
        // do some stuff with mySpecialPrototype
        // perhaps set dependency with some other prototype??
        return mySpecialPrototype;
      }
    }
    
    <bean id="entityFactory" class="MyFactory">
      <lookup-method name="createMyPrototype" bean="myPrototype"/> 
    </bean>
    
    <bean id="myPrototype" class="MyPrototype" scope="prototype"/>
    I'm not sure that this is not overkill in your situation but hopefully it gives you another option to try out.
    -----------------------
    John Turner

    http://thoughtforge.net

  3. #3

    Default

    I understand my question is a bit confusing and am trying to come up with examples which would not be so related to the actual solution that they are hard to understand...

    Example:

    Code:
    FridgeA {
      public void addFoodItems(List<FoodItem> l);
      public List<FoodItems> getAllItems();
      public void addFridgeEmptyObserver(FridgeEmptyObserver o);
    }
    
    FridgeRefillManagerB {
      private FridgeA f;
      private ShoppingService s;
      ...
      public void setFridge(Fridge f) {
        f.addFridgeEmptyObserver(this);
        this.f = f;
      }
      ..
    }
    Now, Fridge, FridgeRefillManager and ShoppingService are spring-managed beans. ShoppingService is a singleton, and Fridge and its manager are prototypes that should be created as pairs. Spring should inject the dependencies so that FridgeRefillManager has a Fridge and the ShoppingService.

    Client code in this case does not need to or want to know about FridgeRefillManager. It creates new fridges and the manager instance should be created and associated with the Fridge behind the scenes. client code more or less wants to do

    Code:
    beanFactory.getBean("fridge")
    and receive a new Fridge instance, with a new FridgeRefillManager created in background.

  4. #4
    Join Date
    Jun 2007
    Location
    Dublin, Ireland
    Posts
    72

    Default

    Can you create the Fridge with a default observer added like below?

    Code:
    <bean id="FridgeRefillManagerB" scope="prototype"....../>
    
    <bean id="FridgeA" scope="prototype">
      <property name="observers">
        <util:list>
          <ref local="FridgeRefillManagerB"/>
        </util:list>
      <property>
    </bean>
    The only thing this does not do is give the manager a reference to the fridge. If you want to do this, I'm afraid you will have to use the method lookup I mentioned previously.
    -----------------------
    John Turner

    http://thoughtforge.net

  5. #5

    Default

    Quote Originally Posted by turnerj View Post
    Can you create the Fridge with a default observer added like below?

    ....

    The only thing this does not do is give the manager a reference to the fridge. If you want to do this, I'm afraid you will have to use the method lookup I mentioned previously.
    No....manager needs the reference to Fridge. When manager receives info that the fridge is empty, it needs to do some shopping and then call fridge.addFoodItems(). In this silly example

    I think I am going to use the manager object to get the reference to the "fridge". Along the lines:

    Code:
       Fridge newFridge = beanFactory.getBean("fridgeRefillManager").getFridge();
    with some (ugly) casting added as needed. The dowside is that client code becomes aware of the fridgeRefillManager, even though it wouldnt need to, and the syntax is a bit ugly. But I dont want to create a set of creation / dependecy setting methods by hand for the method injection (there's many different bean classes that need the same treatment).

  6. #6

    Default

    I got an idea....thought that defining fridge bean as depends-on="manager" would ensure that when I request a new fridge instance, a new manager bean is created and injected the fridge. But unfortunately this did not work:

    Code:
        <bean id="fridge" class="FridgeImpl"
             scope="prototype" depends-on="refillManager" />
    
        <bean id="refillManager" class="FridgeRefillManager"
            scope="prototype">
            <property name="fridge" ref="fridge" />
            <property name="SomeService" ref="someFooService" />
        </bean>

    Code:
            ... 29 more
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'refillManager' defined in file [C:\....\applicationContext.xml]: Cannot resolve reference to bean 'fridge' while setting bean property 'refillManager'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'refillManager': Requested bean is currently in creation: Is there an unresolvable circular reference?
            at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)
            at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:106)
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1308)
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1067)
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:511)
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:450)
            at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:309)
            at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:189)
            at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:280)
            at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:189)
            at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1044)
            at com.coreanticipe.safproto.model.spring.BeanFactory2.getBean(BeanFactory2.java:26)
            at com.coreanticipe.safproto.DesktopApplication1View.showWizard(DesktopApplication1View.java:275)
            ... 34 more
    Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'refillManager': Requested bean is currently in creation: Is there an unresolvable circular reference?
            at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:251)
            at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:189)
            at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:280)
            at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:189)
            at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:322)
            ... 46 more
    If the beans are not prototypes but singletons, this does work and no circular reference -problems.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •