NullPointerException异常时试图访问JPA服务类
我有下面的托管beanNullPointerException异常时试图访问JPA服务类
@ManagedBean
@RequestScoped
public class customerBean {
private Customer customer;
private CustomerJpaController customerJpa;
@PostConstruct
public void init() {
customer = new Customer();
}
public String addCustomer() throws Exception {
customerJpa.create(customer);
return "customer";
}
// getter and setter
}
的CustomerJpaController
看上去象下面这样:
public class CustomerJpaController implements Serializable {
@PersistenceContext(unitName = "JFSCustomerPU")
private EntityManagerFactory emf = null;
private UserTransaction utx = null;
public CustomerJpaController(UserTransaction utx, EntityManagerFactory emf) {
this.utx = utx;
this.emf = emf;
}
// ...
}
当addCustomer()
从视图中调用,它抛出java.lang.NullPointerException
在行customerJpa.create(customer);
。这是如何造成的,我该如何解决这个问题?
这是我对事物的认识(它可能不是100%正确的,但它会给你一个总体思路):
凡在你的bean是您的服务实例?无处。换句话说,customerJpa
为空。 启动与db的连接会加重资源。因此,不是你自己实例化不同的服务,而是打开关闭连接,容器拥有一个服务池,并为所有需要它的人提供免费服务(在你的情况下,你的bean需要一个服务)。您怎么要求容器给你一个服务:
注释@EJB
服务上面:
@EJB
private CustomerJpaController customerJpa;
,我认为你缺少@Stateless以及
@Stateless
public class CustomerJpaController...
这是建议切换到@Named
和@RequestScoped
(另一个包),而不是@ManagedBean
。然后,您可以使用@Inject
来注入您的服务,而不是@EJB
。 here you can read further on the subject.
在您的代码示例中,您的CustomerJpaController从未实例化过。所以,你会得到一个空指针异常。
我建议您切换到CDI并依靠其注入方法让实体管理器(工厂?)正确实例化,并在最后一次实例化时将其注入控制器。所以,要使用@Named而不是@ManagedBean。
所以,你会:
@Named
@RequestScoped
public class CustomerJpaController implements Serializable {
...
}
(或任何范围更符合您的需要)
在我看来,你应该使用一个EntityManager(EM),而不是EntityManagerFactory的(EMF)在你的控制器中。
如果EMF是容器管理,您只有一个持久性单元,您可以使用标准的JPA @PersistenceContext
注释:
@PersistenceContext
private EntityManager entityManager;
如果EMF没有被管理,您可以利用的deltaspike JPA module功率(记:deltaspike是对你有好处:-)),并在控制器中注入EntityManager:
@Named
@RequestScoped
public class CustomerJpaController implements Serializable {
@Inject
private EntityManager em;
}
这需要EntityManagerProducer类的实现,它可以有任何名称,但必须有一个方法注释@Produces @RequestScoped
返回一个EntityManager,另一个采用用@Disposes注解的EntityManager参数。例如:
public class MyEntityManagerProducer {
@Inject
@PersistenceUnitName("myPU")
private EntityManagerFactory emf;
@Produces
@RequestScoped
public EntityManager createEntityManager() {
return emf.createEntityManager();
}
public void disposeEntityManager(@Disposes em) {
if (em.isOpen()) {
em.close();
}
}
注@PersistenceUnitName( “myPU”)的使用,该deltaspike注释将处理EMF的instanciation。
如果您有多个持久性单元,因为在现实世界中经常出现这种情况,您可以使用限定符将它们分开。要声明一个限定词,声明@interface
与以下注释:
@Target({ FIELD, METHOD, PARAMETER, TYPE })
@Retention(RUNTIME)
@Documented
@Qualifier
public @interface MyQualifier {
}
然后,这个限定词添加到所有@Produces,@Disposes和@Inject,允许CDI来决定哪个持久化单元/实体管理你愿意使用方法:
public class MyEntityManagerProducer {
@Inject
@PersistenceUnitName("myPU")
private EntityManagerFactory emf;
@Produces
@MyQualifier
@RequestScoped
public EntityManager createEntityManager() {
return emf.createEntityManager();
}
public void disposeEntityManager(@Disposes @MyQualifier em) {
if (em.isOpen()) {
em.close();
}
}
和控制器:
@Named
@RequestScoped
public class CustomerJpaController implements Serializable {
@Inject
@MyQualifier
private EntityManager em;
}
所有这些都需要CDI。配置CDI不仅仅是对你的问题的简短回答。我所有的项目中都有我的use OpenWebBeans。 Weld也很受欢迎。
你必须@ @注入这个JPA或创建它的某个实例,因为变量'customerJpa'为null,你不需要初始化它。 – Geinmachi