asgs
asgs

Reputation: 3984

Spring: Value is null when an object is injected to both base and child class beans

I have a parent abstract class and a concrete child class. The abstract one has one concrete method and one other abstract method, which the child class implements. Both of these classes are configured as Spring beans. The code snippets are similar to below:

Spring Config:

<bean id="parent" class="Parent" abstract="true">
  <property name="propA" ref="propA"/>
  <property name="cacheMan" ref="cacheMan"/>
</bean>

<bean id="child" class="Child" parent="parent">
  <property name="propB" ref="propB"/>
  <property name="cacheMan" ref="cacheMan"/>
</bean>

<!-- Of course, cacheMan is defined elsewhere and not relevant here.-->

Class definitions:

    public abstract class Parent {
      private A propA; // A is irrelevant.
      private CacheManager cacheMan; // This is the object in question.
      public void doProcess1() {
         //code logic
         if (cacheMan == null) {
            // Error!
         }
      }
      public void doProcess2();
    }

    public class Child extend Parent {
      private B propB; // Again, B is irrelevant.
      private CacheManager cacheMan; // This is the object in question.
      public void doProcess2() {
         //code logic
      }
    }


public class Test {
        private Parent parent; //Assume this is Spring injected and it's of type Child.
        public void doTest() {
          parent.doProcess1(); // Error thrown since cacheMan is null.
        }
}

Both of these classes have appropriate getter/setter methods for cacheMan. I don't understand how cacheMan is being null in the doProcess1() method. However, if i change that line from

cacheMan == null to getCacheMan() == null, the error is not thrown.

I think the getCacheMan() is retrieving the object injected to the child class, since parent is of the instance Child and that's why it's not being null.

Please shed some light on it and let me know if this is not clear.

Upvotes: 1

Views: 3410

Answers (1)

Tomasz Nurkiewicz
Tomasz Nurkiewicz

Reputation: 340693

This problem is not related to Spring but to Java language - method overriding to be specific.

You have setCacheMan() (that's what I assume) method defined in both abstract parent and child class. When Spring calls that method, it always calls the overriden version in child - and that version modifies cacheMan reference in child as well. cacheMan reference in parent is never really touched because the only method that accesses it is overriden in child.

if i change that line from cacheMan == null to getCacheMan() == null, the error is not thrown.

That is quite obvious from what has already been said - getCacheMan() is also overriden! cacheMan reference in parent is null (see above), but since getCacheMan() is overriden, it accesses cacheMan in child, not in parent. Effectively you have two variables, but the one in child can't be upated.

Solution: the idea of parent bean is to have common dependencies in one place and avoid duplicating them in every child:

<bean id="parent" class="Parent" abstract="true">
  <property name="propA" ref="propA"/>
  <property name="cacheMan" ref="cacheMan"/>
</bean>

<bean id="child" class="Child" parent="parent">
  <property name="propB" ref="propB"/>
</bean>

And either declare cacheMan protected or have at least protected getter so that child classes can access it. Do not create cacheMan field in child classes.

Upvotes: 2

Related Questions