I am trying to use Hibernate/Spring in an OSGi (Equinox) environment. It works great if I explicitly point it to the Entity classes in the Persistence.xml:
This blog shows how it can be handled with Spring's Dynamic Modules. Based on that blog, you'd create bean definitions for DAO and Service beans in your application context. The DAO has a reference to the hibernate sessionFactory bean:
<bean id="stuffDao" class="com.es.t.eee.domain.dao.StuffSourceDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="stuffService"
class="com.es.t.eee.domain.dao.StuffServiceImpl">
<property name="stuffDao" ref="stuffDao"/>
</bean>
<bean id="stuffSource"
class="com.es.t.eee.domain.StuffSource" scope="prototype"/>
The StuffSourceDaoImpl would implement the store() method to persist the StuffSource, it passes the StuffSource to the HibernateTemplate to actually do the persistence.
To avoid having to define persistence.xml files or specifying every Entity, you can use the AnnotationSessionFactoryBean and a wildcard to include all the types in the package(s) containing your entities (you may instead want to set the packagesToScan property, I've not tried this and it might take you back to your original problem):
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="hibernateProperties">
<props>
<!--etc-->
</props>
</property>
<!-- set either one of these properties -->
<property name="annotatedClasses">
<list>
<value>com.es.t.eee.domain.StuffSource</value>
<value>com.es.t.eee.domain.PostalAddress</value>
</list>
</property>
<property name="packagesToScan">
<list>
<value>com.es.t.eee.domain</value>
</list>
</property>
</bean>
To use this you'd get the BundleContext, get the service and bean from the context, then carry on as normal:
String serviceName = StuffService .class.getName();
StuffService service =
(StuffService )context.getService(context.getServiceReference(serviceName));
String stuffName = StuffSource.class.getName();
StuffSource stuffSource =
(StuffSource) context.getService(context.getServiceReference(stuffName ));
//do whatever with StuffSource
...
service.store(stuffSource );
You may also want to look at this OSGi Alliance blog that discusses some of the issues involved. From the OSGi Alliance blog:
Hibernate manipulates the classpath, and programs like that usually do not work well together with OSGi based systems. The reason is that in many systems the class visibility between modules is more or less unrestricted. In OSGi frameworks, the classpath is well defined and restricted. This gives us a lot of good features but it also gives us pain when we want to use a library that has aspirations to become a classloader when it grows up. ...
To work with Hibernate, you need a Session object. You can get a Session object from a SessionFactory. To get the the SessionFactory, you need to create it with a Configuration object. The Configuration object is created from a configuration XML file. By default, Hibernate loads this from the root of your JAR file, however, you can add classes manually to the configuration if so desired.
The previous reply mentioning the OSGi blog entry on the problems of Hibernate and OSGi is an informative read.
I suggest stepping back and thinking about the assumptions that are true in a traditional Java application and how they are no longer valid inside OSGi:
How will your application work if the Hibernate bundle is started before any bundles that provide the entity classes? Even if the scanning for entity classes worked, it wouldn't find any.
In traditional Java all the classes are available at start-up because of the flat class path, but in OSGi classes are only available if the contributing bundle is started and you import the packages.
OSGi requires explicit wiring of dependencies; if you don't import a bundle/package, then you can't see the classes in those bundles/packages.
Since you say that explicitly configuring the entity classes work, I assume you are using one of the following to do the dependency wiring:
Rich Seller's suggestion should work (I haven't tested it), but you are still forced to import the packages containing the entity classes, though I see nothing wrong with this and the proposed solution gives the option for package scanning rather than explicitly specifying every single entity class.
Now option 1 is easy and option 2 involves a whole lot of work. It all depends on your requirement for automatic adding/removing of entity classes from Hibernate without needing to explicitly specify packages/classes.