By default, when you use Spring Data JPA Starter in your Spring project, Hibernate will be the default implementation used. However, in some cases, you may not want to use this default implementation. For example, I’m converting this open source openid-connect https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server from Spring MVC to Spring Boot https://github.com/huongdanjavacom/openid-connect-spring-boot, this opensource is using EclipseLink instead of Hibernate. In my case, how to replace EclipseLink with Hibernate? I will guide you to do that in this tutorial.
First, I will create a new Spring Boot project:
with Spring Data JPA Starter and PostgreSQL dependency as follows:
Configure the database information in the application.properties file:
1 2 3 |
spring.datasource.url=jdbc:postgresql://localhost:5432/test spring.datasource.username=khanh spring.datasource.password=1 |
and run this Spring Boot application, you will see the following log message:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.5.0) 2021-05-26 20:56:58.926 INFO 8449 --- [ main] c.h.s.e.SpringBootEclipselinkApplication : Starting SpringBootEclipselinkApplication using Java 15.0.1 on Khanhs-MacBook-Pro.local with PID 8449 (/Users/khanh/Documents/workspace-spring-tool-suite-4-4.9.0.RELEASE/spring-boot-eclipselink/target/classes started by khanh in /Users/khanh/Documents/workspace-spring-tool-suite-4-4.9.0.RELEASE/spring-boot-eclipselink) 2021-05-26 20:56:58.930 INFO 8449 --- [ main] c.h.s.e.SpringBootEclipselinkApplication : No active profile set, falling back to default profiles: default 2021-05-26 20:56:59.402 INFO 8449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. 2021-05-26 20:56:59.411 INFO 8449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 3 ms. Found 0 JPA repository interfaces. 2021-05-26 20:56:59.743 INFO 8449 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2021-05-26 20:57:00.182 INFO 8449 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. 2021-05-26 20:57:00.223 INFO 8449 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] 2021-05-26 20:57:00.328 INFO 8449 --- [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 5.4.31.Final 2021-05-26 20:57:00.562 INFO 8449 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.1.2.Final} 2021-05-26 20:57:00.709 INFO 8449 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.PostgreSQL10Dialect 2021-05-26 20:57:01.094 INFO 8449 --- [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform] 2021-05-26 20:57:01.105 INFO 8449 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' 2021-05-26 20:57:01.437 INFO 8449 --- [ main] c.h.s.e.SpringBootEclipselinkApplication : Started SpringBootEclipselinkApplication in 2.816 seconds (JVM running for 3.734) 2021-05-26 20:57:01.440 INFO 8449 --- [ main] o.s.b.a.ApplicationAvailabilityBean : Application availability state LivenessState changed to CORRECT 2021-05-26 20:57:01.441 INFO 8449 --- [ main] o.s.b.a.ApplicationAvailabilityBean : Application availability state ReadinessState changed to ACCEPTING_TRAFFICĐ |
Read carefully the above loglines, you will see how Spring Data JPA Starter uses Hibernate as the default implementation.
Now, to replace this Hibernate default implementation with EclipseLink, first, I will declare the EclipseLink dependency as follows:
1 2 3 4 5 |
<dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>org.eclipse.persistence.jpa</artifactId> <version>2.7.8</version> </dependency> |
Then exclude Hibernate dependency in Spring Data JPA Starter dependency as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <exclusions> <exclusion> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> </exclusion> <exclusion> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> </exclusion> </exclusions> </dependency> |
Spring Boot uses the HibernateJpaAutoConfiguration class to configure all the necessary information for the Hibernate default implementation. If you take a look at this HibernateJpaAutoConfiguration class, you will see, all the information related to Hibernate is configured by Spring Boot in the HibernateJpaConfiguration class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
/* * Copyright 2012-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.boot.autoconfigure.orm.jpa; import javax.persistence.EntityManager; import org.hibernate.engine.spi.SessionImplementor; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; /** * {@link EnableAutoConfiguration Auto-configuration} for Hibernate JPA. * * @author Phillip Webb * @author Josh Long * @author Manuel Doninger * @author Andy Wilkinson * @since 1.0.0 */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EntityManager.class, SessionImplementor.class }) @EnableConfigurationProperties(JpaProperties.class) @AutoConfigureAfter({ DataSourceAutoConfiguration.class }) @Import(HibernateJpaConfiguration.class) public class HibernateJpaAutoConfiguration { } |
This HibernateJpaConfiguration class extends from the JpaBaseConfiguration class. This is the base class so we can extend and configure JPA for each implementation you want. Hibernate is an implementation and EclipseLink is also an implementation of JPA.
We will create a new class to configure JPA for EclipseLink:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
package com.huongdanjava.springboot.eclipselink; import java.util.Map; import javax.sql.DataSource; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; import org.springframework.context.annotation.Configuration; import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter; import org.springframework.transaction.jta.JtaTransactionManager; @Configuration public class EclipseLinkJpaConfiguration extends JpaBaseConfiguration { protected EclipseLinkJpaConfiguration(DataSource dataSource, JpaProperties properties, ObjectProvider<JtaTransactionManager> jtaTransactionManager) { super(dataSource, properties, jtaTransactionManager); } @Override protected AbstractJpaVendorAdapter createJpaVendorAdapter() { // TODO Auto-generated method stub return null; } @Override protected Map<String, Object> getVendorProperties() { // TODO Auto-generated method stub return null; } } |
The two methods that you need to implement in the EclipseLinkJpaConfiguration class are createJpaVendorAdapter() and getVendorProperties(). The createJpaVendorAdapter() method will return the implementation provider for JPA. By default, Spring already supports Hibernate and EclipseLink:
so you just need to return the object of the EclipseLinkJpaVendorAdapter class.
1 2 3 4 |
@Override protected AbstractJpaVendorAdapter createJpaVendorAdapter() { return new EclipseLinkJpaVendorAdapter(); } |
The getVendorProperties() method helps us define some implementation-specific configurations. For EclipseLink, you can use the PersistenceUnitProperties class to add the properties it supports. Examples are as follows:
1 2 3 4 5 6 7 8 |
@Override protected Map<String, Object> getVendorProperties() { Map<String, Object> map = new HashMap<>(); map.put(PersistenceUnitProperties.WEAVING, "false"); map.put(PersistenceUnitProperties.LOGGING_LEVEL, SessionLog.FINER_LABEL); return map; } |
Now, if you run this application again, you will see the following log message:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.5.0) 2021-05-26 22:04:26.403 INFO 10452 --- [ main] c.h.s.e.SpringBootEclipselinkApplication : Starting SpringBootEclipselinkApplication using Java 15.0.1 on Khanhs-MacBook-Pro.local with PID 10452 (/Users/khanh/Documents/workspace-spring-tool-suite-4-4.9.0.RELEASE/spring-boot-eclipselink/target/classes started by khanh in /Users/khanh/Documents/workspace-spring-tool-suite-4-4.9.0.RELEASE/spring-boot-eclipselink) 2021-05-26 22:04:26.405 INFO 10452 --- [ main] c.h.s.e.SpringBootEclipselinkApplication : No active profile set, falling back to default profiles: default 2021-05-26 22:04:26.747 INFO 10452 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. 2021-05-26 22:04:26.756 INFO 10452 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 3 ms. Found 0 JPA repository interfaces. [EL Fine]: server: 2021-05-26 22:04:27.108--Thread(Thread[main,5,main])--Configured server platform: org.eclipse.persistence.platform.server.NoServerPlatform [EL Finer]: metadata: 2021-05-26 22:04:27.126--Thread(Thread[main,5,main])--Searching for mapping file: [META-INF/orm.xml] at root URL: [file:/Users/khanh/Documents/workspace-spring-tool-suite-4-4.9.0.RELEASE/spring-boot-eclipselink/target/classes/]. [EL Finer]: metadata: 2021-05-26 22:04:27.13--Thread(Thread[main,5,main])--Searching for mapping file: [META-INF/eclipselink-orm.xml] at root URL: [file:/Users/khanh/Documents/workspace-spring-tool-suite-4-4.9.0.RELEASE/spring-boot-eclipselink/target/classes/]. [EL Finer]: metamodel: 2021-05-26 22:04:27.139--ServerSession(674233333)--Thread(Thread[main,5,main])--metamodel_type_collection_empty (There is no English translation for this message.) 2021-05-26 22:04:27.140 INFO 10452 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' 2021-05-26 22:04:27.254 INFO 10452 --- [ main] c.h.s.e.SpringBootEclipselinkApplication : Started SpringBootEclipselinkApplication in 1.08 seconds (JVM running for 2.108) 2021-05-26 22:04:27.255 INFO 10452 --- [ main] o.s.b.a.ApplicationAvailabilityBean : Application availability state LivenessState changed to CORRECT 2021-05-26 22:04:27.257 INFO 10452 --- [ main] o.s.b.a.ApplicationAvailabilityBean : Application availability state ReadinessState changed to ACCEPTING_TRAFFIC [EL Finer]: 2021-05-26 22:04:27.268--Thread(Thread[SpringContextShutdownHook,5,main])--initializing session manager |
Our application is using EclipseLink already!
Sab
Hello Sir,
Is it possible to implement tenant discriminator column in this project setup?