0

When autowiring a component, in this case a @Service, I get a BeanInstantiationException from a NullPointerException.

I am using annotation based bean creation, from what I understand all needed is to annotate the class with @Service, @Repository, @Component or @Controller. I have tried scanning the packages and classes separately and combined, and am using @EnableJpaRepositories on the repository package.

The application:

package com.demoApp;


import com.demoApp.backend.DAOs.UserDAO;
import com.demoApp.backend.domain.User;
import com.demoApp.backend.services.Services;
import com.demoApp.ui.views.MainView;
import com.demoApp.app.security.SecurityConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

/**
 * Spring boot web application initializer.
 */
@SpringBootApplication(scanBasePackageClasses = { SecurityConfiguration.class, MainView.class, admexFront.class,
        UserDAO.class, Services.class}, exclude = ErrorMvcAutoConfiguration.class,scanBasePackages = {"com.demoApp.backend.services"})
@EnableJpaRepositories(basePackages = {"com.demoApp.backend.DAOs"})
@EntityScan(basePackages = {"com.demoApp.backend.domain"})
public class admexFront extends SpringBootServletInitializer {

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

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(admexFront.class);
    }
}

And here is the Services helper class:

package com.demoApp.backend.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.web.context.annotation.SessionScope;

import java.io.Serializable;

@Service(value = "Services")
@SessionScope
public class Services implements Serializable {

    @Autowired
    private ApplicationContext applicationContext;

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public ContactService getContactService() {
        return applicationContext.getBean(ContactService.class);
    }

    public UserService getUserService() {
        return applicationContext.getBean(UserService.class);
    }
}

Here is the ContactView route in which the error occurs:

package com.demoApp.ui.views;

import com.demoApp.app.security.SecurityUtils;
import com.demoApp.backend.domain.Client;
import com.demoApp.backend.domain.Contact;
import com.demoApp.backend.domain.User;
import com.demoApp.backend.services.Services;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

@Tag("contact-view")
@Route(value = "contacts", layout = MenuBar.class)
public class ContactView extends Div {


    public static String NAME = "Contacts";
    public static String ROUTE = "contacts";
    public static String ICON = "arrow-right";

    private VerticalLayout mainLayout = new VerticalLayout();

    @Autowired
    private Services services;

    @Autowired
    public ContactView() {
        User loggedInUser = SecurityUtils.getUser();

        Contact userContact = loggedInUser.getContactRef();
        Client client = userContact.getClientRef();


        mainLayout.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.AUTO);
        add(mainLayout);


        List<Contact> contacts = services.getContactService().getAllContactsFromClient(client);

        Grid<Contact> contactGrid = new Grid<>(Contact.class);
        contactGrid.setColumns("Contact Code", "Name", "Email");

        add(contactGrid);

    }
}

The error message I get is:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.demoApp.ui.views.ContactView': Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [co
m.demoApp.ui.views.ContactView]: Constructor threw exception; nested exception is java.lang.NullPointerException

JohVi784
  • 3
  • 3
  • 1
    Since the exception is thrown in your `ContactView`, you should probably include that. Without seeing that, my guess would be that you use field injection but try to access the autowired field in the constructor. Please try using [constructor injection](https://stackoverflow.com/questions/40737720/constructor-injection-vs-field-injection) instead and tell me how that went. – kscherrer Jun 12 '19 at 15:03
  • I agree with @kaspar since the error is from ContactView, can't identify without seeing this file. issue with constructor – Parthiban Manickam Jun 12 '19 at 15:21
  • Thanks, added the `ContactView` class as well – JohVi784 Jun 12 '19 at 18:30
  • There are many things wrong with this design. I suggest you understand the Model View Controller pattern. Also understand what Dependency Injection is and how Spring can be used for it. – MarkOfHall Jun 12 '19 at 18:51
  • Another thanks @Kaspar - it did solve the issue – JohVi784 Jun 12 '19 at 19:04

1 Answers1

1

Put yourself in Spring's shoes. It has to contruct a ContactView, and populate its services field.

To be able to populate the field of the object, the object needs to exist, right? So it has to call the constructor to construct the object, before being able to set its field. So, when the constructor is called, the field can't possibly be populated yet, and is thus null. Hence the NullPointerException, since you call a method on the field inside the constructor.

Solution: don't use field injection. Use constructor injection.

// NO @Autowired here
private Services services;

@Autowired // this is actually optional unless you have another constructor
public ContactView(Services services) {
    this.services = services;
    // ...
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255