How can I enable CDI with Jersey Test Framework?
Asked Answered
R

1

4

I found How can I inject a data source dependency into a RESTful web service with Jersey (Test Framework)? but I think I'm gonna ask a little bit different question.

This is a follow-up question of @PostConstruct of abstract ancestors are not invoked

I wrote a JAX-RS library and I'm trying to unit-test with Jersey Test Framework.

I seems HK2 injects properly. But I found some of my life cycle interceptor method annotated with @PostConstruct or @PreDestroy aren't invoked (or only some invoked).

public class MyResource {

    @PostConstruct
    private void constructed() { // not invoked
    }

    @Inject
    private Some some; // injection works.
}

How can I enable CDI with Jersey Test Framework? What kind of artifacts do I have to depend on?

Here is my current dependencies.

<dependency>
  <groupId>javax.inject</groupId>
  <artifactId>javax.inject</artifactId>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>javax.ws.rs</groupId>
  <artifactId>javax.ws.rs-api</artifactId>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>org.glassfish.jersey.test-framework.providers</groupId>
  <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
  <scope>test</scope>
</dependency>
Rigorous answered 23/4, 2015 at 9:13 Comment(0)
R
4

I found a solution.

I added following additional dependencies.

<dependency>
  <groupId>org.glassfish.jersey.ext.cdi</groupId>
  <artifactId>jersey-cdi1x</artifactId>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.glassfish.jersey.ext.cdi</groupId>
  <artifactId>jersey-weld2-se</artifactId>
  <scope>test</scope>
</dependency>

Now Weld takes over HK2, I think. I don't know what jersey-cdi1x-ban-custom-hk2-binding is for. Anyway, I can use standard annotations from javax.enterprise:cdi-api.

public class MyProducer {

    @Produces @Some
    public MyType produceSome() {}

    public void disposeSome(@Disposes @Some MyType instance) {}
}

And an initialisation code for Weld added.

@Override
protected Application configure() {

    // this method works somewhat weirdly.
    // local variables including logger
    // is null in here
    // I have to start (and join) a thread
    // which initializes Weld and adds a shutdown hook

    final Thread thread = new Thread(() -> {
        final Weld weld = new Weld();
        weld.initialize();
        Runtime.getRuntime().addShutdownHook(
            new Thread(() -> weld.shutdown()));
    });
    thread.start();
    try {
        thread.join();
    } catch (final InterruptedException ie) {
        throw new RuntimeException(ie);
    }

    final ResourceConfig resourceConfig
        = new ResourceConfig(MyResource.class);

    resourceConfig.register(MyProducer.class);

    return resourceConfig;
}

Every points get injected and all lifecycle methods are invoked. Yay!!!


I don't understand why I tried to use a thread in the first place.

@Override
protected Application configure() {

    final Weld weld = new Weld();
    weld.initialize();
    Runtime.getRuntime().addShutdownHook(new Thread(() -> weld.shutdown()));

    final ResourceConfig resourceConfig
        = new ResourceConfig(MyResource.class);

    resourceConfig.register(MyProducer.class);

    return resourceConfig;
}

Since I use JerseyTestNg.ContainerPerClassTest I failed, at least with TestNG, to work with @BeforeClass and @AfterClass because configure() method is invoked (indirectly) from the constructor.

I think I can use @BeforeMethod and @AfterMethod for initializing/shutting-down Weld if I switch to JerseyTestNg.ContainerPerMethodTest.


jersey-cdi1x is a transitive dependency of the jersey-weld2-se so it can be omitted.

Rigorous answered 23/4, 2015 at 14:34 Comment(4)
Just curious, have you simply tried @BeforeClass and @AfterClass annotated methods to initialize and shutdown weld? Since this is a test class, it seems appropriateMoeller
@peeskillet I found configure() is, apparently, invoked indirectly from the constructor of JerseyTest class. That's why event logger is not useable in that method.Rigorous
What I meant is that JUnit tests offer the @BeforeClass and @AfterClass annotations that you can place on arbitrary static methods in your test class. The former will be called before the tests start and the latter after. Instead of the threading, I was simply wondering if it would work to have a static Weld field, start it in the before method, and shut it down in the after method.Moeller
@peeskillet I, unfortunately, use TestNG. I tried using static field and org.testng.annotations.BeforeClass. And it seems even @BeforeClass applies after instantiation. I'm not sure JUnit works differently.Rigorous

© 2022 - 2024 — McMap. All rights reserved.