如何在符合 SonarQube 规则 S3306 的 CDI 托管 bean 中使用 @Inject
How to use @Inject in CDI managed beans compliant with SonarQube rule S3306
我正在使用 CDI 开发一个 JSF 项目。我们使用 SonarQube 来管理代码质量。 运行 扫描我们的项目后弹出的问题之一是 S3306:“Constructor injection should be used instead of field injection”。
它是由我们在 bean 中使用的注入触发的,例如:
@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。我不确定之前的 link(Oracle 文档)是否适用于此。
编辑 2:我刚刚在阅读 WELD injection points 上的文档后尝试了建议的解决方案。但这给了我这个错误:
WELD-001435: Normal scoped bean class ...AccountsController is not proxyable because it has no no-args constructor
编辑 3:编辑 2 中的错误确实(请参阅问题的评论)是由另一个 AccountsController
的 @Inject
引起的控制器。另见答案。
建议的解决方案确实适用于使用 Payara 4.1.1 163 将 @Stateless
类 注入 CDI bean。不过我在使用 GlassFish 4.1 时遇到了问题。
此外,当您将 bean 注入其他 bean 时应用此解决方案,例如:
@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
N.B。 AccountsController
已按建议修改。
我使用 OmniFaces 解决了这个问题 Beans
:
@Named
@ViewScoped
public class OtherController extends AbstractController<Other> {
private final AccountsController accountsController;
public OtherController() {
this.accountsController = Beans.getInstance(AccountsController.class);
}
}
...或者,对于完全不同的东西,您也可以只抑制 (CDI) 托管 bean 上的警告:
@SuppressWarnings("squid:S3306")
我正在使用 CDI 开发一个 JSF 项目。我们使用 SonarQube 来管理代码质量。 运行 扫描我们的项目后弹出的问题之一是 S3306:“Constructor injection should be used instead of field injection”。
它是由我们在 bean 中使用的注入触发的,例如:
@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 areprivate
. 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。我不确定之前的 link(Oracle 文档)是否适用于此。
编辑 2:我刚刚在阅读 WELD injection points 上的文档后尝试了建议的解决方案。但这给了我这个错误:
WELD-001435: Normal scoped bean class ...AccountsController is not proxyable because it has no no-args constructor
编辑 3:编辑 2 中的错误确实(请参阅问题的评论)是由另一个 AccountsController
的 @Inject
引起的控制器。另见答案。
建议的解决方案确实适用于使用 Payara 4.1.1 163 将 @Stateless
类 注入 CDI bean。不过我在使用 GlassFish 4.1 时遇到了问题。
此外,当您将 bean 注入其他 bean 时应用此解决方案,例如:
@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
N.B。 AccountsController
已按建议修改。
我使用 OmniFaces 解决了这个问题 Beans
:
@Named
@ViewScoped
public class OtherController extends AbstractController<Other> {
private final AccountsController accountsController;
public OtherController() {
this.accountsController = Beans.getInstance(AccountsController.class);
}
}
...或者,对于完全不同的东西,您也可以只抑制 (CDI) 托管 bean 上的警告:
@SuppressWarnings("squid:S3306")