2017-06-15 2 views
0

これは私の最初のSpringアプリケーションですので、私の無知を許してください。`@ Autowired`依存の` NullPoinerException`

@Autowiredに依存しています。

14:08:48,415 SEVERE [com.vaadin.server.DefaultErrorHandler] (default task-4) : java.lang.NullPointerException 
at com.letifer.ui.factory.BudgetTabbedPaneFactory$BudgetTabbedPane.init(BudgetTabbedPaneFactory.java:26) 
at com.letifer.ui.factory.BudgetTabbedPaneFactory.createComponent(BudgetTabbedPaneFactory.java:44) 
at com.letifer.ui.commons.BudgetMainUI.init(BudgetMainUI.java:44) 

BudgetTabbedPaneFactory.java:

package com.letifer.ui.factory; 

import org.springframework.beans.factory.annotation.Autowired; 

import com.vaadin.spring.annotation.SpringComponent; 
import com.vaadin.ui.Alignment; 
import com.vaadin.ui.Component; 
import com.vaadin.ui.HorizontalLayout; 

@SpringComponent 
public class BudgetAccountsFactory implements BudgetComponent { 

    @Autowired 
    private BudgetAccountMenuFactory accountMenuFactory; 

    @Autowired 
    private BudgetInfoPaneFactory infoPaneFactory; 

    private class BudgetAccountsLayout extends HorizontalLayout { 

     Component menu; 
     Component infoPane; 

     public BudgetAccountsLayout init() { 

      menu = accountMenuFactory.createComponent(); 
      infoPane = infoPaneFactory.createComponent(); 

      return this; 
     } 

     public BudgetAccountsLayout layout() { 

      setMargin(true); 
      setSizeFull(); 

      addComponent(menu); 
      setComponentAlignment(menu, Alignment.TOP_LEFT); 
      setExpandRatio(menu, 1); 

      addComponent(infoPane); 
      setComponentAlignment(infoPane, Alignment.TOP_LEFT); 
      setExpandRatio(infoPane, 2); 

      return this; 
     } 

    } 

    public Component createComponent() { 
     return new BudgetAccountsLayout().init().layout(); 
    } 

} 

このCLAS:

package com.letifer.ui.factory; 

import org.springframework.beans.factory.annotation.Autowired; 

import com.letifer.utils.constants.BudgetStringConstants; 
import com.vaadin.spring.annotation.SpringComponent; 
import com.vaadin.ui.Component; 
import com.vaadin.ui.Label; 
import com.vaadin.ui.TabSheet; 
import com.vaadin.ui.VerticalLayout; 

@SpringComponent 
public class BudgetTabbedPaneFactory implements BudgetComponent { 

    private class BudgetTabbedPane extends VerticalLayout { 

     private TabSheet tabSheet; 

     @Autowired 
     BudgetAccountsFactory accountsFactory; 

     Component accounts; 

     public BudgetTabbedPane init() { 
      tabSheet = new TabSheet(); 
      accounts = accountsFactory.createComponent(); // <-- NullPoinerException 
      return this; 
     } 

     public BudgetTabbedPane layout() { 
      setSizeFull(); 
      tabSheet.addTab(accounts, BudgetStringConstants.ACCOUNTS_TAB_NAME.getName()); 
      tabSheet.addTab(new Label(BudgetStringConstants.BALANCE_TAB_NAME.getName()), BudgetStringConstants.BALANCE_TAB_NAME.getName()); 
      tabSheet.addTab(new Label(BudgetStringConstants.STATISTICS_TAB_NAME.getName()), BudgetStringConstants.STATISTICS_TAB_NAME.getName()); 

      addComponent(tabSheet); 

      return this; 
     } 

    } 

    public Component createComponent() { 
     return new BudgetTabbedPane().init().layout(); 
    } 

} 

このクラスはBudgetAccountsFactory依存

BudgetAccountsFactory.javaを持っていますsが別の2つの依存性を持ち、BudgetAccountMenuFactoryBudgetInfoPaneFactory

BudgetAccountMenuFactory.java:

package com.letifer.ui.factory; 

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.HashSet; 
import java.util.List; 
import java.util.Set; 

import com.letifer.utils.constants.BudgetStringConstants; 
import com.vaadin.spring.annotation.SpringComponent; 
import com.vaadin.ui.Component; 
import com.vaadin.ui.ListSelect; 
import com.vaadin.ui.VerticalLayout; 

@SpringComponent 
public class BudgetAccountMenuFactory implements BudgetComponent { 

    private class BudgetAccountMenuLayout extends VerticalLayout { 

     private ListSelect<String> options; 

