-2

I am trying to autowire an object but it gets null. I have read many questions and answers, still no chance. Here is my Spring boot configuration:

package com.alinso.fantasy;

import javax.persistence.EntityManagerFactory;

@SpringBootApplication
@ComponentScan({"com.alinso.fantasy","com.alinso.fantasy.database"})
@Configuration
public class FantasyApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(FantasyApplication.class, args);
    }

    @Autowired
    private EntityManagerFactory entityManagerFactory;

    @Bean
    public SessionFactory getSessionFactory() {
        if (entityManagerFactory.unwrap(SessionFactory.class) == null) {
            throw new NullPointerException("factory is not a hibernate factory");
        }
        return entityManagerFactory.unwrap(SessionFactory.class);
    }
}

Here is the class to be autowired :

package com.alinso.fantasy.database;

@Service
public class BookDAO implements IBookDAO {

    @Autowired
    SessionFactory sessionFactory;


    public UUID save(Book book){
        Session session= sessionFactory.getCurrentSession();
        session.saveOrUpdate(book);
        return book.getId();
     }
}

Finally, here is the class where I get NPE;

package com.alinso.fantasy.resource;

@Controller
public class BookResource {

    @Autowired
    private IBookDAO bookDao;

    public void saveBook() {
        Book b = new Book();
        b.setBook_name("harry potter");
        b.setPrice(50.00);
        bookDao.save(b);  // null pointer exception here
    }
}

IBookDAO interface;

package com.alinso.fantasy.database;

public interface IBookDAO {
    public UUID save(Book book);
}

edit: I am calling the controller method from a test, as below :

public class BookResourceTest {

    @Test
    public void saveBook() {
        BookResource bookResource = new BookResource();
        bookResource.saveBook();
    }
} 
buræquete
  • 14,226
  • 4
  • 44
  • 89
Ali insan Soyaslan
  • 836
  • 5
  • 14
  • 33
  • annotate your `IBookDAO` interface with `@Service` and let me know the status. – Ataur Rahman Munna Dec 14 '17 at 06:52
  • 1
    Try to use constructor injection, and set breakpoint to the constructor body – awesoon Dec 14 '17 at 06:52
  • @AtaurRahmanMunna I added @ service to interface, still same – Ali insan Soyaslan Dec 14 '17 at 06:57
  • Did you try not using from `@Test` ? – Ataur Rahman Munna Dec 14 '17 at 07:00
  • @AtaurRahmanMunna No, I need to make it work inside a test. – Ali insan Soyaslan Dec 14 '17 at 07:02
  • `BookResource` class is not included in your component scan and not autowired, therefore nothing inside is autowired, add its package also in your component scan, namely `com.alinso.fantasy.resource`, and autowire the controller, don't initialize it with constructor. – buræquete Dec 14 '17 at 07:02
  • @bureaquete ComponentScan({"com.alinso.fantasy","com.alinso.fantasy.database","com.alinso.fantasy.resource"}) did not make any changes – Ali insan Soyaslan Dec 14 '17 at 07:05
  • @bureaquete I did not init in constructor actually. – Ali insan Soyaslan Dec 14 '17 at 07:06
  • @AliinsanSoyaslan you gotta autowire `BookResource` in your test, also test has to have some spring runner defined for autowire to work, check [testing in Spring boot here](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html) – buræquete Dec 14 '17 at 07:06
  • You cannot just write `new BookResource()` and assume that all properties will be automagically injected. Spring should create these beans by itself. Here is good article in the official docs how should tests be written with Spring Boot: [Part IV. Spring Boot features: Testing](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html). In general - you have to specify spring configuration for your test and specify a test runner, to allow Spring to initialize all required beans. – awesoon Dec 14 '17 at 07:09

1 Answers1

2

In your test, you have to have runners defined for Spring to initialize your @Autowired variables. Also beware that all classes that you'd like to inject are included in your component scan.

Also, you can skip manually declaring package naming for component scan, just put the main SpringApp class annotated with @SpringBootApplication in the base of your package structure, that will trigger component scan anything in & under of that package, check this.

More information on how injection works on Spring
And on testing in Spring Boot

buræquete
  • 14,226
  • 4
  • 44
  • 89