I am writing application using postgresql database and spring + hibernate frameworks.
I upgraded spring framework from 4.1.5.RELEASE to 4.2.0.RELEASE version and upgraded hibernate framework from 4.3.7.Final to 5.0.0.Final version.
After upgrade I have problems with NamingStrategy. In postgresql database, table column names are in lowercase separated by underscore, in application layer, bean properties are in camelcase.
This is working spring configuration file for older version:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:component-scan base-package="fms" /> <bean id="microFmsDataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close"> <property name="driverClassName" value="org.postgresql.Driver" /> <property name="url" value="***" /> <property name="username" value="***" /> <property name="password" value="***" /> <property name="testOnBorrow" value="true" /> <property name="testOnReturn" value="true" /> <property name="testWhileIdle" value="true" /> <property name="validationQuery" value="select 1" /> <property name="initialSize" value="5" /> <property name="minIdle" value="10" /> <property name="maxIdle" value="100" /> <property name="maxActive" value="100" /> <property name="removeAbandoned" value="true" /> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="microFmsDataSource"/> <property name="packagesToScan"> <list> <value>fms</value> </list> </property> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" /> </property> <property name="jpaPropertyMap"> <map> <entry key="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider" /> <entry key="hibernate.hbm2ddl.auto" value="validate" /> <entry key="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" /> <entry key="hibernate.show_sql" value="true" /> <entry key="hibernate.format_sql" value="true" /> <entry key="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" /> </map> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
After upgrade I changed NamingStrategy configuration:
<entry key="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />
like this:
<entry key="hibernate.implicit_naming_strategy" value="***" />
and tried all variants of options listed in hibernate javadoc: https://docs.jboss.org/hibernate/orm/5.0/javadocs/org/hibernate/cfg/AvailableSettings.html#IMPLICIT_NAMING_STRATEGY
but with no success.
Can you tell me what is alternative of ImprovedNamingStrategy in Hibernate 5 and provide a working configuration example ?
Hibernate uses the Physical Naming Strategy to map our logical names to a SQL table and its columns. By default, the physical name will be the same as the logical name that we specified in the previous section. If we want to customize the physical names, we can create a custom PhysicalNamingStrategy class.
ImprovedNamingStrategy , which will convert the mixed case names to the embedded underscores name .
1. Overview Hibernate 5 provides two different naming strategies for use with Hibernate entities: an Implicit Naming Strategy and a Physical Naming Strategy. In this tutorial, we'll see how to configure those naming strategies to map entities to customized table and column names.
Hibernate maps field names using a physical strategy and an implicit strategy. We previously talked about how to work with the naming strategies in this tutorial. And, Spring Boot, provides defaults for both: We can override these values, but by default, these will: So, for example, an AddressBook entity would be created as the address_book table.
It first determines the logical name of an entity or attribute. You can explicitly set the logical name using the @Table and @Column annotations. If you don’t do that, Hibernate will use one of its implicit naming strategies. It then maps the logical name to a physical name. By default, Hibernate uses the logical name as the physical name.
The Spring Data JPA dependency brings in the Hibernate dependencies for us. 3. Spring Boot Naming Strategies Hibernate maps field names using a physical strategy and an implicit strategy. We previously talked about how to work with the naming strategies in this tutorial.
I think I found the solution.
To achieve my goal, I used hibernate.physical_naming_strategy
configuration, instead of hibernate.implicit_naming_strategy
.
I created an implementation of the PhysicalNamingStrategy
interface which simulates part of the functionality of the original ImprovedNamingStrategy
class:
package fms.util.hibernate; import org.apache.commons.lang.StringUtils; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.naming.PhysicalNamingStrategy; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; public class ImprovedNamingStrategy implements PhysicalNamingStrategy { @Override public Identifier toPhysicalCatalogName(Identifier identifier, JdbcEnvironment jdbcEnv) { return convert(identifier); } @Override public Identifier toPhysicalColumnName(Identifier identifier, JdbcEnvironment jdbcEnv) { return convert(identifier); } @Override public Identifier toPhysicalSchemaName(Identifier identifier, JdbcEnvironment jdbcEnv) { return convert(identifier); } @Override public Identifier toPhysicalSequenceName(Identifier identifier, JdbcEnvironment jdbcEnv) { return convert(identifier); } @Override public Identifier toPhysicalTableName(Identifier identifier, JdbcEnvironment jdbcEnv) { return convert(identifier); } private Identifier convert(Identifier identifier) { if (identifier == null || StringUtils.isBlank(identifier.getText())) { return identifier; } String regex = "([a-z])([A-Z])"; String replacement = "$1_$2"; String newName = identifier.getText().replaceAll(regex, replacement).toLowerCase(); return Identifier.toIdentifier(newName); } }
After I created this class, I changed my configuration from:
<entry key="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />
to this:
<entry key="hibernate.physical_naming_strategy" value="fms.util.hibernate.ImprovedNamingStrategy" />
and now everything works correctly.
This solution covers only small part of ImprovedNamingStrategy
. In my project, for table mapping and join mapping, I always specify the name of table or join column explicitly. I rely on implicit name conversion only for column names. So this simple solution was acceptable for me.
This is a full example of my Spring configuration file:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:component-scan base-package="fms" /> <bean id="microFmsDataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close"> <property name="driverClassName" value="org.postgresql.Driver" /> <property name="url" value="***" /> <property name="username" value="***" /> <property name="password" value="***" /> <property name="testOnBorrow" value="true" /> <property name="testOnReturn" value="true" /> <property name="testWhileIdle" value="true" /> <property name="validationQuery" value="select 1" /> <property name="initialSize" value="5" /> <property name="minIdle" value="10" /> <property name="maxIdle" value="100" /> <property name="maxActive" value="100" /> <property name="removeAbandoned" value="true" /> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="microFmsDataSource"/> <property name="packagesToScan"> <list> <value>fms</value> </list> </property> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" /> </property> <property name="jpaPropertyMap"> <map> <entry key="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider" /> <entry key="hibernate.hbm2ddl.auto" value="validate" /> <entry key="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" /> <entry key="hibernate.show_sql" value="true" /> <entry key="hibernate.format_sql" value="true" /> <entry key="hibernate.physical_naming_strategy" value="fms.util.hibernate.ImprovedNamingStrategy" /> </map> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
I hope this solution will be helpful for somebody. :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With