     public BudgetAccountMenuLayout init() { 
      options = new ListSelect<String>(BudgetStringConstants.ACCOUNTS_MENU_OPTION_TITLE.getName()); 
      List<String> optionsList = new ArrayList<String>(Arrays.asList(BudgetStringConstants.ACCOUNTS_MENU_OPTION_SHOW_ACCOUNTS.getName(), 
        BudgetStringConstants.ACCOUNTS_MENU_OPTION_ADD.getName(), BudgetStringConstants.ACCOUNTS_MENU_OPTION_REMOVE.getName())); 
      Set<String> optionsSet = new HashSet<String>(optionsList); 
      options.setValue(optionsSet); 
      return this; 
     } 

     public BudgetAccountMenuLayout layout() { 
      setMargin(true); 
      setSizeFull(); 

      addComponent(options); 
      return this; 
     } 

    } 

    public Component createComponent() { 
     return new BudgetAccountMenuLayout().init().layout(); 
    } 

} 

BudgetInfoPaneFactory.java:

package com.letifer.ui.factory; 

import com.vaadin.spring.annotation.SpringComponent; 
import com.vaadin.ui.Component; 
import com.vaadin.ui.Label; 
import com.vaadin.ui.VerticalLayout; 

@SpringComponent 
public class BudgetInfoPaneFactory implements BudgetComponent { 

    private class BudgetInfoPaneLayout extends VerticalLayout { 

     public static final String VIEW_NAME = "info"; 

     private Label label; 

     public BudgetInfoPaneLayout init() { 
      label = new Label("INFO HERE"); 
      return this; 
     } 

     public BudgetInfoPaneLayout layout() { 
      setMargin(true); 
      setSizeFull(); 
      addComponent(label); 
      return this; 
     } 

    } 

    public Component createComponent() { 
     return new BudgetInfoPaneLayout().init().layout(); 
    } 

} 

私の無知は、 "ネストされた" という依存関係を信じるように私を導きました(@Autowiredコンポーネント内の@Autowiredコンポーネント内のコンポーネント)はju大丈夫です。

しかし、明らかに私はNullPoinerExceptionをトップコンポーネントに取得します。

私はここで何が欠けていますか?

「依存関係内に依存関係を挿入する」インテリジェントな方法は何ですか?

+0

ここで 'new BudgetInfoPaneLayout()'のように 'new'を使ってオブジェクトを作成すると、そのオブジェクトには注入されたオブジェクトやプロパティのようなSpringの管理コンテンツがなくなり、nullになります。新しいオブジェクトを作成するのではなく、それらをクラスに注入するだけです。 – csmckelvey

+0

@csm_devこれは質問に対する答えです。 – solomkinmv

+0

@csm_dev私の前提は、内部クラスと他の依存関係が同じ 'builder-pattern'を使って' Spring'によって管理される必要はないということでした。しかし、 "ネストされた依存関係"は何も問題なく注入されません。 –

答えて

2

さて、Springの依存性注入が何であるかを明確にする必要があると思います。

  1. アノテーション@SpringComponent@Controllerを持つクラスをマークし、@Repositoryなど春は自動的にこのクラスのインスタンスを作成します。しかし、これはBudgetTabbedPaneFactoryではなく、BudgetTabbedPaneFactoryの動的に生成されるサブクラス(いわゆるProxy)になります。
  2. 注釈を付けた後、すべての注釈付きコンポーネントがSpringで表示されます。それらはSpring contextにあり、managed beansになります。
  3. 次に、@Autowiredとマークされたすべてのメソッドとフィールドをチェックし、前のステージから自動的に作成されたオブジェクトの適切なインスタンスを使用して初期化しようとします。

しかし、手動でオブジェクトを作成すると、それはSpring contextの外に存在し、Springはそのオブジェクトとその注釈を気にしません。実際にあなたのクラスについては全く分かりません。 Annotationsは、それ自体が機能を実行しないマーカーの一種です。

Spring IoC containerをお読みください。たぶんそれはあなたの仕事に最適なソリューションを見つけるのに役立ちます。

P.S.あなたの状況では、少なくとも@SpringComponentの注釈をBudgetTabbedPane以上にするべきです(内側のクラスで動作するかどうかはわかりません)。これはSpring Beanではないため、Springを手動で作成しないようにしてください。

+0

内部クラスにアノテーションを付けて問題を解決しました... 私はコンセプトを理解していますが、コードの 'new VerticalLayout()'にはまだ 'new'型のコンポーネントの作成があり、動作しますどうして? –

+0

そのクラスには、内部にスプリング管理コンポーネントがないためです。 – csmckelvey

+0

はい、@ csm_devが正しいです。言い換えれば、クラス内にSpringアノテーションがある場合( '@ Autowired'、' @ SpringComponent')、それはSpringによってインスタンス化されなければなりません。 'BudgetAccountMenuLayout'や' BudgetInfoPaneLayout'にいくつかの '@ Autowired'プロパティを追加し、' init() 'でそれにアクセスしてみてください。 'NullPointerException'も取得します。 – invenit

関連する問題