3

I am trying to run a simple test for DeltaSpike repository. However, I cannot get the Entity Manager injected. I am using producer which is located and test sources:

@ApplicationScoped
public class EntityManagerProducer {

    @Produces
    public EntityManager getEntityManager() {
        return Persistence
          .createEntityManagerFactory("primary-test")
          .createEntityManager();
    }
}

In META-INF folder under test resources I have a persistence.xml file with primary-test persistence unit defined:

<persistence version="2.0"
         xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="primary-test" transaction-type="RESOURCE_LOCAL">
        <properties>
            <!-- Configuring JDBC properties -->
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test"/>
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>

            <!-- Hibernate properties -->
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
            <property name="hibernate.format_sql" value="false"/>
            <property name="hibernate.show_sql" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

In very simple Unit I am trying to inject Entity Manager:

@RunWith(CdiTestRunner.class)
public class UserRepositoryTest {

    @Inject
    private EntityManager entityManager;

    @Test
    public void shouldReturnEmptyListWhenDBIsEmpty() {
        // dummy test here
    }
}

However, when I am running it I am getting the exception:

 WELD-001408 Unsatisfied dependencies for type [EntityManager] with qualifiers [@Default] at injection point [[field] @Inject private com.repository.UserRepositoryTest.entityManager]

My pom.xml has dependencies to Apache DeltaSpike Test Module and Weld:

<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <deltaspike.version>1.8.2</deltaspike.version>
  <weld.version>1.1.10.Final</weld.version>
</properties>

<dependency>
  <groupId>org.apache.deltaspike.modules</groupId>
  <artifactId>deltaspike-test-control-module-api</artifactId>
  <version>${deltaspike.version}</version>
  <scope>test</scope>
</dependency>

<dependency>
  <groupId>org.apache.deltaspike.modules</groupId>
  <artifactId>deltaspike-test-control-module-impl</artifactId>
  <version>${deltaspike.version}</version>
  <scope>test</scope>
</dependency>

<dependency>
  <groupId>org.apache.deltaspike.cdictrl</groupId>
  <artifactId>deltaspike-cdictrl-weld</artifactId>
  <version>${deltaspike.version}</version>
  <scope>test</scope>
</dependency>

<dependency>
  <groupId>org.jboss.weld.se</groupId>
  <artifactId>weld-se-core</artifactId>
  <version>${weld.version}</version>
  <scope>test</scope>
</dependency>

Any ideas why Entity Manager cannot be injected? I do not want to use Arquillian.

EDIT: Current pom.xml:

<groupId>com.us</groupId>
<artifactId>deltaspike-samples</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<name>DeltaSpike samples</name>

<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <deltaspike.version>1.8.1</deltaspike.version>
  <weld.version>3.0.4.Final</weld.version>
