2016-11-24 1 views
2

Я работаю над проектом JSF с использованием CDI. Мы используем SonarQube для управления качеством кода. Одной из проблем, возникших после сканирования в нашем проекте, является S3306: «Constructor injection should be used instead of field injection».Как использовать @Inject в управляемых битах CDI, соответствующих правилу SonarQube S3306

Это было вызвано впрыскивает, которые мы используем в наших бобах, например:

@Named 
@ViewScoped 
public class AccountsController extends AbstractController<Account> { 

    @Inject 
    private AccountsFacade accountsFacade; 

    public AccountsController() { 
    super(Account.class); 
    } 

    ... 
} 

Введенный являются фасадами, как:

@Stateless 
public class AccountsFacade extends AbstractFacade<Account> { 

    @PersistenceContext(unitName = "...") 
    private EntityManager entityManager; 

    public AccountsFacade() { 
    super(Account.class); 
    } 

    ... 
} 

Информационных по данному вопросу, предоставленный SonarQube:

Field injection seems like a tidy way to get your classes what they need to do their jobs, but it's really a NullPointerException waiting to happen unless all your class constructors are private . That's because any class instances that are constructed by callers, rather than instantiated by the Spring framework, won't have the ability to perform the field injection.

Instead @Inject should be moved to the constructor and the fields required as constructor parameters.

This rule raises an issue when classes with non- private constructors (including the default constructor) use field injection.

Предлагаемое решение:

class MyComponent { 

    private final MyCollaborator collaborator; 

    @Inject 
    public MyComponent(MyCollaborator collaborator) { 
    Assert.notNull(collaborator, "MyCollaborator must not be null!"); 
    this.collaborator = collaborator; 
    } 

    public void myBusinessMethod() { 
    collaborator.doSomething(); 
    } 
} 

С managed beans are created using a constructor with no arguments, существует ли какой-либо способ соблюдения правила SonarQube?

Редактировать: Я считаю это актуальным: мы используем CDI. Я не уверен, что здесь применяется предыдущая ссылка (документация Oracle).

Редактировать 2: Я просто попробовал предлагаемое решение после того, как прочитал документацию по адресу WELD injection points. Но это дает мне эту ошибку:

WELD-001435: Normal scoped bean class ...AccountsController is not proxyable because it has no no-args constructor

Редактировать 3: Ошибка редактирования 2 действительно (см комментарии на вопрос), вызванные @Inject из AccountsController в другой контроллер. См. Также ответ.

+0

Вы уверены, что это должно быть '@Inject общественного MyComponent (MyCollaborator сотрудник) {...}' и 'не общественное MyComponent (@Inject MyCollaborator соавтор) {...} '? См. Также http://stackoverflow.com/questions/19381846/why-use-constructor-over-setter-injection-in-cdi – Kukeltje

+0

Хмммм ... противоречивая информация ... (никогда не использовалась конструкция конструктора) ... – Kukeltje

+1

Ваш пример кажется действительно правильным ... Странно и btw ... 'Spring framework' в документах sonarcube? Hmmmm Может быть, переопределить правило sonarcube ;-) – Kukeltje

ответ

1

Предлагаемое решение действительно для инъекций @Stateless классов в CDI beans с Payara 4.1.1 163. Однако у меня возникли проблемы с GlassFish 4.1.

Кроме того, при применении этого раствора при введении бобы в другие бобы, как:

@Named 
@ViewScoped 
public class OtherController extends AbstractController<Other> { 

    private final AccountsController accountsController; 

    @Inject 
    public OtherController(AccountsController accountsController) { 
    Assert.notNull(accountsController, "accountsController must not be null!"); 
    this.accountsController = accountsController; 
    } 

} 

.. вы получите эту ошибку (как указано в редактировании 2 вопроса):

WELD-001435: Normal scoped bean class ...AccountsController is not proxyable because it has no no-args constructor

NB AccountsController был изменен, как было предложено.

Я решил эту проблему, используя OmniFaces Beans:

@Named 
@ViewScoped 
public class OtherController extends AbstractController<Other> { 

    private final AccountsController accountsController; 

    public OtherController() { 
    this.accountsController = Beans.getInstance(AccountsController.class); 
    } 

} 
+0

Это решение или «обходной путь»? – Kukeltje

+1

Я не эксперт CDI/WELD, но это похоже на проблему. В этой перспективе это обходное решение. В перспективе соблюдения S3306 это решение. –

Смежные вопросы