Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ImprovedNamingStrategy no longer working in Hibernate 5

I have simple spring-jpa configuration where I have configured Hibernate's ImprovedNamingStrategy. This means if my entity class has a variable userName, then Hibernate should convert it to user_name for querying the database. But this naming conversion stopped working after I upgraded to Hibernate 5. I am getting the error:

ERROR: Unknown column 'user0_.userName' in 'field list'

This is my Hibernate config:

@Configuration @EnableJpaRepositories("com.springJpa.repository") @EnableTransactionManagement public class DataConfig {      @Bean     public DataSource dataSource(){         DriverManagerDataSource ds = new DriverManagerDataSource();         ds.setDriverClassName("com.mysql.jdbc.Driver");         ds.setUrl("jdbc:mysql://localhost:3306/test");         ds.setUsername("root");         ds.setPassword("admin");         return ds;     }       @Bean     public LocalContainerEntityManagerFactoryBean entityManagerFactory(){           HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();         vendorAdapter.setShowSql(Boolean.TRUE);         vendorAdapter.setDatabase(Database.MYSQL);          LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();         factory.setJpaVendorAdapter(vendorAdapter);         factory.setDataSource(dataSource());         factory.setPackagesToScan("com.springJpa.entity");           Properties jpaProperties = new Properties();          jpaProperties.put("hibernate.ejb.naming_strategy","org.hibernate.cfg.ImprovedNamingStrategy");         jpaProperties.put("hibernate.dialect","org.hibernate.dialect.MySQL5InnoDBDialect");          factory.setJpaProperties(jpaProperties);         factory.afterPropertiesSet();         return factory;     }      @Bean     public SharedEntityManagerBean entityManager() {         SharedEntityManagerBean entityManager = new SharedEntityManagerBean();         entityManager.setEntityManagerFactory(entityManagerFactory().getObject());         return entityManager;     }        @Bean     public PlatformTransactionManager transactionManager() {         JpaTransactionManager txManager = new JpaTransactionManager();         txManager.setEntityManagerFactory(entityManagerFactory().getObject());         return txManager;     }      @Bean     public ImprovedNamingStrategy namingStrategy(){         return new ImprovedNamingStrategy();     } } 

This is my Entity class:

@Getter @Setter @Entity @Table(name="user") public class User{      @Id     @GeneratedValue     private Long id;      private String userName;     private String email;     private String password;     private String role;  } 

I don't want to explicitly name my database fields within the @Column annotations. I want my configuration which can implicitly convert camel case to underscore.

Please guide.

like image 799
Anup Avatar asked Sep 07 '15 11:09

Anup


1 Answers

Thanks for posting your own solution. It helps me so much to set Hibernate 5 naming strategy!

The hibernate.ejb.naming_strategy property of pre-Hibernate 5.0 seems split into two parts:

  • hibernate.physical_naming_strategy
  • hibernate.implicit_naming_strategy

The values of these properties do not implement the NamingStrategy interface as did hibernate.ejb.naming_strategy. There are two new interfaces for these purposes:

  • org.hibernate.boot.model.naming.PhysicalNamingStrategy
  • org.hibernate.boot.model.naming.ImplicitNamingStrategy

Hibernate 5 provides only one implementation of PhysicalNamingStrategy (PhysicalNamingStrategyStandardImpl) that assumes physical identifier names are the same as logical ones.

There are several implementations of ImplicitNamingStrategy but I found none equivalent to the old ImprovedNamingStrategy. (See: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl)

So, I implemented my own PhysicalNamingStrategy which is very simple:

public class PhysicalNamingStrategyImpl extends PhysicalNamingStrategyStandardImpl implements Serializable {   public static final PhysicalNamingStrategyImpl INSTANCE = new PhysicalNamingStrategyImpl();   @Override  public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {      return new Identifier(addUnderscores(name.getText()), name.isQuoted());  }   @Override  public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {      return new Identifier(addUnderscores(name.getText()), name.isQuoted());  }    protected static String addUnderscores(String name) {      final StringBuilder buf = new StringBuilder( name.replace('.', '_') );      for (int i=1; i<buf.length()-1; i++) {         if (              Character.isLowerCase( buf.charAt(i-1) ) &&              Character.isUpperCase( buf.charAt(i) ) &&              Character.isLowerCase( buf.charAt(i+1) )          ) {              buf.insert(i++, '_');          }      }      return buf.toString().toLowerCase(Locale.ROOT);  } } 

Note that the addUnderscores() method is from the original org.hibernate.cfg.ImprovedNamingStrategy.

Then, I set this physical strategy into the persistence.xml file :

  <property name="hibernate.physical_naming_strategy" value="my.package.PhysicalNamingStrategyImpl" /> 

It is a trap to set Hibernate 5 naming strategy as previous version settings.

like image 151
Samuel Andrés Avatar answered Oct 03 '22 16:10

Samuel Andrés