I have code using JPA and everything works fine in my development environment and in unit tests. But deploying my modules into the OSGi target environment, I regularly run into the weirdest class loading issues. I really like OSGi, but if I can't fix this once and for all, I'm going to get stark raving mad. And as long as I don't understand what classes need to be seen by which other classes, I'm never going to get the OSGi stuff set up properly.
So, as far as I can see, I have the following items that may or may not be visible from some piece of running code, let's call them "subjects":
- the JPA annotated entity classes
- the persistence API in
- the persistence provider classes
And I have the following situations in my code:
- create an
- instantiate new entity objects
- passing those objects to the
EntityManagerto put them into its persistence context
- keep using them, occasionally asking the EntityManager to save changes
- instantiating, using, and discarding entity objects without ever saving them to the database or otherwise explicitly calling the EntityManager's methods
- instead of instantiating entity objects, ask the EM to load them from the database, this leads to instantiation happening somewhere I don't see it.
- using, altering, saving and discarding these instances
So, in which of the above situations do I need which subjects to be visible?
I guess it's probably obvious that
- the persistence provider and entity classes need to be aware of javax.persistence
- the code that creates the EntityManager needs to see javax.persistence (and I guess the persistence provider, although that's not directly visible in any of my own code)
Create these bundles:
- Model (your JPA annotated classes)
- Lib (javax.persistence)
- DAO (persistence.xml, persistence provider classes)
- Business code
- Model imports and exports Lib
- DAO imports Model (and thereby Lib). DAO exports the search methods of the EM and the Model.
- Business code imports DAO
[EDIT] What you must understand is how OSGi classloading works: If you have two bundles A and B and you import both are used in C, then A can't see B and B can't see anything from A. C can see both.
Now A and B use a library bundle X. If A creates some instance from X and passes that to C who in turn passes it to B, you'll get errors since the X from A is not the same X as from B. Each X is completely encapsulated from the outside world.
In Java lingo: The classes from X are created using different classloaders and even if the name is the same, classes from different classloaders are never the same.
This is why you must avoid to import X from two different paths.