I recently faced a singular situation: I had to adapt an application as a Solr plug-in. That application was using two different JPA implementations. As a reference to a previous post, in a traditional environment a standard API implementation is usually specified using the SPI. A central interface for the API is identified (e.g. java.sql.Driver for JDBC). Then the full name of the implementing class is specified in the content of a file available in the ClassPath under the location META-INF/services/{"fullInterfaceName"}. Multiple implementations can be specified on separate lines, this is an important point.

Usually nobody cares about the SPI: each implementation has its own META-INF/services declaration. If you want to check it just take a look inside the JAR of your usual JDBC driver (type 4). This is why the JDBC DriverManager does not require any more to use a Class.forName(...) call since Java 6. Things become more complex when multiple implementations are available in the ClassPath: for example when an application uses both a PostgreSQL and a MySQL driver. This is a common case. The JDBC API solves the problem with a workaround: a specific system property (jdbc.drivers) can be used to specify the classes names. This is not the case for all standard APIs. To solve that, the usual solution is to define your own META-INF/services/{"fullInterfaceName"} file in your application ClassPath. But with a Solr plug-in, just like my situation, it is difficult to handle the question of class loading.

In order to troubleshoot the loading of SPI implementations the JRE ServiceLoader#loadClass(Class,ClassLoader) methods is a very useful tool. In my case, it showed me that the PersistenceProvider implementations specified in my META-INF/services/javax.persistence.spi.PersistenceProvider file where not properly loaded in the Solr plug-in. As a consequence, the call to Persistence.createEntityManagerFactory(String) failed.

Understanding that the problem of implementation discovery was related to the ClassLoader, I had a look at the source of PersistenceProviderResolverHolder. It showed me that the ClassLoader used for the discovery of the JPA implementations was the current thread's:


Then the solution was obvious. Before calling Persistence.createEntityManagerFactory(...) I just forced the ClassLoader associated to the thread:

ClassLoader cLoader = getClass().getClassLoader();

Well, in the end all is logical. But such problems can be quite challenging to understand. The Java platform could be improved on that point. Perhaps an improvement provided by project Jigsaw ?