Demoiselle JUnit - NullPointerException

9

When running a unit test with br.gov.frameworkdemoiselle.junit.DemoiselleRunner , the following error is occurring at the end of the test run:

java.lang.NullPointerException
    at br.gov.frameworkdemoiselle.internal.bootstrap.SeBootstrap.removeContexts(SeBootstrap.java:70)
    at br.gov.frameworkdemoiselle.internal.bootstrap.SeBootstrap$Proxy$_$$_WeldClientProxy.removeContexts(SeBootstrap$Proxy$_$$_WeldClientProxy.java)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.jboss.weld.util.reflection.SecureReflections$13.work(SecureReflections.java:267)
    at org.jboss.weld.util.reflection.SecureReflectionAccess.run(SecureReflectionAccess.java:52)
    at org.jboss.weld.util.reflection.SecureReflectionAccess.runAsInvocation(SecureReflectionAccess.java:137)
    at org.jboss.weld.util.reflection.SecureReflections.invoke(SecureReflections.java:263)
    at org.jboss.weld.introspector.jlr.WeldMethodImpl.invokeOnInstance(WeldMethodImpl.java:164)
    at org.jboss.weld.introspector.ForwardingWeldMethod.invokeOnInstance(ForwardingWeldMethod.java:51)
    at org.jboss.weld.injection.MethodInjectionPoint.invokeOnInstanceWithSpecialValue(MethodInjectionPoint.java:154)
    at org.jboss.weld.event.ObserverMethodImpl.sendEvent(ObserverMethodImpl.java:245)
    at org.jboss.weld.event.ObserverMethodImpl.sendEvent(ObserverMethodImpl.java:233)
    at org.jboss.weld.event.ObserverMethodImpl.notify(ObserverMethodImpl.java:213)
    at org.jboss.weld.event.ObserverNotifier.notifyObserver(ObserverNotifier.java:117)
    at org.jboss.weld.event.ObserverNotifier.notifyObservers(ObserverNotifier.java:85)
    at org.jboss.weld.event.ObserverNotifier.fireEvent(ObserverNotifier.java:75)
    at org.jboss.weld.event.ObserverNotifier.fireEvent(ObserverNotifier.java:70)
    at org.jboss.weld.manager.BeanManagerImpl.fireEvent(BeanManagerImpl.java:580)
    at br.gov.frameworkdemoiselle.junit.DemoiselleRunner.shutdown(DemoiselleRunner.java:88)
    at br.gov.frameworkdemoiselle.junit.DemoiselleRunner.runChild(DemoiselleRunner.java:63)
    at br.gov.frameworkdemoiselle.junit.DemoiselleRunner.runChild(DemoiselleRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at br.gov.frameworkdemoiselle.junit.DemoiselleRunner.run(DemoiselleRunner.java:73)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

This is an application module that runs as a service. That is, it does not run on any application servers. The purpose of running tests with DemoiselleRunner is to enable the CDI.

The demoiselle dependencies I have are as follows:

        <dependency>
            <groupId>br.gov.frameworkdemoiselle.component</groupId>
            <artifactId>demoiselle-junit</artifactId>
            <version>2.3.1</version>
        </dependency>

        <dependency>
            <groupId>br.gov.frameworkdemoiselle</groupId>
            <artifactId>demoiselle-core</artifactId>
            <version>2.4.1</version>
        </dependency>

        <dependency>
            <groupId>br.gov.frameworkdemoiselle</groupId>
            <artifactId>demoiselle-jpa</artifactId>
            <version>2.4.1</version>
        </dependency>

The test basically makes access to the database to read data from one table, and to insert into another. I forgot to say but I'm using JPA and Hibernate in the application in the data access part. And in the case of the tests I'm also using DbUnit and the HSQLDB bank in memory. During the tests I make use of the CDI to inject (@Inject) the EntityManager and a DAO.

Thank you.

    
asked by anonymous 22.02.2015 / 16:18

2 answers

2

This question is quite old, but I'm going through this problem at the moment and I thought it best to record an answer.

Investigating I realized that the problem is a change in the order of events marked by the AfterShutdownProccess interface when Oracle JDK 8 is used.

More specifically, in Oracle JDK8 the method: CustomContextBootstrap # terminateContexts runs before SeBootstrap # removeContexts. Already with Oracle JDK7 the opposite occurs.

Apparently to run DemoiseilleRunner, it is not necessary for SeBootstrap # removeContexts to run since CustomContextBootstrap # terminateContexts clears the contexts. I believe it is not possible to remove the listener from the SeBootstrap # removeContexts event programmatically or declaratively without changing the Demoiseille code itself.

So the workaround I'm using is to use a fork of the DemoiselleRunner class and not to fire the event, but run directly CustomContextBootstrap # terminateContexts after running the last test method:


import org.jboss.weld.environment.se.Weld;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;

import br.gov.frameworkdemoiselle.internal.bootstrap.CustomContextBootstrap;
import br.gov.frameworkdemoiselle.lifecycle.AfterShutdownProccess;
import br.gov.frameworkdemoiselle.lifecycle.AfterStartupProccess;
import br.gov.frameworkdemoiselle.util.Beans;

public class CustomDemoiselleRunner extends BlockJUnit4ClassRunner {

    private Integer testsLeft;

    public CustomDemoiselleRunner(Class testClass) throws InitializationError {
        super(testClass);
        this.testsLeft = this.testCount();
    }

    @Override
    protected void runChild(FrameworkMethod method, RunNotifier notifier) {
        super.runChild(method, notifier);

        if (--this.testsLeft == 0) {
            this.shutdown();
        }
    }

    @Override
    public void run(RunNotifier notifier) {
        Weld weld = new Weld();
        weld.initialize();

        this.startup();
        super.run(notifier);

        weld.shutdown();
    }

    protected Object createTest() throws Exception {
        return Beans.getReference(getTestClass().getJavaClass());
    }

    private void startup() {
        Beans.getBeanManager().fireEvent(new AfterStartupProccess() {
        });
    }

    private void shutdown() {
        Beans.getReference(CustomContextBootstrap.class).terminateContexts(new AfterShutdownProccess() {
        });;
    }


}

Obviously there is the problem of not firing an event possibly necessary for the correct shutdown of the Demoiselle, but it seems to work until there is some definitive solution.

    
27.10.2017 / 22:06
0

Have you used any Demoiselle archetype to create the application? What IDE are you using is Eclipse and what version? Would it be possible to send the complete test class code?

  • According to my comment, the error is bound to version 8 of the JDK (1.8.x). When this method br.gov.frameworkdemoiselle.internal.bootstrap.SeBootstrap.removeContexts performs a deactivation of the contexts, they are null. The implementation for version 2.4.x has been modified, so those using version 2.3.x of Demoiselle do not face this problem. The solution, for now, is to use version 7 (1.7.x) of JDK. Or wait for the solution to the bug.
25.02.2015 / 17:53