Issue
I read that "JPA is just specification, not implementation" and "Hibernate is implementation of JPA". But I don't understand how they fits together when it comes to execute program. Let me explain what I mean step by step:
I put two dependencies in my pom:
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
</dependency>
for JPA stuff (classes, annotations) and
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.1.11</version>
</dependency>
for implementation.
I prepare persistence.xml file with settings, where I denote that I want to use Hibernate
<persistence-unit name="dvdPU">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<property name="jakarta.persistence.jdbc.driver" value="org.postgresql.Driver" />
<property name="jakarta.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/dvdrental" />
<property name="jakarta.persistence.jdbc.user" value="postgres" />
<property name="jakarta.persistence.jdbc.password" value="j123" />
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
</properties>
</persistence-unit>
Then I write
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
...
final EntityManagerFactory factory = Persistence.createEntityManagerFactory("dvdPU");
final EntityManager manager = factory.createEntityManager();
As you can see - no mention of Hibernate in this code yet, just javax.persistence package. Does this mean that this Persistence class from JPA package does implement some bootstrapping stuff which leads program to understand of using Hibernate? And also this means that JPA is not "just a specification", it has some implementation yet?
Solution
Think of javax.persistence-api
(or jakarta.persistence-api
) as a facade where you can switch underlying implementations. Just as with the logging facade slf4j
. Slf4j also comes with it's own classes. It's more than a theoretical specification. It might come with a set of interfaces or even classes that define the contract.
If you check the source of Persistence.createEntityManagerFactory("dvdPU");
, you will see that it will search for a persistenceProvider via a resolver.
public static EntityManagerFactory createEntityManagerFactory(String persistenceUnitName, Map properties) {
EntityManagerFactory emf = null;
PersistenceProviderResolver resolver = PersistenceProviderResolverHolder.getPersistenceProviderResolver();
List<PersistenceProvider> providers = resolver.getPersistenceProviders();
The resolver will search the runtime environment for all classes implementing the javax.persistence.spi.PersistenceProvider
(old version) or jakarta.persistence.spi.PersistenceProvider
(new version) interface. Because you have Hibernate on the classpath, the org.hibernate.jpa.HibernatePersistenceProvider
will be detected and used. If you use eclipselink and have that on the classpath, then org.eclipse.persistence.jpa.PersistenceProvider
will be used.
And of course you can optionally also explicitly bind a Provider to the persistence-unit. That might be the best option when you have multiples on the classpath.
Note that the specification lists these interfaces and classes.
Link to ProviderChecker javadoc. See specifically "Does the descriptor and/or integration request Hibernate as the PersistenceProvider? Note that in the case of no requested provider being named we assume we are the provider (the calls got to us somehow...)".
Answered By - Nico Van Belle
Answer Checked By - Dawn Plyler (JavaFixing Volunteer)