Skip to content

Commit f9f4d61

Browse files
toepimpkorstanje
authored andcommitted
[DeltaSpike] Add ObjectFactory for Apache DeltaSpike (#1616)
Deltaspike abstracts underlining cdi-container so it is possible to change CDI implementations by only replacing the dependencies. In the long term this means that `cucumber-weld` and `cucumber-openejb` can be removed.
1 parent 0188c95 commit f9f4d61

File tree

12 files changed

+372
-0
lines changed

12 files changed

+372
-0
lines changed

deltaspike/README.md

+129
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
Cucumber DeltaSpike
2+
===================
3+
4+
This module relies on [DeltaSpike Container Control](https://deltaspike.apache.org/documentation/container-control.html) to start/stop supported CDI container.
5+
6+
## Setup
7+
Enable cdi support for your steps by adding a (empty) beans.xml into your classpath (src/main/resource/META-INF for normal classes or src/test/resources/META-INF for test classes):
8+
9+
```xml
10+
<beans xmlns="http://java.sun.com/xml/ns/javaee"
11+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
12+
xsi:schemaLocation="
13+
http://java.sun.com/xml/ns/javaee
14+
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
15+
16+
</beans>
17+
```
18+
19+
To use DependencyInjection add `@Inject` to any field which should be managed by CDI, for more information see [JSR330](https://www.jcp.org/en/jsr/detail?id=330).
20+
21+
```java
22+
public class BellyStepdefs {
23+
24+
@Inject
25+
private Belly belly;
26+
27+
//normal step code ...
28+
```
29+
30+
This ObjectFactory doesn't start or stop any [Scopes](https://docs.oracle.com/javaee/6/tutorial/doc/gjbbk.html), so all beans live inside the default scope (Dependent). Now cucumber requested a instance of your stepdefinitions for every step, which means cdi create a new instance for every step and for all injected fields. This behaviour makes it impossible to share a state inside a szenario.
31+
32+
To bybass this, you must annotate your class(es) with `@javax.inject.Singleton`:
33+
1. on stepdefintions: now the ojectfactory will creates only one instance include injected fields per scenario and both injected fields and stepdefinitions can be used to share state inside a scenario.
34+
2. on any other class: now the objectfactory will create a new instance of your stepdefinitions per step and stepdefinitions can not be used to share state inside a scenario, only the annotated classes can be used to share state inside a scenario
35+
36+
you can also combine both approaches.
37+
38+
```java
39+
@Singleton
40+
public class BellyStepdefs {
41+
42+
@Inject
43+
private Belly belly;
44+
45+
//normal step code ...
46+
```
47+
It is not possible to use any other scope than Dependent this means alsoi it is not possible to share a state over two or more scenarios, every scenario start with a clean environment.
48+
49+
To enable this objectfactory add the folling dependency to your classpath:
50+
```xml
51+
<dependency>
52+
<groupId>io.cucumber</groupId>
53+
<artifactId>cucumber-deltaspike</artifactId>
54+
<version>${cucumber.version}</version>
55+
<scope>test</scope>
56+
</dependency>
57+
```
58+
59+
and one of the supported cdi-containers.
60+
61+
to use it with Weld:
62+
63+
```xml
64+
<dependency>
65+
<groupId>org.apache.deltaspike.cdictrl</groupId>
66+
<artifactId>deltaspike-cdictrl-weld</artifactId>
67+
<version>${deltaspike.version}</version>
68+
<scope>test</scope>
69+
</dependency>
70+
<dependency>
71+
<groupId>org.jboss.weld.se</groupId>
72+
<artifactId>weld-se-core</artifactId>
73+
<version>${weld-se.version}</version>
74+
<scope>test</scope>
75+
</dependency>
76+
```
77+
78+
or to use it with OpenEJB:
79+
80+
```xml
81+
<dependency>
82+
<groupId>org.apache.deltaspike.cdictrl</groupId>
83+
<artifactId>deltaspike-cdictrl-openejb</artifactId>
84+
<version>${deltaspike.version}</version>
85+
<scope>test</scope>
86+
</dependency>
87+
<dependency>
88+
<groupId>org.apache.tomee</groupId>
89+
<artifactId>openejb-core</artifactId>
90+
<version>${openejb-core.version}</version>
91+
<scope>test</scope>
92+
</dependency>
93+
<dependency>
94+
<groupId>javax.xml.bind</groupId>
95+
<artifactId>jaxb-api</artifactId>
96+
<version>${jaxb-api.version}</version>
97+
<scope>test</scope>
98+
</dependency>
99+
<dependency>
100+
<groupId>org.glassfish.jaxb</groupId>
101+
<artifactId>jaxb-runtime</artifactId>
102+
<version>${jaxb-api.version}</version>
103+
<scope>test</scope>
104+
</dependency>
105+
```
106+
107+
or to use it with OpenWebBeans:
108+
```xml
109+
<dependency>
110+
<groupId>org.apache.deltaspike.cdictrl</groupId>
111+
<artifactId>deltaspike-cdictrl-owb</artifactId>
112+
<version>${deltaspike.version}</version>
113+
<scope>test</scope>
114+
</dependency>
115+
<dependency>
116+
<groupId>org.apache.openwebbeans</groupId>
117+
<artifactId>openwebbeans-impl</artifactId>
118+
<version>${owb.version}</version>
119+
<scope>test</scope>
120+
</dependency>
121+
<dependency>
122+
<groupId>javax.annotation</groupId>
123+
<artifactId>jsr250-api</artifactId>
124+
<version>1.0</version>
125+
<scope>test</scope>
126+
</dependency>
127+
```
128+
129+
Some containers need that you provide a CDI-API in a given version, but if you develop CDI and use one of the above containers it should already on your path.

deltaspike/pom.xml

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>io.cucumber</groupId>
9+
<artifactId>cucumber-jvm</artifactId>
10+
<version>5.0.0-SNAPSHOT</version>
11+
</parent>
12+
13+
<artifactId>cucumber-deltaspike</artifactId>
14+
<packaging>jar</packaging>
15+
<name>Cucumber-JVM: DeltaSpike</name>
16+
17+
<properties>
18+
<project.Automatic-Module-Name>io.cucumber.deltaspike</project.Automatic-Module-Name>
19+
<deltaspike.version>1.9.0</deltaspike.version>
20+
</properties>
21+
22+
<dependencies>
23+
<dependency>
24+
<groupId>io.cucumber</groupId>
25+
<artifactId>cucumber-core</artifactId>
26+
</dependency>
27+
<dependency>
28+
<groupId>org.apache.deltaspike.cdictrl</groupId>
29+
<artifactId>deltaspike-cdictrl-api</artifactId>
30+
<version>${deltaspike.version}</version>
31+
</dependency>
32+
<dependency>
33+
<groupId>javax.enterprise</groupId>
34+
<artifactId>cdi-api</artifactId>
35+
<version>1.0-SP4</version>
36+
<scope>provided</scope>
37+
</dependency>
38+
39+
<dependency>
40+
<groupId>io.cucumber</groupId>
41+
<artifactId>cucumber-java</artifactId>
42+
<scope>test</scope>
43+
</dependency>
44+
<dependency>
45+
<groupId>io.cucumber</groupId>
46+
<artifactId>cucumber-junit</artifactId>
47+
<scope>test</scope>
48+
</dependency>
49+
<dependency>
50+
<groupId>junit</groupId>
51+
<artifactId>junit</artifactId>
52+
<scope>test</scope>
53+
</dependency>
54+
<dependency>
55+
<groupId>org.apache.deltaspike.cdictrl</groupId>
56+
<artifactId>deltaspike-cdictrl-weld</artifactId>
57+
<version>${deltaspike.version}</version>
58+
<scope>test</scope>
59+
</dependency>
60+
<dependency>
61+
<groupId>org.jboss.weld.se</groupId>
62+
<artifactId>weld-se-core</artifactId>
63+
<version>1.1.34.Final</version>
64+
<scope>test</scope>
65+
</dependency>
66+
</dependencies>
67+
68+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package io.cucumber.deltaspike;
2+
3+
import org.apache.deltaspike.cdise.api.CdiContainer;
4+
import org.apache.deltaspike.cdise.api.CdiContainerLoader;
5+
import io.cucumber.core.backend.ObjectFactory;
6+
import javax.enterprise.context.spi.CreationalContext;
7+
import javax.enterprise.inject.spi.Bean;
8+
import javax.enterprise.inject.spi.BeanManager;
9+
import java.util.Set;
10+
import org.apiguardian.api.API;
11+
12+
@API(status = API.Status.STABLE)
13+
public final class DeltaSpikeObjectFactory implements ObjectFactory {
14+
15+
private final CdiContainer container;
16+
17+
public DeltaSpikeObjectFactory() {
18+
this.container = CdiContainerLoader.getCdiContainer();
19+
}
20+
21+
@Override
22+
public void start() {
23+
container.boot();
24+
}
25+
26+
@Override
27+
public void stop() {
28+
container.shutdown();
29+
}
30+
31+
@Override
32+
public boolean addClass(final Class<?> clazz) {
33+
return true;
34+
}
35+
36+
@Override
37+
public <T> T getInstance(final Class<T> type) {
38+
final BeanManager beanManager = container.getBeanManager();
39+
final Set<Bean<?>> beans = beanManager.getBeans(type);
40+
final Bean<?> bean = beanManager.resolve(beans);
41+
final CreationalContext<?> creationalContext = beanManager.createCreationalContext(bean);
42+
try {
43+
return type.cast(beanManager.getReference(bean, type, creationalContext));
44+
} finally {
45+
creationalContext.release();
46+
}
47+
}
48+
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.cucumber.deltaspike.DeltaSpikeObjectFactory
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.cucumber.deltaspike;
2+
3+
public class Belly {
4+
5+
private int cukes;
6+
7+
public void setCukes(int cukes) {
8+
this.cukes = cukes;
9+
}
10+
11+
public int getCukes() {
12+
return cukes;
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package io.cucumber.deltaspike;
2+
3+
import io.cucumber.java.en.Given;
4+
import io.cucumber.java.en.Then;
5+
import javax.inject.Inject;
6+
import javax.inject.Singleton;
7+
8+
import static org.junit.Assert.assertEquals;
9+
import static org.junit.Assert.assertTrue;
10+
11+
@Singleton
12+
public class BellyStepdefs {
13+
14+
// For injecting classes from src/test/java, your beans.xml has to be
15+
// located in src/test/resources.
16+
// If you want to inject classes from src/main/java, you will need an
17+
// additional beans.xml in src/main/resources.
18+
@Inject
19+
private Belly belly;
20+
21+
private boolean inTheBelly = false;
22+
23+
@Given("I have {int} cukes in my belly")
24+
public void haveCukes(int n) {
25+
belly.setCukes(n);
26+
inTheBelly = true;
27+
}
28+
29+
@Then("there are {int} cukes in my belly")
30+
public void checkCukes(int n) {
31+
assertEquals(n, belly.getCukes());
32+
assertTrue(inTheBelly);
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package io.cucumber.deltaspike;
2+
3+
import io.cucumber.core.backend.ObjectFactory;
4+
import org.junit.Test;
5+
import static org.junit.Assert.assertNotNull;
6+
import static org.junit.Assert.assertNotSame;
7+
8+
public class DeltaSpikeObjectFactoryTest {
9+
10+
private final ObjectFactory factory = new DeltaSpikeObjectFactory();
11+
12+
@Test
13+
public void shouldGiveUsNewInstancesForEachScenario() {
14+
factory.addClass(BellyStepdefs.class);
15+
16+
// Scenario 1
17+
factory.start();
18+
final BellyStepdefs o1 = factory.getInstance(BellyStepdefs.class);
19+
factory.stop();
20+
21+
// Scenario 2
22+
factory.start();
23+
final BellyStepdefs o2 = factory.getInstance(BellyStepdefs.class);
24+
factory.stop();
25+
26+
assertNotNull(o1);
27+
assertNotSame(o1, o2);
28+
}
29+
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package io.cucumber.deltaspike;
2+
3+
import io.cucumber.junit.Cucumber;
4+
import org.junit.runner.RunWith;
5+
6+
@RunWith(Cucumber.class)
7+
public class RunCukesTest {
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package io.cucumber.deltaspike;
2+
3+
import io.cucumber.java.Before;
4+
import io.cucumber.java.en.Given;
5+
6+
public class UnusedGlue {
7+
8+
public UnusedGlue() {
9+
throw new IllegalStateException();
10+
}
11+
12+
@Given("unused")
13+
public void unused() {
14+
throw new IllegalStateException();
15+
}
16+
17+
@Before("@unused")
18+
public void unusedHook() {
19+
throw new IllegalStateException();
20+
}
21+
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<beans xmlns="http://java.sun.com/xml/ns/javaee"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="
4+
http://java.sun.com/xml/ns/javaee
5+
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
6+
7+
</beans>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Feature: Cukes
2+
3+
Scenario: Eat some cukes
4+
Given I have 4 cukes in my belly
5+
Then there are 4 cukes in my belly
6+
7+
Scenario: Eat some more cukes
8+
Given I have 6 cukes in my belly
9+
Then there are 6 cukes in my belly

pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@
208208
<module>openejb</module>
209209
<module>needle</module>
210210
<module>cdi2</module>
211+
<module>deltaspike</module>
211212
</modules>
212213

213214
<profiles>

0 commit comments

Comments
 (0)