0

I injected a bean by setter into another bean in Spring Boot. The bean is not null when inside the setter, but when I call it from another method, it returns null.

I've tried all combinations (injecting by constructor and setter, autowiring field only, autowiring field and setter...).

SpringConfiguration.java

@Bean
public BeanToInject beanToInject(){
    return new BeanToInject();
}
@Bean
public TargetClass targetClass(){
    return new TargetClass();
}

BeanToInject.java

@Component
public class BeanToInject{
    public BeanToInject(){}
    //More stuff
}

TargetClass.java

@Component
public class TargetClass {

    private BeanToInject beanToInject;

    public TargetClass(){}

    @Autowired
    public void setBeanToInject(BeanToInject beanToInject){
        this.beanToInject = beanToInject;
        System.out.print("1. " + this.beanToInject); //Here is instanced
    }

    public void anotherMethod(){
        System.out.print("2. " + beanToInject); //Here is null
        beanToInject.doSomeStuff(); //Here comes the exception
    }

}

Output:

//Spring stuff...
1. com.foo.bar.BeanToInject@blahblah
2. null

//------And then, the exception

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
    at acteso.standard.deskapp.gui.LoginController.btAceptar(LoginController.java:82)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Node.fireEvent(Node.java:8411)
    at javafx.scene.control.Button.fire(Button.java:185)
    at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
    at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
    at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:394)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:432)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:410)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:431)
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
    at com.sun.glass.ui.View.notifyMouse(View.java:937)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$3(WinApplication.java:177)
    at java.lang.Thread.run(Unknown Source)

I guess the exception won't be usefull at all. I'm using JavaFX but it doesn't matter when the exception comes from Spring.

I don't know if I'm missing any annotation or if I have configured it wrong.

Edit:

Actually it was a problem about Spring and JavaFX creating their own instances of TargetClass, so BeanToInject was duplicate. I solved it by making Spring manage the JavaFX controllers, following this tutorial: Add Spring to JavaFX. Thanks to all for the help!

Niedon
  • 15
  • 1
  • 8
  • 1. one of @ Component / @ Bean would suffice to make the java class a bean. 2. How are you obtaining the TargetClass instance and calling the method anotherMethod() – R.G Nov 03 '19 at 10:38
  • 1. Should I delete one of @Component or @Bean? 2. TargetClass is a FXML Controller, the fxml file references it in and the FXMLLoader instantiates it as a controller. anotherMethod() is an onAction event for a button. – Niedon Nov 03 '19 at 10:54
  • I am not familiar with FXML Controller. This link may be helpful : https://stackoverflow.com/questions/22910399/how-to-wire-multiple-fxml-controllers-using-spring-dependency-injection . – R.G Nov 03 '19 at 10:57
  • It helped me to finally find the answer, thanks! – Niedon Nov 03 '19 at 16:12

1 Answers1

0

An example

BeanOne (BeanToInject)

public class BeanOne {

}

BeanTwo ( TargetClass )

public class BeanTwo {

    BeanOne beanOne;


    @Autowired
    public void setBeanOne(BeanOne beanOne) {
        this.beanOne = beanOne;
        System.out.println("From setter "+beanOne);
    }

    public void testMethod() {
        System.out.println("From testMethod "+beanOne);
    }


}

Configuration . Note that , only @Bean is used here

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class TestConfiguration {

    @Bean
    public BeanOne getBeanOne() {
        return new BeanOne();
    }

    @Bean
    public BeanTwo getBeanTwo() {
        return new BeanTwo();
    }
}

Test App

public class TestApp {

    public static void main(String[] args) {

        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(TestConfiguration.class);

        ctx.registerShutdownHook();

        BeanTwo bean = ctx.getBean(BeanTwo.class);

        bean.testMethod();
    }

}

The output when run

From setter BeanOne@7f1302d6
From testMethod BeanOne@7f1302d6

Spring container injects the instance of BeanOne when BeanTwo is created. During this the "From setter" message gets printed.

Then we are obtaining this BeanTwo instance from the ApplicationContext and testMethod() is called , which gives the "From testMethod" message.

From the way it looks , in your case you are creating the BeanTwo ( TargetClass ) instance on your own (new TargetClass() ) . Such a bean is not managed by the Spring Container and will have BeanOne reference as null when created.

R.G
  • 6,436
  • 3
  • 19
  • 28
  • Well, after a lot of search, you are right, but it happens for a reason I didn't expect to happen. Spring instantiates my controller (TargetClass) and then JavaFX/FXMLLoader instantiates it again, and this second one is who answers when I click a button (and it doesn't have the autowired BeanToInject). So technically, you're right. – Niedon Nov 03 '19 at 16:11