Search code examples
javaspringjunit4autowired

Autowired Bean in two classes not being updated after accessing it from the second class


I have the following scenario:

A bean Autowired in two classes, I populate the bean in one class, then I check the bean in the second class, it is not populated. Whereas, when I add a getter in the class where I populated the bean and call the getter, it returns the bean populated. Why can't I access that bean directly in the other class, shouldn't it be populated since it's acting as a singleton in spring context?

A JUnit4 test class loading the spring context from an xml file:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/spring/test-main-context.xml" })
public class MyTests {

    @Autowired
    MyObject myObject;

    @Autowired
    MyUtils myUtils;

    @Test
    public void testingContext() {
        myUtils.setMyObjectFromDB();
        System.out.println(myUtils.getMyObject().getId());
        System.out.println(myObject.getId());
    }
}

MyUtils:

public class MyUtils {

    @Autowired MyObject myObject;

    public void setMyObjectFromDB() {
        MyObject myDBObject = new MyObject();
        //
        // getting myObjectFromDB;
        //
        myObject = myDBObject;
    }

    public MyObject getMyObject() {
        return myObject;
    }
}

In the test class, myUtils.getMyObject().getId() returns a correct id but the second line myObject.getId() it returns null.

Why is MyObject which is set in MyUtils class and is @Autowired in both classes is not being updated when I access it directly in the test class.


Solution

  • When you're reassigning myObject = myDBObject; in setMyObjectFromDB method, you're creating a new object and saving it's referene in myObject variable which is different from the one created with Autowired.

    When you use Autowired, then it will assign the created bean's reference in the variable. But if you reassign that variable, it will point to the new object.

    EDIT:

    If you really need to update all the variables of myObject with initialized with Autowired, it is better to create a container class that stores myObject variable.

    public class MyObjectContainer {
         @Autowired
         MyObject myObject;
    
         // Getters & Setters
    }
    

    In all the classes, where you're autowiring myObject, use an object of MyObjectContainer class instead. And when you want to update myObject value, just update it in myObjectContainer object with it's setter. So your MyUtils would be like:

    public class MyUtils {
    
        @Autowired MyObjectContainer myObjectContainer;
    
        public void setMyObjectFromDB() {
            MyObject myDBObject = new MyObject();
            //
            // getting myObjectFromDB;
            //
            myObjectContainer.setMyObject(myDBObject);
        }
    
        public MyObjectContainer getMyObjectContainer() {
            return myObjectContainer;
        }
    }