0

I have created a Singleton-Bean containing the database-access. The EntityManager is injected as PersistenceContext and i've created some basic methods to persist items. Stripped-Down-Version:

@Singleton
public class Database implements Serializable {

private static final long serialVersionUID = -349043798329818812L;

    @PersistenceContext(name = "PUname")
    private EntityManager em;

    public EntityManager getEntityManager() {
        return this.em;
    }
    ...
}

There is a remote-interface (the facade) injecting this Singleton, but for this test it's not needed.

For testing, I created a JUnit-Test and got the container by:

@BeforeClass
public static void setUpClass() throws NamingException {
    container = javax.ejb.embeddable.EJBContainer.createEJBContainer();
    instance = (Database) container.getContext().lookup("java:global/classes/Database");
}

When I now try to store my entities, it works fine for most of them, but for some, all operations like

instance.getEntityManager().persist(entity);

throw a NullPointerException becaue the EntityManager is null.

I don't understand why because it's working fine for most of them.

The entities all have the same basis, as they are derived from my AbstractEntity:

@MappedSuperclass
public abstract class AbstractEntity implements Serializable{

    private static final long serialVersionUID = -5790226883892406345L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true, nullable = false)
    private String uuid;
    ...
}

The Entites all have serialUUIDs and the @Entity annotation.

This is driving me crazy and I tried a lot of things. I think it is really strange, that these operations work fine for most of my entities, but when I try to invoke the methods for others, the EntityManager is not injected correctly.

EDIT01: I found out that for an entity called "User" I can call em.persist(user), but if I try to call em.merge(user) after I changed some values, I get the NullPointerException for the EntityManager.

I am using GlassFish contained in JDK 8.

EDIT02: Stacktrace:

java.lang.NullPointerException
at zulu.votesapplication.logic.impl.Database.mergeUser(Database.java:311)
at zulu.votesapplication.logic.impl.DatabaseTest.testMergeUser(DatabaseTest.java:593)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.apache.tools.ant.taskdefs.optional.junit.JUnit4TestMethodAdapter.run(JUnit4TestMethodAdapter.java:105)
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.run(JUnitTestRunner.java:532)
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.launch(JUnitTestRunner.java:1179)
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(JUnitTestRunner.java:1030)

EDIT03: I even tried to run "Clean and Build" in Netbeans, but that did not help. There weren't many changes to my last GIT-commit, and I checked them about 10 times. Nothing that should make trouble (I even reverted them locally).

At the end I checked out the last commit at a different place and placed my changes there: Now it seems to be working fine. So I think the IDE or the GIT-Bash screwed my project somehow, but I did not find the issue.

Klumbe
  • 370
  • 2
  • 12
  • 1
    Just wanted to tell you that you are introducing a bottleneck by using a Singleton to access you entity manager every time. – Dainesch Oct 28 '15 at 07:16
  • I thought about that, too. Can you give me a hint what's the better way? I need the methods of that Database-Class in some other classes and I don't want to have an open interface (it must not be callable from outside the ejb-layer). – Klumbe Oct 28 '15 at 09:13
  • @Dainesch : Do you think Stateless and LocalBean annotations do well for that case? – Klumbe Oct 28 '15 at 09:30
  • 1
    It depends a bit on the use of the singleton, and why the class is declared as singleton. But generally you would use `@Stateless` beans to perform operations on the database using the entity manager. From there you also could access the singleton when needed. You could also "optimize" the singleton by managing the `@Lock` modes and the `@ConcurrencyManagement` but better go for stateless beans. – Dainesch Oct 28 '15 at 09:32
  • The methods themselves don't need the Singleton. I just thought it would be better because of the concurrency. But I've read later, that the EntityManager is threadsave. Do I just need the '@Stateless' instead of the '@Singleton' ? Thanks @Dainesch – Klumbe Oct 28 '15 at 09:53
  • 1
    Yes the `@Stateless` is sufficient. It is not accessible from outside as long as you don't define an `@Remote` interface for it. Btw normally you use many many stateless beans and just inject the entity manager using `@PersistenceContext` where needed. The container takes care of nearly anything (transactions, injection, thread safety, ...) – Dainesch Oct 28 '15 at 10:04
  • Thank you very very much @Dainesch ! You are right about injecting the EntityManager every time, but a colleague decided to create a new class for it and now I have to stick with it :-) – Klumbe Oct 28 '15 at 10:19

0 Answers0