Spring Framework 4.2 will add support for Hibernate 5 which will lead to auto-configuration updates on our side.
With a pure JPA-based implementation, it looks like we don't have to do anything. Let's reopen if we think we need to change something.
Actually, Hibernate 5 has a breaking change regarding the naming strategy support so we should at least track that.
The new naming strategy seems to create a regression as documented here:
https://hibernate.atlassian.net/browse/HHH-9908
Maybe due to this deprecated call:
2015-08-15 09:28:43.818 WARN 28766 --- [ main] org.hibernate.orm.deprecation : HHH90000006: Attempted to specify unsupported NamingStrategy via setting [hibernate.ejb.naming_strategy]; NamingStrategy has been removed in favor of the split ImplicitNamingStrategy and PhysicalNamingStrategy; use [hibernate.implicit_naming_strategy] or [hibernate.physical_naming_strategy], respectively, instead.
I've tested with spring boot 1.3.0.RC1 and I still get the same warning.
Also, when autogenerating tables I see each row two times for each table, maybe there is something suboptimal there too?
2015-10-21 16:24:57.195 INFO 31799 --- [ main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: ab
2015-10-21 16:24:57.196 INFO 31799 --- [ main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: ab
2015-10-21 16:24:57.305 INFO 31799 --- [ main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: ablabel
2015-10-21 16:24:57.306 INFO 31799 --- [ main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: ablabel
2015-10-21 16:24:57.416 INFO 31799 --- [ main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: account
2015-10-21 16:24:57.417 INFO 31799 --- [ main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: account
What worries me is using a naming strategy that will change when that problem will be fixed, and hence render uncompatible the autogenerated schema
I think the main problem is that the Hibernate team has no concrete answer for that either. If you look at the naming strategy we have for 4.3, it's basically org.hibernate.cfg.ImprovedNamingStrategy
and there is no counter part in 5.0. As far as I understand, the one that is closer is org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
and there is legacy in the name.
If you are relying on that naming strategy (with the little fix that we have added in SpringNamingStrategy
) I am afraid it's more an hibernate migration problem than a Spring Boot problem.
I tried to use Hibernate5 with spring-boot-1.3.RC1
for leveraging Oracle12cDialect
and native java.time
support. It took me quite some time (and pain) to figure it out. The main problem was related to the naming strategy problematic. The things that worked really good was just setting spring.version
and hibernate.version
in my gradle.properties
file and add dependency org.hibernate:hibernate-java8
. Libraries were pulled in correctly, no classpath issues.
Then I removed all the Jadira stuff and tried to start to app. Bang. The problem is that the NamingStrategy
from configuration key spring.jpa.hibernate.naming-strategy
from the HibernateJpaAutoConfiguration
class has no effect, as the according Hibernate property has been deprecated. You may also see:
https://jira.spring.io/browse/DATAJPA-777
Hibernate5 now uses two types of naming strategies (org.hibernate.boot.model.naming.ImplicitNamingStrategy
& org.hibernate.boot.model.naming.PhysicalNamingStrategy
). In order to still leverage Hibernate autoconfiguration, I had to add the following bean definition to my application context:
@Bean
@Primary
public static JpaProperties jpaProperties() {
final Map<String, String> hibernateConfig = newHashMap();
hibernateConfig.put("hibernate.implicit_naming_strategy",
"org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl");
hibernateConfig.put("hibernate.physical_naming_strategy",
"com.anyapp.CustomNamingStrategy");
final JpaProperties jpaProperties = new JpaProperties();
jpaProperties.setProperties(hibernateConfig);
jpaProperties.setDatabase(ORACLE);
jpaProperties.setDatabasePlatform(ORACLE12C_DIALECT);
jpaProperties.setGenerateDdl(false);
jpaProperties.setShowSql(false);
return jpaProperties;
}
Therefore I am loosing spring.jpa.*
configuration from the application.yml
which is no big point here, as I do not really need it to be configurable here. If so I could inject the values into the bean factory method.
The most annoying part was to find out which naming strategies to apply in what way and the fact that I had to implement CustomNamingStrategy
on my own, as Hibernate does not provide a PhysicalNamingStrategy
that matches the naming of legacy ImprovedNamingStrategy
.
The custom naming strategy is nearly the same as here...
http://stackoverflow.com/questions/32165694/spring-hibernate-5-naming-strategy-configuration
... just replaced the regex stuff with Guava's CaseFormat
.
The CustomNamingStrategy
is just a simple implementation. A verified solution by Spring(-Boot) team is highly appreciated.
Hope this helps getting Hibernate5 compat into 1.3.
Another helper may be:
http://stackoverflow.com/questions/31358356/how-to-migrate-a-hibernate-namingstrategy-to-implicitphysicalnamingstrategy
Thanks for the detailed analysis. We know about the naming strategy (see the comments before yours).
I am not sure I understand why you have tot hack JpaProperties
like that but if you want to keep support for spring.jpa.*
you simply need to add @ConfigurationProperties
to your custom bean definition. That is:
@Bean
@Primary
@ConfigurationProperties(prefix = "spring.jpa")
public static JpaProperties jpaProperties() {
...
}
I overwrote the bean in order to be able to specify the new naming strategy key names:
hibernate.implicit_naming_strategy
hibernate.physical_naming_strategy
As I understand, they would not be applied by HibernateJpaAutoConfiguration
or is there some kind of lax binding I am overlooking.
If I can achieve that from application.yml
, it would be my preferred way.
Well either do what I wrote above (have you seen it?) or ditch your override and add this to your config
spring:
jpa:
properties:
hibernate.implicit_naming_strategy: xyz
hibernate.physical_naming_strategy: abc
That works. Thats a lot.
It looks like there is some issue with Hiberante 5 and Devtools as well.
Hibernate 5 recently added support for joining on unrelated entities, https://hibernate.atlassian.net/plugins/servlet/mobile#issue/hhh-16.
From this ticket it looks like support will be added to boot in version 1.4.0, is this correct?
The title of the issue is "Support for Hibernate 5"(.0) and the milestone is 1.4.0.M2
so I am not sure what your question is. Are you worried we won't support 5.1 or something?
Sorry, I was viewing the mobile version of this site and it seemed to state that this ticket was removed from 1.4M2, I'm just looking to track this issue and am also looking forward to using hibernate 5.x within boot.
I've been facing inconsistence issue when running test on hibernate 5.0.x. On hibernate 4.3.x my test always pass as expected, but after upgrade hibernate version, my test cases always fail.
Here are my detailed question on stackoverflow
In reference to the use of the new naming strategy properties in hibernate 5, I had trouble with:
spring.jpa.properties.hibernate.implicit_naming_strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl
I was seeing the warning about the use of the deprecated hibernate.naming-strategy
usage.
Looking at org.springframework.boot.autoconfigure.orm.jpa.JpaProperties
class, I could see why.
What worked for me in my spring applicaton.properties
file was these two lines:
spring.jpa.properties.hibernate.implicit_naming_strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl
spring.jpa.properties.hibernate.ejb.naming_strategy_delegator=
Setting hibernate.ejb.naming_strategy_delegator
to an empty value bypassed some of the logic in JpaProperties
that was causing the warning and preventing usage of the new strategies.
I've added a proposal in ca023b5 (which is mainly dealing with the naming strategy) and I've also extended the support by "fixing" our test suite to work _also_ with Hibernate 5 (see f3c3119). If you take the state of that branch you can build with -Dhibernate.version=5.0.9.Final
. We're not promoting Hibernate 5 by default just yet.
Most of these changes are due to the naming strategy change. Maybe we shouldn't rely on default column names after all?
I think this is basically fixed but I'm leaving it open for team discussion and because we'll need some release notes. The plan is:
SpringNamingStrategy
is deprecated because it's no longer used.ImplicitNamingStrategy
because Hibernate's defaults are very close to (if not identical) to Spring Boot 1.3 defaults.SpringPhysicalNamingStrategy
to restore lowercase/underscore sanity to names.hibernate.id.new_generator_mappings
to false
on Hibernate 5 so that people can upgrade easily. We might want to change this default in Spring Boot 2.0 but I don't think we should for 1.4I like @philwebb's plan. We're already using Hibernate 5.1 due to bug with 4.3's component path naming strategy that is fixed in 5.1.
This will make us upgrading to boot 1.4 easily. And we always use the component-path physical naming strategy anyway.
We need to not deprecate SpringNamingStrategy
I tried to upgrade to spring boot 1.4.0M2 my app that is using 1.3.x where I was already using hibernate5 but a new naming strategy was adopted and all my tables were modified (and of course everything stopped working).
Which configuration options must I set to revert back to the old strategy?
@Polve check the release notes
I am not sure I understand what you mean here. Upgrading to Spring Boot will not modify your tables. We didn't support Hibernate 5 previously so if you were specifying an implicit or physical strategy before, you should have done so in your own code. The alternative is that you were using Hibernate 5 default and those breaks compared to what you can experience with Boot and Hibernate 4.3.
The easiest way to know which properties are available is to use the auto-completion in your IDE or check the appendix.
But the problem I'm having is exactly that by upgrading from Hibernate 5.1+spring boot 1.3 to hibernate 5.1+spring boot 1.4M2 the naming strategy changed substantially and a field named "twoWords" is now mapped to "two_words", breaking havoc on the application.
I understand this is related to the new physical-strategy and implicit-strategy handling, the problem being that I'm unable to find any documentation on what are the correct values for those fields to restore the old behaviour (the default used in boot 1.3).
@Polve I think there is a misunderstanding of what the issue is. You were using Hibernate 5 _before_ we actually support it so you got the default Hibernate 5 provides. These breaks compared to Hibernate 4 with Spring Boot. What we did is making sure that those who are upgrading can do so safely (If you take Hibernate 4 and Spring Boot, you'll get two_words
not twoWords
).
If you want to stick with the default Hibernate 5 provides, just configure the naming strategy accordingly:
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
the old behaviour (the default used in boot 1.3).
Just to make that clear, this is the hibernate 5 default that you got by using it _before_ we actually support it. It's not something that we changed, we didn't support it before. I hope that clarifies.
@snicoll https://docs.spring.io/spring-boot/docs/1.4.0.M2/reference/html/common-application-properties.html states:
spring.jpa.hibernate.naming.physical-strategy= # Hibernate 5 physical naming strategy fully qualified name.
spring.jpa.hibernate.naming.strategy= # Hibernate 4 naming strategy fully qualified name. Not supported with Hibernate 5.
which means the _default_ physical strategy is empty, which _should_ mean Hibernate's default, _not_ Spring Boot's.
If Spring Boot 1.4 specifies a physical strategy, the appendix should mention it to be clear.
Same goes for Hibernate4's naming.strategy, since Spring Boot specifies the SpringNamingStrategy
this should be mentioned in the appendix.
So even if the behavior is "by design", I think there's a documentation bug here.
Thanks @snicoll for the details: that was exactly what I was looking for.
I agree with @ceefour : I got confused because I thought I was using hibernate's default, that's why by already using hibernate 5.1 on boot 1.3 I expected to work the same way with boot 1.4.
Thanks to both for the valuable infos.
@ceefour we can't document everything in the appendix. There is an algorithm to figure out what to do there and it's documented in the release notes. Granted, we should add that to the doc but simply putting the value in the appendix does not reflect what's happening either.
Please don't use the appendix to attempt to figure out what happens.
which means the default physical strategy is empty, which should mean Hibernate's default, not Spring Boot's.
There are many places where we compute the default based on the environment and we can't write "a default " because it simply does not exist. Don't take the shortcut of no-value in the appendix == no default.
@snicoll After reading the release notes I guess the behavior is the following as Spring Boot's defaults:
spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy # Hibernate 5 physical naming strategy fully qualified name.
spring.jpa.hibernate.naming.strategy=org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy # Hibernate 4 naming strategy fully qualified name. Not supported with Hibernate 5.
Other properties mention their defaults, e.g.:
server.port=8080 # Server HTTP port.
I don't understand why Spring Boot's naming strategy defaults can't be mentioned in the appendix. Leaving it empty as it is now is even more confusing.
No it's not. I think I already explained why above so I am afraid I am out of arguments here. We only set the latter if you're running Hibernate 4 (otherwise it's not set at all). The former is only set if you haven't set it any other way (including via spring.jpa.properties.hibernate.physical-naming-strategy
). This is too much information to write in there, sorry. And I still think trying to understand how things work by _only_ looking there is broken.
For reference, this commit updates the documentation. I've also updated the release notes based on your feedback.
Is there a way for a user to apply the SpringNamingStrategy in SpringBoot 1.3.x with latest Hibernate so as to have it already compatible when upgrading to 1.4.x?
Does adding
spring.jpa.hibernate.naming.strategy=org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy
work for 1.3.x?
No it doesn't, that file is compiling against the Hibernate 5 API. The whole point of that effort is that migrating from Hibernate 4 (1.3) to Hibernate 5 (1.4) is painless if you're using our naming strategy. Have you actually noticed that's not compatible?
We want to use hibernate 5 with spring boot 1.3.x and want to have the same naming as hibernate 4.3 as 1.4.x isn't available and don't want to run into any issues when upgrading to 1.4.x.
We don't officially support H5 in 1.3.x so I am afraid I have nothing to suggest. You could copy the naming strategies but you'll need to setup that manually in 1.3.x.
Thanks. That's sufficient :)
On a related note, you may be interested in adding something about this to the docs:
Using DefaultComponentSafeNamingStrategy
was very common in older versions of Hibernate to avoid having to use excessive AttributeOverrides
Most helpful comment
I think this is basically fixed but I'm leaving it open for team discussion and because we'll need some release notes. The plan is:
SpringNamingStrategy
is deprecated because it's no longer used.ImplicitNamingStrategy
because Hibernate's defaults are very close to (if not identical) to Spring Boot 1.3 defaults.SpringPhysicalNamingStrategy
to restore lowercase/underscore sanity to names.hibernate.id.new_generator_mappings
tofalse
on Hibernate 5 so that people can upgrade easily. We might want to change this default in Spring Boot 2.0 but I don't think we should for 1.4