Search code examples
javaspringspring-mvcautowiredcglib

Strange behavior with Spring CGlib autowairing?


I am working with Spring MVC application.

I want to create new event:

fill data at page > controller handle this info > saving new event to DB

I have already created DAO layer and repository layer. But at some places, it behaves very strangely. I have created Java configuration for all repositories in the same way.

Here is Repositories Configuration snippet:

@Configuration
@ComponentScan({ "net.lelyak.edu.repository", "net.lelyak.edu.service" })
@Import({ DatabaseDAOConfiguration.class })
public class ApplicationConfiguration {

    @Autowired
    private UserDAO userDAO;

    @Autowired
    private EventDAO eventDAO;

    @Autowired
    private TicketDAO ticketDAO;

    @Autowired
    private AuditoriumDAO auditoriumDAO;

    @Bean
    public AuditoriumRepository auditoriumRepository() {
        AuditoriumRepository auditoriumRepository = new AuditoriumRepository();
        auditoriumRepository.setDao(auditoriumDAO);
        return auditoriumRepository;
    }

    @Bean
    public EventRepository eventRepository() {
        EventRepository eventRepository = new EventRepository();
        eventRepository.setDao(eventDAO);
        return eventRepository;
    }

I have faced strange behavior at the controller level.

Here is controller code snippet:

@Controller
@RequestMapping("events")
public class EventsController {

    @Autowired
    private AuditoriumRepository auditoriumRepository;
    @Autowired
    private EventRepository eventRepository;

    @RequestMapping(path = "add", method = RequestMethod.POST)
    public String addEvent(@RequestParam Map<String, String> allRequestParams) {
       Event newEvent = new Event();
       // get auditorium id from request
       String auditoryIdString = allRequestParams.get("auditorium");
       Long auditoryId = Long.parseLong(auditoryIdString);
       Auditorium auditorium = auditoriumRepository.getById(auditoryId);
       newEvent.setAuditorium(auditorium);

AuditoriumRepository is auto-wired fine.
Here is snippet from debug view:

enter image description here

but EventRepository isn't:

enter image description here

Configuration is the same for both. One repository is auto-wired fine, second fails. I am newly at Spring. I can't get a clue why does this happen?

Here is snippet of code from EventRepository:

public class EventRepository extends BaseRepository<Event, EventDAO> {

    @Autowired
    private AuditoriumRepository auditoriumRepository;

    @Override
    public int put(Event entity) {
        auditoriumRepository.put(entity.getAuditorium());
        return super.put(entity);
    }

AuditoriumRepository code snippet:

public class AuditoriumRepository extends BaseRepository<Auditorium, AuditoriumDAO> {

    @Override
    public Auditorium preSave(Auditorium entity) {
        return entity;
    }

For saving new event to DB I have to use exactly EventRepository. It fails, of course, with following stack trace:

java.lang.NullPointerException 
at net.lelyak.edu.repository.BaseRepository.put(BaseRepository.java:23) 
at net.lelyak.edu.repository.EventRepository.put(EventRepository.java:20) 
at net.lelyak.edu.repository.EventRepository$$FastClassBySpringCGLIB$$5de8d2a5.invoke() 
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)

I am using spring 4.2.4.RELEASE on Windows 10.

UPDATE:

BaseRepository code snippet:

public abstract class BaseRepository<T extends BaseEntity, E extends BaseDAO<T>> {    
    private E dao;

    public E getDao() {
        return dao;
    }

    public void setDao(E dao) {
        this.dao = dao;
    }

    public int put(T entity) {
        return dao.save(preSave(entity));
    }

I can't understand why with the same configuration and repository structure. One instance is auto-wired by Spring fine, but the second one fails. How to find the root of this problem? And some solution.

UPDATE 2:

I have tried recommended solution, and added next setter to EventRepository:

public void setAuditoriumRepository(AuditoriumRepository auditoriumRepository) {
    System.out.println("EventRepository.setAuditoriumRepository");
    this.auditoriumRepository = auditoriumRepository;
}

As log message show this setter is executed. But keep failing for the same reason.

How to solve this issue?


Solution

  • i saw your code and the problem is not related to Spring and autowiring process. The problem is in your save method in BaseDAO class:

    @Override
    public Integer save(ENTITY entity) {
        if (entity.getId() == null) {
            insert(entity);
        } else {
            update(entity);
        }
        return null;
    }
    

    if you change the metod to return newly inserted/updated entity id it will work fine.

    try to hardcode it just for test :

    @Override
    public Integer save(ENTITY entity) {
        if (entity.getId() == null) {
            insert(entity);
        } else {
            update(entity);
        }
        return 1;
    }
    

    and the problem is raised when you return null from save method then you are doing assignment in the EventsController class which is:

    int eventId = eventRepository.put(newEvent); //this is null and throws NullPointerException because you are trying to assign null to primitive variable.