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?
CodePudding user response:
javax.persistence.Persistence
is a class, not an interface, and you're passing to its constructor the name of the persistence unit you've defined in your XML configuration file, the same file in which you state you want to use Hibernate. So what's happening here is as you assumed: your configuration file is being read, and Hibernate gets used because you configured things so it would be used. You can find the source code for javax.persistence.Persistence
here and see for yourself what it does (you might need to check other classes for the actual part that reads the XML configuration).
CodePudding user response:
Being a specification and API, does not preclude the API from having some concrete classes. In this context the word "implementation" means "implementation of this specification". The JPA API is not an implementation of the JPA specification, libraries like Hibernate and EclipseLink are an implementation.
This also applies to other specification. For example, JDBC has a number of concrete classes (most importantly DriverManager
), but that doesn't mean the JDBC API itself is an implementation. JDBC drivers are an implementation of the JDBC specification.
I think you will find that the APIs of a lot of specifications in the Java ecosystem have one or more concrete classes that provide bootstrapping, lookup or other services to make the actual implementations discoverable and usable.
CodePudding user response:
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.