0

I'm getting a null pointer when I try to access and use a SimpleJdbcDaoSupport. This is how I'm working it out:

In the main class

@Override
    public void start(final Stage primaryStage) {

        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");

        SimpleJdbcDaoImpl dao = ctx.getBean("simpleJdbcDaoImpl", SimpleJdbcDaoImpl.class);

In some other stage controller class

public class HomeController implements Initializable {

    @Autowired
    private SimpleJdbcDaoImpl simpleJdbcDaoImpl;

    // Initializes the controller class.
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // Stage and the rest called
    }

    @FXML
    public void showNewCalendarStage() throws Exception {
        System.out.println(simpleJdbcDaoImpl.getCircleCount());
    }

The SimpleJdbcDaoSupport class

import org.springframework.jdbc.core.simple.SimpleJdbcDaoSupport;

public class SimpleJdbcDaoImpl extends SimpleJdbcDaoSupport {

    public int getCircleCount() {
        String sql = "SELECT COUNT(*) FROM KIWI_TABLE";
        return this.getJdbcTemplate().queryForInt(sql);
    }
}

The spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:context="http://www.springframework.org/schema/context"
     xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="org.h2.Driver"/>
        <property name="url" value="jdbc:h2:file:C:/WAKILI/WAKILIdb"/>
        <property name="username" value="sa"/>
        <property name="password" value=""/>
    </bean>

    <bean id="simpleJdbcDaoImpl" class="wakiliproject.dao.SimpleJdbcDaoImpl">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="configLocation">    
            <value>
                classpath:/hibernate.cfg.xml
            </value>
        </property>

        <property name="hibernateProperties">
            <props>
                <prop key="dialect">org.hibernate.dialect.H2Dialect</prop>
            </props>    
        </property>

    </bean>


    <context:annotation-config/>
    <context:component-scan base-package="wakiliproject"/>

</beans>

The error:

Caused by: java.lang.NullPointerException
    at HomeController.showNewCalendarStage(HomeController.java:283)
    ... 42 more

I'm trying to teach myself Spring and would like to, for example, populate a Label in another Controller class (other than the main class) with text retrieved from the database.

For simplicity, in this case, lets print some text from the database to the console. What am I doing wrong with the above code? Thank you all.

Program-Me-Rev
  • 6,184
  • 18
  • 58
  • 142
  • `ApplicationContext ctx = new ClassPathXmlApplicationContext` in a web app? All context initialization should be let to Spring to handle (meaning, in web.xml you define the needed classes). Have you looked at some simple Spring web app samples? – Andrei Stefan Jul 22 '14 at 15:02
  • Thanks for the reply @Andrei Stefan. I'm working on a stand-alone. I'm not sure if the implementation is the same but I'd love to look at that. I would appreciate some links to some useful projects, if you have some. – Program-Me-Rev Jul 22 '14 at 15:10

1 Answers1

0

In order for a Spring bean to be injected with its collaborators, it has to be managed by Spring. The HomeController is actually managed by FXML, which knows nothing about Spring annotations (@Autowired) and will ignore them. Even worse, assuming that the HomeController is under the wakiliproject package (or one of its subpackages), Spring will indeed create another instance of the HomeController that will have the @Autowired stuff injected but NOT the @FXML stuff.

Depending on how you load the controller you may be able to set the instance of the HomeController retrieved from Spring as the controller of the .fxml view. So:

  1. Make sure Spring actually sees the HomeController (this will give you an instance of HomeController with the @Autowired stuff injected).

  2. Load the FXML document as:

    HomeController homeController = springContext.getBean(HomeController.class);
    FXMLLoader fxmlLoader = new FXMLLoader(xxx.getResource("HomeController.fxml"));
    fxmlLoader.setController(homeController);
    try {
        fxmlLoader.load();
    } catch...
    

    The above is almost pseudo-code, adapt as necessary!

    If the load() is successful, the the @FXML fields of the controller will be populated too and its initialization method will be called.

Check out the VERY helpful answer to this question.

Community
  • 1
  • 1
Nikos Paraskevopoulos
  • 39,514
  • 12
  • 85
  • 90
  • You might also consider using a controller factory on the `fxmlLoader`. Something like `fxmlLoader.setControllerFactory((Class> clazz) -> springContext.getBean(clazz));` – James_D Jul 22 '14 at 15:14
  • Thanks @Nikos Paraskevopoulos. It took some hours but I now get it. Thanks for pointing me on the direction to go. – Program-Me-Rev Jul 23 '14 at 10:36