【问题标题】:Vaadin + Spring = getting a nullpointer exceptionVaadin + Spring = 获取空指针异常
【发布时间】:2020-01-18 11:22:43
【问题描述】:

我正在使用 Vaadin 创建应用程序的前端。我正在尝试通过我的 ApiController 与我的后端进行通信,以便我可以从数据库中获取我的数据。

@RestController
@RequestMapping("/v1")
public class ApiController {
    @Autowired
    private ApiClient apiClient;

    @RequestMapping(method = RequestMethod.GET, value = "getDoctors")
    public void getAllDoctors() {
        List<DoctorDto> doctorsList = apiClient.getDoctors();
        doctorsList.forEach(doctorDto -> System.out.println(doctorDto.getName() + " " + doctorDto.getRating()));
    }
}

到目前为止,我只有一个带有几个选项卡的主页,其中一个是我想列出数据库中所有医生的地方。

主视图:

@org.springframework.stereotype.Component // <--- I already have an import regarding Vaddin's components
@Route("test")
public class MainView extends VerticalLayout {
    private DoctorsPage doctorsPage = new DoctorsPage(this);
    private Tab doctorsTab = new Tab("Our doctors");

    public MainView() {
        // stuff
    }
}

和DoctorsPage:

@Component
public class DoctorsPage extends VerticalLayout {
    @Autowired
    private ApiClient apiClient;  // <---- not autowiring
    private MainView mainView;

    public DoctorsPage(MainView mainView) {
        this.mainView = mainView;
        List<DoctorDto> list = apiClient.getDoctors();
    }
}

有趣的事实,如果我尝试使用浏览器并粘贴我的端点以获取此代码的医生列表

doctorsList.forEach(doctorDto -> System.out.println(doctorDto.getName() + " " + doctorDto.getRating()));

完美运行。但即使我试图在 MainView 类中自动装配我的 ApiClient,我仍然会收到一个空异常。

有日志:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'doctorsPage' defined in file [C:\Users\x\IdeaProjects\medical-clinic-frontend\build\classes\java\main\com\x\medicalclinicfrontend\gui\DoctorsPage.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mainView' defined in file [C:\Users\x\IdeaProjects\medical-clinic-frontend\build\classes\java\main\com\x\medicalclinicfrontend\gui\MainView.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.x.medicalclinicfrontend.gui.MainView]: Constructor threw exception; nested exception is java.lang.NullPointerException
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:798) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:228) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1358) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1204) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
    at com.x.medicalclinicfrontend.MedicalClinicFrontendApplication.main(MedicalClinicFrontendApplication.java:10) ~[main/:na]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mainView' defined in file [C:\Users\x\IdeaProjects\medical-clinic-frontend\build\classes\java\main\com\x\medicalclinicfrontend\gui\MainView.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.x.medicalclinicfrontend.gui.MainView]: Constructor threw exception; nested exception is java.lang.NullPointerException
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1320) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1287) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:885) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    ... 19 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.x.medicalclinicfrontend.gui.MainView]: Constructor threw exception; nested exception is java.lang.NullPointerException
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:213) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1312) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    ... 31 common frames omitted
Caused by: java.lang.NullPointerException: null
    at com.x.medicalclinicfrontend.gui.MainView.<init>(MainView.java:38) ~[main/:na]
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:na]
    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500) ~[na:na]
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481) ~[na:na]
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:200) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    ... 33 common frames omitted

【问题讨论】:

  • 注意 DoctorPage 的范围 - 它默认为带有 Spring 的单例。很可能您至少需要 UI 范围。

标签: spring nullpointerexception vaadin


【解决方案1】:

自动装配在使用 new 关键字创建的实例中不起作用。您的 DoctorsPage 必须改为 @Autowired 以允许 Spring 创建实例的实例,以便 Spring 可以将 bean 注入其字段。

我还看到您必须为类中的 @Component 注释使用完全限定名称。您可以改用由 Vaadin 的 Spring 集成定义的 @SpringComponent 别名来避免这种情况。

【讨论】:

  • 是的,但即使我使用 ApiClient 创建一个自动装配字段,调试器仍然显示它为空。不创建 DoctorsPage 的新实例也不起作用,因为它给了我一个空值,尽管不同的“由”引起
  • @yomi 如果您尝试了一些不起作用的方法,请编辑您的问题并添加新的见解。
  • 另外需要注意的是,字段自动装配是在构造函数之后进行的,所以在构造函数中自动装配的字段为空。您可以将 ApiClient 自动装配为构造函数参数而不是字段。
【解决方案2】:

悠米,

如果您要让 Spring 创建您的 DoctorsPage,请使用 @PostConstruct 注释添加另一个方法并在其中初始化组件。

@Component
public class DoctorsPage extends VerticalLayout {
    @Autowired
    private ApiClient apiClient;  
    private MainView mainView;

    public DoctorsPage(MainView mainView) { }

    @PostConstruct                               // <---- like this
    puvlic void init() {
        this.mainView = mainView;
        List<DoctorDto> list = apiClient.getDoctors();
    }
}

或者正如@Tatu Lund 所说,在构造函数中自动连接 apiClient。

斯图尔特。

【讨论】:

    【解决方案3】:

    答案归功于@Tatu Lund 和@Stainless Steel Rat

    所以就像你们说的,它应该在构造函数中自动装配:

    @org.springframework.stereotype.Component
    @Route("test")
    public class MainView extends VerticalLayout {
        private DoctorsPage doctorsPage;
    
        @Autowired
        public MainView (DoctorsPage doctorsPage) {
            this.doctorsPage = doctorsPage;
        }
    }
    
    @Component
    public class DoctorsPage extends VerticalLayout {
        private ApiClient apiClient;
    
        @Autowired
        public DoctorsPage(ApiClient apiClient) {
            this.apiClient = apiClient;
        }
    }
    

    我无法立即确认解决方案,因为我在这两个课程中做了很多事情,我花了一点时间才使它起作用,但这很重要,它起作用了:D

    再次感谢 @Tatu Lund@Stainless Steel Rat 以及其他人。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多