001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.orm.jpa.vendor; 018 019import java.util.HashMap; 020import java.util.Map; 021import javax.persistence.EntityManager; 022import javax.persistence.EntityManagerFactory; 023import javax.persistence.spi.PersistenceProvider; 024import javax.persistence.spi.PersistenceUnitInfo; 025import javax.persistence.spi.PersistenceUnitTransactionType; 026 027import org.hibernate.cfg.Environment; 028import org.hibernate.dialect.DB2Dialect; 029import org.hibernate.dialect.DerbyDialect; 030import org.hibernate.dialect.H2Dialect; 031import org.hibernate.dialect.HSQLDialect; 032import org.hibernate.dialect.InformixDialect; 033import org.hibernate.dialect.MySQL5Dialect; 034import org.hibernate.dialect.Oracle9iDialect; 035import org.hibernate.dialect.PostgreSQLDialect; 036import org.hibernate.dialect.SQLServer2008Dialect; 037 038/** 039 * {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for Hibernate 040 * EntityManager. Developed and tested against Hibernate 3.6, 4.2/4.3 as well as 5.x. 041 * <b>Hibernate 4.2+ is strongly recommended for use with Spring 4.0+.</b> 042 * 043 * <p>Exposes Hibernate's persistence provider and EntityManager extension interface, 044 * and adapts {@link AbstractJpaVendorAdapter}'s common configuration settings. 045 * Also supports the detection of annotated packages (through 046 * {@link org.springframework.orm.jpa.persistenceunit.SmartPersistenceUnitInfo#getManagedPackages()}), 047 * e.g. containing Hibernate {@link org.hibernate.annotations.FilterDef} annotations, 048 * along with Spring-driven entity scanning which requires no {@code persistence.xml} 049 * ({@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#setPackagesToScan}). 050 * 051 * <p>Note that the package location of Hibernate's JPA support changed from 4.2 to 4.3: 052 * from {@code org.hibernate.ejb.HibernateEntityManager(Factory)} to 053 * {@code org.hibernate.jpa.HibernateEntityManager(Factory)}. As of Spring 4.0, 054 * we're exposing the correct, non-deprecated variant depending on the Hibernate 055 * version encountered at runtime, in order to avoid deprecation log entries. 056 * 057 * <p><b>A note about {@code HibernateJpaVendorAdapter} vs native Hibernate settings:</b> 058 * Some settings on this adapter may conflict with native Hibernate configuration rules 059 * or custom Hibernate properties. For example, specify either {@link #setDatabase} or 060 * Hibernate's "hibernate.dialect_resolvers" property, not both. Also, be careful about 061 * Hibernate's connection release mode: This adapter prefers {@code ON_CLOSE} behavior, 062 * aligned with {@link HibernateJpaDialect#setPrepareConnection}, at least for non-JTA 063 * scenarios; you may override this through corresponding native Hibernate properties. 064 * 065 * @author Juergen Hoeller 066 * @author Rod Johnson 067 * @since 2.0 068 * @see HibernateJpaDialect 069 * @see org.hibernate.ejb.HibernatePersistence 070 * @see org.hibernate.ejb.HibernateEntityManager 071 */ 072public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter { 073 074 private final HibernateJpaDialect jpaDialect = new HibernateJpaDialect(); 075 076 private final PersistenceProvider persistenceProvider; 077 078 private final Class<? extends EntityManagerFactory> entityManagerFactoryInterface; 079 080 private final Class<? extends EntityManager> entityManagerInterface; 081 082 083 @SuppressWarnings("unchecked") 084 public HibernateJpaVendorAdapter() { 085 ClassLoader cl = HibernateJpaVendorAdapter.class.getClassLoader(); 086 Class<? extends EntityManagerFactory> emfIfcToUse; 087 Class<? extends EntityManager> emIfcToUse; 088 Class<?> providerClass; 089 PersistenceProvider providerToUse; 090 try { 091 try { 092 // Try Hibernate 4.3/5.0's org.hibernate.jpa package in order to avoid deprecation warnings 093 emfIfcToUse = (Class<? extends EntityManagerFactory>) cl.loadClass("org.hibernate.jpa.HibernateEntityManagerFactory"); 094 emIfcToUse = (Class<? extends EntityManager>) cl.loadClass("org.hibernate.jpa.HibernateEntityManager"); 095 providerClass = cl.loadClass("org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider"); 096 } 097 catch (ClassNotFoundException ex) { 098 // Fall back to Hibernate 3.6-4.2 org.hibernate.ejb package 099 emfIfcToUse = (Class<? extends EntityManagerFactory>) cl.loadClass("org.hibernate.ejb.HibernateEntityManagerFactory"); 100 emIfcToUse = (Class<? extends EntityManager>) cl.loadClass("org.hibernate.ejb.HibernateEntityManager"); 101 providerClass = cl.loadClass("org.springframework.orm.jpa.vendor.SpringHibernateEjbPersistenceProvider"); 102 } 103 providerToUse = (PersistenceProvider) providerClass.newInstance(); 104 } 105 catch (Exception ex) { 106 throw new IllegalStateException("Failed to determine Hibernate PersistenceProvider", ex); 107 } 108 this.persistenceProvider = providerToUse; 109 this.entityManagerFactoryInterface = emfIfcToUse; 110 this.entityManagerInterface = emIfcToUse; 111 } 112 113 114 /** 115 * Set whether to prepare the underlying JDBC Connection of a transactional 116 * Hibernate Session, that is, whether to apply a transaction-specific 117 * isolation level and/or the transaction's read-only flag to the underlying 118 * JDBC Connection. 119 * <p>See {@link HibernateJpaDialect#setPrepareConnection(boolean)} for details. 120 * This is just a convenience flag passed through to {@code HibernateJpaDialect}. 121 * <p>On Hibernate 5.1/5.2, this flag remains {@code true} by default like against 122 * previous Hibernate versions. The vendor adapter manually enforces Hibernate's 123 * new connection handling mode {@code DELAYED_ACQUISITION_AND_HOLD} in that case 124 * unless a user-specified connection handling mode property indicates otherwise; 125 * switch this flag to {@code false} to avoid that interference. 126 * <p><b>NOTE: For a persistence unit with transaction type JTA e.g. on WebLogic, 127 * the connection release mode will never be altered from its provider default, 128 * i.e. not be forced to {@code DELAYED_ACQUISITION_AND_HOLD} by this flag.</b> 129 * Alternatively, set Hibernate 5.2's "hibernate.connection.handling_mode" 130 * property to "DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION" or even 131 * "DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT" in such a scenario. 132 * @since 4.3.1 133 * @see PersistenceUnitInfo#getTransactionType() 134 * @see #getJpaPropertyMap(PersistenceUnitInfo) 135 * @see HibernateJpaDialect#beginTransaction 136 */ 137 public void setPrepareConnection(boolean prepareConnection) { 138 this.jpaDialect.setPrepareConnection(prepareConnection); 139 } 140 141 142 @Override 143 public PersistenceProvider getPersistenceProvider() { 144 return this.persistenceProvider; 145 } 146 147 @Override 148 public String getPersistenceProviderRootPackage() { 149 return "org.hibernate"; 150 } 151 152 @Override 153 public Map<String, Object> getJpaPropertyMap(PersistenceUnitInfo pui) { 154 return buildJpaPropertyMap(this.jpaDialect.prepareConnection && 155 pui.getTransactionType() != PersistenceUnitTransactionType.JTA); 156 } 157 158 @Override 159 public Map<String, Object> getJpaPropertyMap() { 160 return buildJpaPropertyMap(this.jpaDialect.prepareConnection); 161 } 162 163 private Map<String, Object> buildJpaPropertyMap(boolean connectionReleaseOnClose) { 164 Map<String, Object> jpaProperties = new HashMap<String, Object>(); 165 166 if (getDatabasePlatform() != null) { 167 jpaProperties.put(Environment.DIALECT, getDatabasePlatform()); 168 } 169 else if (getDatabase() != null) { 170 Class<?> databaseDialectClass = determineDatabaseDialectClass(getDatabase()); 171 if (databaseDialectClass != null) { 172 jpaProperties.put(Environment.DIALECT, databaseDialectClass.getName()); 173 } 174 } 175 176 if (isGenerateDdl()) { 177 jpaProperties.put(Environment.HBM2DDL_AUTO, "update"); 178 } 179 if (isShowSql()) { 180 jpaProperties.put(Environment.SHOW_SQL, "true"); 181 } 182 183 if (connectionReleaseOnClose) { 184 // Hibernate 5.1/5.2: manually enforce connection release mode ON_CLOSE (the former default) 185 try { 186 // Try Hibernate 5.2 187 Environment.class.getField("CONNECTION_HANDLING"); 188 jpaProperties.put("hibernate.connection.handling_mode", "DELAYED_ACQUISITION_AND_HOLD"); 189 } 190 catch (NoSuchFieldException ex) { 191 // Try Hibernate 5.1 192 try { 193 Environment.class.getField("ACQUIRE_CONNECTIONS"); 194 jpaProperties.put("hibernate.connection.release_mode", "ON_CLOSE"); 195 } 196 catch (NoSuchFieldException ex2) { 197 // on Hibernate 5.0.x or lower - no need to change the default there 198 } 199 } 200 } 201 202 return jpaProperties; 203 } 204 205 /** 206 * Determine the Hibernate database dialect class for the given target database. 207 * @param database the target database 208 * @return the Hibernate database dialect class, or {@code null} if none found 209 */ 210 @SuppressWarnings("deprecation") 211 protected Class<?> determineDatabaseDialectClass(Database database) { 212 switch (database) { 213 case DB2: return DB2Dialect.class; 214 case DERBY: return DerbyDialect.class; // DerbyDialect deprecated in 4.x 215 case H2: return H2Dialect.class; 216 case HSQL: return HSQLDialect.class; 217 case INFORMIX: return InformixDialect.class; 218 case MYSQL: return MySQL5Dialect.class; 219 case ORACLE: return Oracle9iDialect.class; 220 case POSTGRESQL: return PostgreSQLDialect.class; // PostgreSQLDialect deprecated in 4.x 221 case SQL_SERVER: return SQLServer2008Dialect.class; 222 case SYBASE: return org.hibernate.dialect.SybaseDialect.class; // SybaseDialect deprecated in 3.6 but not 4.x 223 default: return null; 224 } 225 } 226 227 @Override 228 public HibernateJpaDialect getJpaDialect() { 229 return this.jpaDialect; 230 } 231 232 @Override 233 public Class<? extends EntityManagerFactory> getEntityManagerFactoryInterface() { 234 return this.entityManagerFactoryInterface; 235 } 236 237 @Override 238 public Class<? extends EntityManager> getEntityManagerInterface() { 239 return this.entityManagerInterface; 240 } 241 242}