Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

spring - hibernate 5 naming strategy configuration

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 ?

like image 317
Yoh0xFF Avatar asked Aug 23 '15 10:08

Yoh0xFF


People also ask

What is Spring JPA Hibernate naming strategy?

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.

What is ImprovedNamingStrategy?

ImprovedNamingStrategy , which will convert the mixed case names to the embedded underscores name .

What are the different naming strategies in hibernate?

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.

How does hibernate map field names in Spring Boot?

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.

How does hibernate decide the logical name of an entity?

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.

What is spring data JPA hibernate?

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.


1 Answers

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. :)

like image 122
Yoh0xFF Avatar answered Oct 04 '22 01:10

Yoh0xFF