我正在尝试通过注释将无状态EJB 注入我的JAX-RS Web服务。不幸的是,EJB只是null
,当我尝试使用它时,我得到NullPointerException
。
@Path("book")
public class BookResource {
@EJB
private BookEJB bookEJB;
public BookResource() {
}
@GET
@Produces("application/xml")
@Path("/{bookId}")
public Book getBookById(@PathParam("bookId") Integer id)
{
return bookEJB.findById(id);
}
}
我做错了什么?
以下是有关我的机器的一些信息:
你们能展示一些有效的例子吗?
答案 0 :(得分:109)
我不确定这应该有效。所以:
选项1:使用注射提供者SPI
实现将执行查找并注入EJB的提供程序。参见:
com.sun.jersey的示例:jersey-server:1.17:
import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.core.spi.component.ComponentScope;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;
import javax.ejb.EJB;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.ws.rs.ext.Provider;
import java.lang.reflect.Type;
/**
* JAX-RS EJB Injection provider.
*/
@Provider
public class EJBProvider implements InjectableProvider<EJB, Type> {
public ComponentScope getScope() {
return ComponentScope.Singleton;
}
public Injectable getInjectable(ComponentContext cc, EJB ejb, Type t) {
if (!(t instanceof Class)) return null;
try {
Class c = (Class)t;
Context ic = new InitialContext();
final Object o = ic.lookup(c.getName());
return new Injectable<Object>() {
public Object getValue() {
return o;
}
};
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
选项2:将BookResource设为EJB
@Stateless
@Path("book")
public class BookResource {
@EJB
private BookEJB bookEJB;
//...
}
请参阅:
选项3:使用CDI
@Path("book")
@RequestScoped
public class BookResource {
@Inject
private BookEJB bookEJB;
//...
}
请参阅:
答案 1 :(得分:13)
这个线程相当陈旧,不过我昨天也遇到了同样的问题。这是我的解决方案:
只需在课程级别通过@javax.annotation.ManagedBean将BookResource设置为托管bean。
为此,您需要使用beans.xml启用CDI:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>
如果BookResource是war文件的一部分,则此文件必须位于WEB-INF中。如果BookResource与ejbs一起打包,则将其放入META-INF。
如果你想使用@EJB,你就完成了。如果你想通过@Inject注入EJB,那么bean.xml也必须放入ejbs jar文件到META-INF中。
您正在做什么:您只是告诉容器资源应该是容器管理的。因此,它支持注入和生命周期事件。因此,您可以拥有自己的业务外观,而无需将其提升为EJB。
您无需为此扩展javax.ws.rs.core.Application。 BookResource是一个自动请求作用域的根资源。
使用Glassfish 3.1.2和maven项目进行测试。
快乐的编码。
答案 2 :(得分:10)
您应该能够在JAX-RS资源中进行注入,而无需使用EJB或CDI组件。但是你必须记住你的JAX-RS资源不能是单例。
因此,您使用此代码设置应用程序。这使得 BookResource 类每个请求 JAX-RS资源。
@javax.ws.rs.ApplicationPath("application")
public class InjectionApplication extends javax.ws.rs.core.Application {
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> classes = new HashSet<Class<?>>();
public InjectionApplication() {
// no instance is created, just class is listed
classes.add(BookResource.class);
}
@Override
public Set<Class<?>> getClasses() {
return classes;
}
@Override
public Set<Object> getSingletons() {
return singletons;
}
}
通过此设置,您可以让JAX-RS基于每个请求为您实例化 BookResource ,并且还会注入所有必需的依赖项。如果您使用 BookResource 类 singleton JAX-RS资源,那么您可以输入 getSingletons
public Set<Object> getSingletons() {
singletons.add(new BookResource());
return singletons;
}
然后,您创建了一个不受JAX-RS运行时管理的实例,并且容器中没有人关心注入任何内容。
答案 3 :(得分:5)
不幸的是,我的回答太长,无法发表评论,所以这里有。 :)
Zeck,我希望您通过将您的bean推广到EJB来了解您正在做什么,正如Pascal所建议的那样。不幸的是,就像现在使用Java EE“将类创建为EJB”一样简单,您应该意识到这样做的含义。每个EJB都会产生开销以及它提供的附加功能:它们具有事务感知能力,具有自己的上下文,它们参与完整的EJB生命周期等等。
我认为您应该采取干净且可重复使用的方法:将服务器服务(希望通过SessionFacade :)访问的服务提取到BusinessDelegate。这个委托应该使用某种JNDI查找(可能是ServiceLocator - 是的,它们在Java EE中仍然有效!)来访问你的后端。
好的,关闭记录:如果你真的,真的,真的需要注入,因为你不想手动编写JNDI访问,你仍然可以让你的委托成为EJB,尽管它......嗯,这只是感觉不对。 :) 这样,如果您决定切换到JNDI查找方法,至少可以很容易地用其他东西替换它......
答案 4 :(得分:3)
我试图做同样的事情。我正在使用EJB 3.1并将我的应用程序部署为具有单独EJB项目的EAR。正如Jav_Rock指出的那样,我使用了上下文查找。
@Path("book")
public class BookResource {
@EJB
BookEJB bookEJB;
public BookResource() {
try {
String lookupName = "java:global/my_app/my_ejb_module/BookEJB";
bookEJB = (BookEJB) InitialContext.doLookup(lookupName);
} catch (NamingException e) {
e.printStackTrace();
}
}
@GET
@Produces("application/xml")
@Path("/{bookId}")
public Book getBookById(@PathParam("bookId") Integer id) {
return bookEJB.findById(id);
}
}
请参阅以下链接,了解非常有用的JNDI查找提示
答案 5 :(得分:1)
Arjan是对的。我创建了另一个类来初始化EJB,而不是为RS创建一个bean
@Singleton
@LocalBean
public class Mediator {
@EJB
DatabaseInterface databaseFacade;
避免空指针:
@Path("stock")
public class StockResource {
@EJB
DatabaseInterface databaseFacade;
...
它实际上适用于GF
答案 6 :(得分:0)
我有同样的问题,我解决了它通过上下文查询调用te EJB(注入是不可能的,我有相同的错误NullPointerException)。