Как решить исключение NullPointerException при использовании компонента Autowiring в приложении spring-boot

При автоподключении компонента, в данном случае @Service, я получаю исключение BeanInstantiationException из исключения NullPointerException.

Я использую создание bean-компонентов на основе аннотаций, насколько я понимаю, все, что нужно, это аннотировать класс с помощью @Service, @Repository, @Component или @Controller. Я пробовал сканировать пакеты и классы по отдельности и вместе, и использую @EnableJpaRepositories в пакете репозитория.

Приложение:

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);
    }
}

А вот вспомогательный класс Services:

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);
    }
}

Вот маршрут ContactView, в котором возникает ошибка:

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);

    }
}

Сообщение об ошибке, которое я получаю:

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


person JohVi784    schedule 12.06.2019    source источник
comment
Поскольку исключение выдается в вашем ContactView, вам, вероятно, следует включить его. Не видя этого, я предполагаю, что вы используете внедрение поля, но пытаетесь получить доступ к автоматически связанному полю в конструкторе. Попробуйте вместо этого использовать внедрение конструктора и расскажите, как это было.   -  person kscherrer    schedule 12.06.2019
comment
Я согласен с @kaspar, так как ошибка связана с ContactView, я не могу определить, не видя этот файл. проблема с конструктором   -  person Parthiban Manickam    schedule 12.06.2019
comment
Спасибо, добавил класс ContactView   -  person JohVi784    schedule 12.06.2019
comment
В этом дизайне много чего не так. Я предлагаю вам понять шаблон контроллера представления модели. Также поймите, что такое внедрение зависимостей и как для этого можно использовать Spring.   -  person MarkOfHall    schedule 12.06.2019
comment
Еще одно спасибо @Kaspar - это решило проблему   -  person JohVi784    schedule 12.06.2019


Ответы (1)


Поставьте себя на место Весны. Он должен построить ContactView и заполнить его поле services.

Чтобы можно было заполнить поле объекта, объект должен существовать, верно? Таким образом, он должен вызвать конструктор для создания объекта, прежде чем сможет установить его поле. Таким образом, когда вызывается конструктор, поле еще не может быть заполнено и, следовательно, равно нулю. Следовательно, NullPointerException, поскольку вы вызываете метод для поля внутри конструктора.

Решение: не используйте инъекцию поля. Используйте внедрение конструктора.

// NO @Autowired here
private Services services;

@Autowired // this is actually optional unless you have another constructor
public ContactView(Services services) {
    this.services = services;
    // ...
person JB Nizet    schedule 12.06.2019
comment
Большое спасибо за объяснение - это решило это! - person JohVi784; 12.06.2019