Skip to content

[CDI2] Add CDI2 integration #1626

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions cdi2/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
= Cucumber CDI 2

This module relies on CDI Standalone Edition (CDI SE) API to start/stop a CDI container
and customize it - adding steps. It looks up the beans/steps in CDI and if not available
it instantiates it as POJO with CDI injection support - unmanaged bean.

== Setup

To use it, it is important to provide your CDI SE implementation - likely Weld or Apache OpenWebBeans.

For Apache OpenWebBeans the dependency is:

[source,xml]
----
<dependency>
<groupId>org.apache.openwebbeans</groupId>
<artifactId>openwebbeans-se</artifactId>
<version>2.0.10</version>
<scope>test</scope>
</dependency>
----

And for Weld it is:

[source,xml]
----
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se-core</artifactId>
<version>3.1.1.Final</version>
<scope>test</scope>
</dependency>
----

To ensure the module is compatible with all implementations and future API version, it does not transitively bring the API.
If you don't know which one to use, you can import the following one but if you develop CDI code you should already have one provided:

[source,xml]
----
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>2.0</version>
</dependency>
----
64 changes: 64 additions & 0 deletions cdi2/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<properties>
<openwebbeans.version>2.0.10</openwebbeans.version>
</properties>

<parent>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-jvm</artifactId>
<version>4.4.0-SNAPSHOT</version>
</parent>

<artifactId>cucumber-cdi2</artifactId>
<packaging>jar</packaging>
<name>Cucumber-JVM: CDI 2</name>

<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-core</artifactId>
</dependency>

<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency> <!-- java 11 -->
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.apache.openwebbeans</groupId>
<artifactId>openwebbeans-impl</artifactId>
<version>${openwebbeans.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.openwebbeans</groupId>
<artifactId>openwebbeans-se</artifactId>
<version>${openwebbeans.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
67 changes: 67 additions & 0 deletions cdi2/src/main/java/cucumber/runtime/java/cdi2/Cdi2Factory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package cucumber.runtime.java.cdi2;

import io.cucumber.core.backend.ObjectFactory;

import javax.enterprise.inject.Instance;
import javax.enterprise.inject.se.SeContainer;
import javax.enterprise.inject.se.SeContainerInitializer;
import javax.enterprise.inject.spi.Unmanaged;
import java.util.HashMap;
import java.util.Map;

public class Cdi2Factory implements ObjectFactory {

protected SeContainerInitializer initializer;
protected SeContainer container;
private final Map<Class<?>, Unmanaged.UnmanagedInstance<?>> standaloneInstances = new HashMap<>();

@Override
public void start() {
container = getInitializer().initialize();
}

@Override
public void stop() {
if (container != null) {
container.close();
container = null;
initializer = null;
}
for (final Unmanaged.UnmanagedInstance<?> unmanaged : standaloneInstances.values()) {
unmanaged.preDestroy();
unmanaged.dispose();
}
standaloneInstances.clear();
}

@Override
public boolean addClass(final Class<?> clazz) {
getInitializer().addBeanClasses(clazz);
return true;
}

@Override
public <T> T getInstance(final Class<T> type) {
final Object instance = standaloneInstances.get(type);
if (instance != null) {
return type.cast(instance);
}
final Instance<T> selected = container.select(type);
if (selected.isUnsatisfied()) {
final Unmanaged.UnmanagedInstance<T> value = new Unmanaged<>(container.getBeanManager(), type).newInstance();
value.produce();
value.inject();
value.postConstruct();
standaloneInstances.put(type, value);
return value.get();
}
return selected.get();
}

private SeContainerInitializer getInitializer() {
if (initializer == null) {
initializer = SeContainerInitializer.newInstance();
}
return initializer;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cucumber.runtime.java.cdi2.Cdi2Factory
16 changes: 16 additions & 0 deletions cdi2/src/test/java/cucumber/runtime/java/cdi2/Belly.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package cucumber.runtime.java.cdi2;

import javax.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class Belly {
private int cukes;

public void setCukes(int cukes) {
this.cukes = cukes;
}

public int getCukes() {
return cukes;
}
}
18 changes: 18 additions & 0 deletions cdi2/src/test/java/cucumber/runtime/java/cdi2/BellyStepdefs.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cucumber.runtime.java.cdi2;

import cucumber.api.java.en.Given;

import javax.enterprise.inject.Vetoed;
import javax.inject.Inject;

@Vetoed
public class BellyStepdefs {

@Inject
private Belly belly;

@Given("I have {int} cukes in my belly")
public void haveCukes(int n) {
belly.setCukes(n);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package cucumber.runtime.java.cdi2;

import cucumber.api.java.en.Then;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;

import static org.junit.Assert.assertEquals;

@ApplicationScoped
public class CDIBellyStepdefs {

@Inject
private Belly belly;

@Then("there are {int} cukes in my belly")
public void checkCukes(int n) {
assertEquals(n, belly.getCukes());
}
}
36 changes: 36 additions & 0 deletions cdi2/src/test/java/cucumber/runtime/java/cdi2/Cdi2FactoryTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package cucumber.runtime.java.cdi2;

import io.cucumber.core.backend.ObjectFactory;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;

public class Cdi2FactoryTest {

@Test
public void shouldGiveUsNewInstancesForEachScenario() {

final ObjectFactory factory = new Cdi2Factory();
factory.addClass(BellyStepdefs.class);
factory.addClass(CDIBellyStepdefs.class);

// Scenario 1
factory.start();
final BellyStepdefs o1 = factory.getInstance(BellyStepdefs.class);
final CDIBellyStepdefs cdiStep = factory.getInstance(CDIBellyStepdefs.class);
assertNotEquals(CDIBellyStepdefs.class, cdiStep.getClass()); // it is a CDI proxy
assertEquals(CDIBellyStepdefs.class, cdiStep.getClass().getSuperclass());
factory.stop();

// Scenario 2
factory.start();
final BellyStepdefs o2 = factory.getInstance(BellyStepdefs.class);
factory.stop();

assertNotNull(o1);
assertNotSame(o1, o2);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package cucumber.runtime.java.cdi2;

import cucumber.api.junit.Cucumber;
import org.junit.runner.RunWith;

@RunWith(Cucumber.class)
public class RunCukesTest {
}
20 changes: 20 additions & 0 deletions cdi2/src/test/java/cucumber/runtime/java/cdi2/UnusedGlue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package cucumber.runtime.java.cdi2;

import cucumber.api.java.Before;
import cucumber.api.java.en.Given;

public class UnusedGlue {
public UnusedGlue() {
throw new IllegalStateException();
}

@Given("unused")
public void unused() {
throw new IllegalStateException();
}

@Before("@unused")
public void unusedHook() {
throw new IllegalStateException();
}
}
7 changes: 7 additions & 0 deletions cdi2/src/test/resources/META-INF/beans.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<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>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Feature: Cukes

Scenario: Eat some cukes
Given I have 4 cukes in my belly
Then there are 4 cukes in my belly

Scenario: Eat some more cukes
Given I have 6 cukes in my belly
Then there are 6 cukes in my belly
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@
<module>weld</module>
<module>openejb</module>
<module>needle</module>
<module>cdi2</module>
</modules>

<profiles>
Expand Down