views:

56

answers:

1

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
  • a persistence.xml
  • the persistence API in javax.persistence
  • the persistence provider classes

And I have the following situations in my code:

  • create an EntityManagerFactory and an EntityManager
  • instantiate new entity objects
  • passing those objects to the EntityManager to 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)
+1  A: 

Create these bundles:

  • Model (your JPA annotated classes)
  • Lib (javax.persistence)
  • DAO (persistence.xml, persistence provider classes)
  • Business code

Visibility:

  • 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.

Aaron Digulla
But wouldn't Model at least have to see Lib?
Hanno Fietz
And I'm definitely in trouble if I don't put the persistence.xml in the same bundle as the models, that has already bitten me.
Hanno Fietz
Oops, yeah, you're right. Fixed.
Aaron Digulla
Those later comments were very helpful, I hadn't really grokked that, and it will heavily affect anything that looks up stuff based on some `Class` reference. My persistence provider (eclipselink) for instance has a `Map<Class, Something>` that it uses to decide whether it can persist a particular object. See if I'll get a grip on it now.
Hanno Fietz
If you take X to be Model, I guess I shouldn't be instantiating classes from it all over the place and pass them to DAO to persist, because then suddenly classes meant to be identical are considered different, right? That would explain a lot of my trouble.
Hanno Fietz