Announcement Announcement Module
Collapse
No announcement yet.
Using hierarchical BeanFactory as a factory hierarchy ? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Using hierarchical BeanFactory as a factory hierarchy ?

    Hi,

    I'm using spring-core, or more precisely the factory part, to build an IoC factory of sorts. In essence there is a hierarchy of factories where the root one defines default implementation types and sub factories can override them (see below for an example). However these redefinitions are not used but rather the ones in the root factory. Is there a way that the definitions of the sub factory are used ?

    Example code:

    Code:
    package ioctest;
    
    import org.springframework.beans.factory.support.DefaultListableBeanFactory;
    import org.springframework.beans.factory.support.RootBeanDefinition;
    
    public class Main
    {
        public static interface A
        {
            public B getSub();
        }
        public static class AImpl implements A
        {
            B b = null;
            public AImpl(B b)
            {
                this.b = b;
            }
    
            public AImpl(C c)
            {}
            public B getSub()
            {
                return b;
            }
        }
        public static interface B
        {}
        public static class BImpl implements B
        {}
        public static class BImpl2 implements B
        {}
        public static interface C
        {}
        public static class CImpl implements C
        {
            public CImpl(D d)
            {}
        }
        public static interface D
        {}
        public static class DImpl implements D
        {}
    
        private static void registerImplementation(DefaultListableBeanFactory factory, Class baseType, Class implType)
        {
            RootBeanDefinition newBeanDef = new RootBeanDefinition(baseType, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
    
            newBeanDef.setBeanClass(implType);
            newBeanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
            newBeanDef.setSingleton(false);
            newBeanDef.setDependencyCheck(RootBeanDefinition.DEPENDENCY_CHECK_NONE);
            factory.registerBeanDefinition(baseType.getName(), newBeanDef);
        }
        
        private static void testSimpleIndirection()
        {
            DefaultListableBeanFactory topContainer = new DefaultListableBeanFactory();
            DefaultListableBeanFactory subContainer = new DefaultListableBeanFactory(topContainer);
    
            registerImplementation(topContainer, A.class, AImpl.class);
            registerImplementation(topContainer, B.class, BImpl.class);
            registerImplementation(subContainer, B.class, BImpl2.class);
    
            A      a = (A)subContainer.getBean(A.class.getName());
            BImpl2 b = (BImpl2)a.getSub();
        }
    
        private static void testDoubleIndirection()
        {
            DefaultListableBeanFactory topContainer = new DefaultListableBeanFactory();
            DefaultListableBeanFactory subContainer = new DefaultListableBeanFactory(topContainer);
    
            registerImplementation(topContainer, A.class, AImpl.class);
            registerImplementation(subContainer, C.class, CImpl.class);
            registerImplementation(subContainer, D.class, DImpl.class);
    
            A a = (A)subContainer.getBean(A.class.getName());
        }
    
        public static void main(String[] args)
        {
            testSimpleIndirection();
            testDoubleIndirection();
        }
    }
    In the first test method I'd expect that the type registered in the sub container is used, but it is not (ClassCastException because it is BImpl, not BImpl2).
    In the second test method an UnsatisfiedDependencyException is issued because at the root factory neither something for B nor for C is registered.

  • #2
    I think you are a bit confused about how container hierarchies work. In a container hierarchy, a child knows about a parent, but not the other way around. So if you ask a child for a bean which actually gets satisfied by the parent, it is the parent which ends up doing the dependency injection, and it knows nothing about the child, so can't use the child as a source.

    Now what you are looking for is some sort of polymorphism, but it would be very hard to implement. First of all, keep in mind that the parent may have been created long before the child, and may have already pre-instantiated a number of the (singleton) beans. That's just one issue...

    Comment


    • #3
      I thought this is a standard hierarchy application. I mean, if I create a hierarchy (where the child know about the parent) than I expect that the child is intended to make it possible to refine or redefine something ?

      I had a look into the source code of the DefaultListableBeanFactory, and I think it is rather an implementation limitation. All it does is delegate the bean retrieval/creation to the parent factory, rather than retrieving the bean definitions (and singletons if possible) and creating the bean itself (which it could since it knows all about its parent).
      And if the parent factory already has a singleton, than the child factory can use this one, create a new one (i.e. if the mapping has changed) or raise an error, but this can be made configurable, or not ?

      I think I'll look a bit more into the source to see whether I can create a variation of the DefaultListableBeanFactory that works this way.

      Comment


      • #4
        Originally posted by Thomas Dudziak
        I thought this is a standard hierarchy application. I mean, if I create a hierarchy (where the child know about the parent) than I expect that the child is intended to make it possible to refine or redefine something ?
        .
        The child does make it possible to redefine something. The child will satisfy the request if the definition is also in the child.

        Ultimately, beans are created by the container that owns their definitions, and that container that creates a bean manages its lifecycle, too. That's the basis of how things work. Now you also do have parent and child bean definitions available to you, if you want to actaully have a definition in a child container for a bean from a parent.

        If you've got some good ideas, by all means file them as a feature request in JIRA. Just keep in mind that we can't do anything tha breaks backwards compatibility in terms of interfaces or behvioral semantics.

        Comment


        • #5
          The child does make it possible to redefine something. The child will satisfy the request if the definition is also in the child.
          Only if I redefine the resource that I request, but not for a resource that is requested via autowiring. See the source code from my initial post for an example of this problem.
          If you've got some good ideas, by all means file them as a feature request in JIRA. Just keep in mind that we can't do anything tha breaks backwards compatibility in terms of interfaces or behvioral semantics.
          As I said, I'll see whether I can create such a bean factory (I'll need it rather soon so I cannot wait for a JIRA feature request). If I'm successful and you're interested than I can put the result into a JIRA feature request. Are there some unit tests for bean factories that I can use ?

          Comment


          • #6
            There are unit tests up the wazoo, which should validate all interfaces and functionality...

            Just check out the code from CVS.

            Comment

            Working...
            X