</properties>

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.apache.deltaspike.distribution</groupId>
      <artifactId>distributions-bom</artifactId>
      <version>${deltaspike.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    <dependency>
      <groupId>org.wildfly.bom</groupId>
      <artifactId>jboss-javaee-7.0-with-hibernate</artifactId>
      <version>8.2.2.Final</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>7.0</version>
    <scope>provided</scope>
  </dependency>

  <dependency>
    <groupId>org.apache.deltaspike.core</groupId>
    <artifactId>deltaspike-core-api</artifactId>
    <scope>compile</scope>
  </dependency>

  <dependency>
    <groupId>org.apache.deltaspike.core</groupId>
    <artifactId>deltaspike-core-impl</artifactId>
    <scope>runtime</scope>
  </dependency>

  <dependency>
    <groupId>org.apache.deltaspike.modules</groupId>
    <artifactId>deltaspike-data-module-api</artifactId>
    <scope>compile</scope>
  </dependency>

  <dependency>
    <groupId>org.apache.deltaspike.modules</groupId>
    <artifactId>deltaspike-data-module-impl</artifactId>
    <scope>runtime</scope>
  </dependency>

  <!--Test dependencies-->
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
  </dependency>

  <dependency>
    <groupId>org.apache.deltaspike.modules</groupId>
    <artifactId>deltaspike-test-control-module-api</artifactId>
    <scope>test</scope>
  </dependency>

  <dependency>
    <groupId>org.apache.deltaspike.modules</groupId>
    <artifactId>deltaspike-test-control-module-impl</artifactId>
    <scope>test</scope>
  </dependency>

  <dependency>
    <groupId>org.apache.deltaspike.cdictrl</groupId>
    <artifactId>deltaspike-cdictrl-api</artifactId>
    <version>${deltaspike.version}</version>
    <scope>compile</scope>
  </dependency>

  <dependency>
    <groupId>org.apache.deltaspike.cdictrl</groupId>
    <artifactId>deltaspike-cdictrl-weld</artifactId>
    <version>${deltaspike.version}</version>
    <scope>test</scope>
  </dependency>

  <dependency>
    <groupId>javax.enterprise</groupId>
    <artifactId>cdi-api</artifactId>
    <version>2.0</version>
  </dependency>

  <dependency>
    <groupId>org.jboss.weld.se</groupId>
    <artifactId>weld-se-shaded</artifactId>
    <version>3.0.4.Final</version>
    <scope>test</scope>
  </dependency>

  <dependency>
    <groupId>org.hibernate.javax.persistence</groupId>
    <artifactId>hibernate-jpa-2.1-api</artifactId>
    <scope>test</scope>
  </dependency>

  <dependency>
    <groupId>org.jboss.spec.javax.annotation</groupId>
    <artifactId>jboss-annotations-api_1.2_spec</artifactId>
    <scope>test</scope>
  </dependency>

</dependencies>
Adam
  • 884
  • 7
  • 29

2 Answers2

2

Using CDI in JAVA SE requires the beans.xml to be put in META-INF although this is optional since Java EE 7.

Then, set discovery mode to annotated and your producer should be detected.

Here is a working configuration :

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
    <deltaspike.version>1.8.2</deltaspike.version>
    <weld.version>3.0.4.Final</weld.version>
</properties>

Now, here is how you setup the base DeltaSpike dependency :

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.apache.deltaspike.distribution</groupId>
            <artifactId>distributions-bom</artifactId>
            <version>${deltaspike.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

In the dependencies, you should have theses specs :

<dependency>
    <groupId>javax.enterprise</groupId>
    <artifactId>cdi-api</artifactId>
    <version>2.0</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>javax.transaction</groupId>
    <artifactId>javax.transaction-api</artifactId>
    <version>1.3</version>
</dependency>   

<dependency>
    <groupId>javax.persistence</groupId>
    <artifactId>javax.persistence-api</artifactId>
    <version>2.2</version>
</dependency>

Now it's time to depend on implementations.

First, Deltaspike itself :

<dependency>
    <groupId>org.apache.deltaspike.core</groupId>
    <artifactId>deltaspike-core-api</artifactId>
    <scope>compile</scope>
</dependency>

<dependency>
    <groupId>org.apache.deltaspike.core</groupId>
    <artifactId>deltaspike-core-impl</artifactId>
    <scope>runtime</scope>
</dependency>

<dependency>
    <groupId>org.apache.deltaspike.cdictrl</groupId>
    <artifactId>deltaspike-cdictrl-api</artifactId>
    <scope>compile</scope>
</dependency>

Then JBoss Weld 3 (CDI 2.0 impl)

<dependency>
    <groupId>org.jboss.weld.se</groupId>
    <artifactId>weld-se-shaded</artifactId>
    <version>${weld.version}</version>
    <scope>runtime</scope>
</dependency>

And Weld controler for DeltaSpike :

<dependency>
    <groupId>org.apache.deltaspike.cdictrl</groupId>
    <artifactId>deltaspike-cdictrl-weld</artifactId>
    <scope>runtime</scope>
</dependency>

Then the DeltaSpike Data module :

<dependency>
    <groupId>org.apache.deltaspike.modules</groupId>
    <artifactId>deltaspike-data-module-api</artifactId>
    <version>${deltaspike.version}</version>
    <scope>compile</scope>
</dependency>

<dependency>
    <groupId>org.apache.deltaspike.modules</groupId>
    <artifactId>deltaspike-data-module-impl</artifactId>
    <version>${deltaspike.version}</version>
    <scope>runtime</scope>
</dependency>

Now it's time for the JPA implementation (EclipseLink JPA 2.7.1) and an embedded database server H2 :

<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>org.eclipse.persistence.jpa</artifactId>
    <version>2.7.1</version>
</dependency>

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.197</version>
    <scope>runtime</scope>
</dependency>

To create unit test with JUnit 5, you need this :

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.1.0</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.1.0</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    <version>5.1.0</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.junit.platform</groupId>
    <artifactId>junit-platform-launcher</artifactId>
    <version>1.1.0</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.junit.platform</groupId>
    <artifactId>junit-platform-runner</artifactId>
    <version>1.1.0</version>
    <scope>test</scope>
</dependency>

And to be able to launch CDI with a single annotation in a JUnit class, you need this as well :

<dependency>
    <groupId>org.jboss.weld</groupId>
    <artifactId>weld-junit5</artifactId>
    <version>1.2.2.Final</version>
    <scope>test</scope>
</dependency>

To enable JUnit 5 in Maven, you must configure maven-surefire-plugin :

<build>
    <plugins>
        <plugin>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.19.1</version>
            <dependencies>
                <dependency>
                    <groupId>org.junit.platform</groupId>
                    <artifactId>junit-platform-surefire-provider</artifactId>
                    <version>1.0.3</version>
                </dependency>
                <dependency>
                    <groupId>org.junit.jupiter</groupId>
                    <artifactId>junit-jupiter-engine</artifactId>
                    <version>5.0.3</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

And, I'll use Lombok and SLF4J :

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.20</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.25</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>1.7.25</version>
    <scope>test</scope>
</dependency>

Here is my project structure :

main/java/fr/fxjavadevblog
          +-- VideoGame.java (JPA Entity)
          +-- VideoGameFactory.java
          +-- VideoGameRepository.java (interface)
          +-- InjectedUUID.java (annotation def.)
          +-- Producers.java (produces EntityManager and UUID has string)
    /resources/META-INF
          +-- beans.xml
          +-- persistence.xml

test/java/fr/fxjavadevblog
          +-- VideoGameReposityTest.java (JUnit 5)
    /resources/META-INF
          +-- beans.xml
          +-- persistence.xml

Here is are my CDI producers, needed by DeltaSpike Data and to inject UUID as private keys :

package fr.fxjavadevblog;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.Persistence;
import java.util.UUID;

/**
 * composite of CDI Producers.
 *
 * @author robin
 */
@ApplicationScoped
public class Producers
{
    public static final String UNIT_NAME = "cdi-deltaspike-demo";

    /**
     * produces the instance of entity manager for the application and for DeltaSpike.
     */
    @Produces
    @SuppressWarnings("unused") // just remove the warning, because the field serves as CDI Producer and the IDE cannot detect it.
    private static EntityManager em = Persistence.createEntityManagerFactory(UNIT_NAME).createEntityManager();

    /**
     * produces randomly generated UUID for primary keys.
     *
     * @return UUID as a HEXA-STRING
     *
     */
    @Produces
    @InjectedUUID
    @SuppressWarnings("unused") // just remove the warning, because the method serves as CDI Producer and the IDE cannot detect it.
    public String produceUUIDAsString()
    {
        return UUID.randomUUID().toString();
    }
}

this class uses a custom CDI Qualifier called @InjectedUUID :

package fr.fxjavadevblog;

import javax.inject.Qualifier;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;


import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * CDI Qualifier for UUID Producers
 *
 * @author robin
 */

@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface InjectedUUID 
{
}

Here is my JPA entity, using Lombok and CDI annotations :

package fr.fxjavadevblog;

import lombok.*;

import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import javax.persistence.*;
import java.io.Serializable;

/**
 * simple JPA Entity, using Lombok and CDI Injected fields (UUID).
 *
 * @author robin
 */

// lombok annotations
@NoArgsConstructor(access = AccessLevel.PROTECTED) // to avoid direct instanciation bypassing the factory.
@ToString(of = {"id","name"})
@EqualsAndHashCode(of="id")

// CDI Annotation
@Dependent

// JPA Annotation
@Entity
public class VideoGame implements Serializable {

    @Id
    @Inject @InjectedUUID // ask CDI to inject an brand new UUID
    @Getter
    private String id;

    @Getter @Setter
    private String name;

    // this field will work as a flag to know if the entity has already been persisted
    @Version
    @Getter
    private Long version;
}

Here is a simple factory for my entity class :

/**
 * simple Factory for creation VideoGame instances populated with UUID, ready to persist.
 * This factory is need to get a proper Entity. Entities must not be created with the "new" operator, but must be build
 * by invoking CDI.
 *
 * @author robin
 */
public class VideoGameFactory
{
    /**
     * creates and brand new VideoGame instance with its own UUID as PK.
     *
     * @return instance of a VideoGame
     */
    public static VideoGame newInstance()
    {
        // ask CDI for the instance, injecting required dependencies.
        return CDI.current().select(VideoGame.class).get();
    }
}

And last but not least, the DeltaSpike Data Resposity for my entity :

package fr.fxjavadevblog;

import org.apache.deltaspike.data.api.EntityRepository;
import org.apache.deltaspike.data.api.Repository;


/**
 * CRUD (and much more) interface, using DeltaSpike Data module.
 *
 * @author robin
 */

@Repository
interface VideoGameRepository extends EntityRepository <VideoGame, String>
{
    // nothing to code here : automatic Repo generated by DeltaSpike
}

Here are the configuration files :

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
       bean-discovery-mode="annotated" version="2.0">
</beans>

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
                                 http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
    <persistence-unit name="cdi-deltaspike-demo" transaction-type="RESOURCE_LOCAL">

        <class>fr.fxjavadevblog.VideoGame</class>

        <properties>
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test"/>
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
            <property name="javax.persistence.schema-generation.database.action" value="create"/>
        </properties>

    </persistence-unit>
</persistence>

These files are duplicated into the test/resources/META-INF folder as well.

And finally, here is the unit test :

package fr.fxjavadevblog;

import org.jboss.weld.junit5.EnableWeld;
import org.jboss.weld.junit5.WeldInitiator;
import org.jboss.weld.junit5.WeldSetup;
import org.junit.Assert;
import org.junit.jupiter.api.Test;

import lombok.extern.slf4j.Slf4j;

import javax.inject.Inject;

/**
 * simple test class for the VideoGameRepository, using LOMBOK and WELD.
 *
 * @author robin
 */

@Slf4j
@EnableWeld
class VideoGameRepositoryTest
{
    @WeldSetup // This is need to discover Producers and DeltaSpike Repository functionality
    private WeldInitiator weld = WeldInitiator.performDefaultDiscovery();

    @Inject
    private VideoGameRepository repo;

    @Test
    void test()
    {

        VideoGame videoGame = VideoGameFactory.newInstance();
        videoGame.setName("XENON");
        repo.save(videoGame);
        // testing if the ID field had been generated by the JPA Provider.
        Assert.assertNotNull(videoGame.getVersion());
        Assert.assertTrue(videoGame.getVersion() > 0);
        log.info("Video Game : {}", videoGame);
    }

}

Usage of Lombok and the UUID producer is optional.

You can find the full code source, and clone the repo, on github : https://github.com/fxrobin/cdi-deltaspike-demo

fxrobin
  • 590
  • 3
  • 9
  • I added this beans.xml. However, next problem: java.lang.ClassNotFoundException: org.jboss.weld.events.WeldEvent. When I use Weld version 2.1.2.Final then exception is: ClassNotFoundException: javax.transaction.SystemException. Is there any way to test Apache DeltaSpike? – Adam Jun 05 '18 at 21:17
  • try all the deps above. I changed weld-se-core into weld-se to get a shaded jar including deps. – fxrobin Jun 05 '18 at 21:33
  • Still does not work - NoClassDefFoundError: org/apache/deltaspike/cdise/api/CdiContainerLoader – Adam Jun 05 '18 at 21:46
  • try weld-se-shaded instead of weld-se. I'll make a demo project which I'll publish on GitHub as soon as possible. – fxrobin Jun 05 '18 at 22:16
  • Did you include a dependency to JPA and Hibernate in your pom.xml ? can you publish your full pom.xml in your question. – fxrobin Jun 05 '18 at 22:24
  • I will update the question with the full pom.xml. However, I was testing simple DeltaSpike JUnits (without Data module, just CDI injection). – Adam Jun 06 '18 at 04:49
  • I updated the question with current pom.xml. When I try to run it now, I am getting exception java.lang.ClassNotFoundException: javax.annotation.Priority – Adam Jun 06 '18 at 19:53
  • I've been able to make it work with DeltaSpike 1.8, JUnit4.12 and Weld 2. It's broken with Weld 3 and JUnit 5. I'll publish my solution in few hours. – fxrobin Jun 06 '18 at 19:56
  • WildFly and HIbernate are a constraint for you ? or another solution is possible ? If you want to run Java EE with an AppServer you'll have to use Arquillian and a Shrinkwrap. – fxrobin Jun 06 '18 at 20:01
  • No - I just want to test it. It does not matter which server and JPA provider – Adam Jun 06 '18 at 20:03
  • Btw. I tried to test with Arquillian but I could not solve Deployment per each test class. – Adam Jun 06 '18 at 20:07
  • I've edited my answer into a full working example. Hope you'll be able to make it work. You better have to clone my git repo on GitHub (follow the given link at the end of the post). – fxrobin Jun 20 '18 at 12:08
0

I had similar issues with Deltaspike and a Junit5 integration test of a database repository. Basically, I could not inject the repository when using Junit5 @Test annotations. I had to use Junit4 @Test annotations as a workaround.

Patrick
  • 1,728
  • 2
  • 17
  • 30