关于Java:通过Jersey / Grizzly运行测试时,如何以及谁应该注入PersistenceContext?

How and who should inject PersistenceContext when running tests through Jersey/Grizzly?

我有这个课程(JAX-RS / Jersey和JPA / Hibernate的混合):

1
2
3
4
5
6
7
8
9
public class Factory {
  @PersistenceContext(unitName ="abc")
  EntityManager em;
  @Path("/{id}")
  @GET
  public String read(@PathParam("id") int i) {
    return em.find(Employee.class, i).getName();
  }
}

这是单元测试:

1
2
3
4
5
6
7
8
9
10
public class FactoryTest extends JerseyTest {
  public FactoryTest() throws Exception {
    super("com.XXX");
  }
  @Test
  public void testReadingWorks() {
    String name = resource().path("/1").get(String.class);
    assert(name.length() > 0);
  }
}

在这里一切都很好,除了以下一项:read()中的emNULL。看起来Grizzly(我将此服务器与Jersey Test Framework一起使用)没有注入PersistenceContext。我在这里做错什么了吗?


Everything is fine here except one this: em is NULL inside read(). Looks like Grizzly (I'm using this server together with Jersey Test Framework) is not injecting PersistenceContext. What am I doing wrong here?

  • 我不确定Grizzly是否会打针。
  • 我不确定"任何" Jersey资源中是否支持注入(Paul Sandoz似乎暗示它应该在此线程中,但是我找不到该主张的明确证据)。
  • 据我所知,最简单的解决方案是将EntityManager注入到EJB 3.1无状态会话Bean(SLSB)中,该Bean可以直接作为REST资源公开(通过使用JAX-RS注释对其进行注释)。

    另一个选择是使JAX-RS资源成为托管bean,并使用CDI进行注入。这就是TOTD#124的方法:将CDI JPA与JAX-RS和JAX-WS一起使用。

    在两种情况下,我认为您都需要使用Embedded GlassFish容器作为Jersey测试的容器。

    资源

    • 泽西测试框架使一切变得简单!
    • 重新访问Jersey测试框架!
    • 带有JavaScript和... EJB 3.1的RESTFul计算器
    • TOTD#124:将CDI JPA与JAX-RS和JAX-WS结合使用


    我找到了com.sun.jersey / jersey-grizzly2版本1.x的解决方案。我实现了一个自定义的InjectableProvider。以下代码摘自Oracle文章:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    import javax.ejb.EJB;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import javax.ws.rs.ext.Provider;

    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;

    @Provider
    public class EJBProvider implements InjectableProvider<EJB, Type> {

        public Scope getScope() {
            return Scope.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(HttpContext c) {
                        return o;
                    }                    
                };            
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    }

    我必须对其稍作调整以适合我的环境。还请注意,提供程序必须与您的服务类位于同一程序包中,否则它将不会被提取(在文章中没有说明)。