Hibernate naming strategy - spring

I am building a REST webservice with Spring (Boot) and am trying to use hibernate as orm mapper without any xml configuration.
I basically got it to work, but I am stuck with a configuration issue.
I instantiate LocalContainerEntityManagerFactoryBean as #Bean in a #Configuration file.
I set hibernate.ejb.naming_strategy as in the following example -> this seems to work for creating the tables if they do not exist (column names are camelCase like in my #Entity classes) but when a query is executed, hibernate "forgets" about this naming configuration and tries to use another kind of naming strategy with under_score_attributes --> obviously those queries fail. Is there any other property I need to set?
Or another way of configuring the properties preferably without adding a cfg.xml or persistence.xml?
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
Properties props = new Properties();
props.put("hibernate.hbm2ddl.auto", "create");
props.put("hibernate.ejb.naming_strategy","org.hibernate.cfg.DefaultNamingStrategy");
lef.setJpaProperties(props);
lef.afterPropertiesSet();

HibernateJpaAutoConfiguration allows the naming strategy (and all other JPA properties) to be set via local external configuration. For example, in application.properties:
spring.jpa.hibernate.ddl_auto: create
spring.jpa.hibernate.naming_strategy: org.hibernate.cfg.EJB3NamingStrategy

Have you tried setting this particular property using programmatic properties? Or a hibernate.properties file in the package root? Or a JVM system property? All are described here.
From my experience, there are sometimes difficult to diagnose Hibernate problems if you insist on not using any XML (which would be my preference as well). If nothing else works, you may be forced to define a configuration file at least.

I got the solution now.
#EnableAutoConfiguration(exclude={HibernateJpaAuto Configuration.class})
The JpaAutoConfiguration must be excluded. Still I think this might be a bug, as normally it should automatically "stand back" when I use my own #Configuration.

Related

spring-integration: SplitterFactoryBean may only be referenced once

I have a Spring project (not using Spring Boot, if that's relevant) that I'm trying to connect to a local database using the Postgres JDBC driver. (The local database is actually Yugabyte, but that should be fully compatible with the Postgres driver.)
When starting the application, I get this error message:
java.lang.IllegalArgumentException: An AbstractMessageProducingMessageHandler may only be referenced once (org.springframework.integration.config.SplitterFactoryBean#0) - use scope="prototype"
at org.springframework.util.Assert.isTrue(Assert.java:118)
at org.springframework.integration.config.AbstractStandardMessageHandlerFactoryBean.checkReuse(AbstractStandardMessageHandlerFactoryBean.java:168)
at org.springframework.integration.config.AbstractStandardMessageHandlerFactoryBean.createHandler(AbstractStandardMessageHandlerFactoryBean.java:137)
at org.springframework.integration.config.AbstractSimpleMessageHandlerFactoryBean.createHandlerInternal(AbstractSimpleMessageHandlerFactoryBean.java:186)
at org.springframework.integration.config.AbstractSimpleMessageHandlerFactoryBean.getObject(AbstractSimpleMessageHandlerFactoryBean.java:174)
at org.springframework.integration.config.AbstractSimpleMessageHandlerFactoryBean.getObject(AbstractSimpleMessageHandlerFactoryBean.java:59)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:171)
... 52 more
I can't place this error at all. There is one similar question on Stack Overflow, but there the asker seems to actually know what they're doing and how this is related to spring integration. I, however, am not aware at all that I'm trying to 'reuse' anything. The referenced question also doesn't seem to be related to database configuration.
My setup/configuration is a bit involved, so I'll try to quote the parts that seem relevant.
I have a dao layer project that has the following gradle dependencies (among others):
implementation("org.springframework:spring-context:5.2.2.RELEASE")
implementation("org.springframework:spring-jdbc:5.2.2.RELEASE")
implementation("org.jooq:jooq-kotlin:3.14.11")
runtimeOnly("org.postgresql:postgresql:42.2.19.jre7")
In the same project, I have some configuration (in Kotlin):
#Configuration
open class Config {
#Bean
open fun jdbcTemplate(dataSource: DataSource): JdbcTemplate = JdbcTemplate(dataSource)
#Bean
open fun dslContext(): DSLContext = DefaultDSLContext(SQLDialect.POSTGRES)
#Configuration
#Profile("!unittest")
open inner class NonTestConfig {
#Bean
open fun dataSource(): DataSource {
return DriverManagerDataSource().apply {
// Hardcoded properties to be replaced by values from property file
setDriverClassName("org.postgresql.Driver")
url = "jdbc:postgresql://localhost:5433/demo"
username = "yugabyte"
password = "yugabyte"
}
}
}
}
(Notes: the DSLContext bean is used for JOOQL, included for completeness' sake. The inner class config is there because there is also a separate unit testing config for an embedded database - that one works fine!)
Now, the above project is used in my top-level project that contains the actual application. It's a maven runtime dependency there. I import the config class in this project's XML configuration, using this method:
<context:annotation-config />
<bean class="my.package.Config" />
Then trying to start the application produces the error message.
I figured out what the problem was, but I still don't know how it relates to a <splitter>.
The problem was that the Config class, apart from the database stuff, also included a bean to encrypt data. It turned out that this bean was also defined in another library used by the top-level project. Fixing this duplicate bean problem made the error go away.
I discovered this in a roundabout way: I included the dao project and its configuration in a different top-level project that uses Spring Boot. This led to a clear error message about the encryptor bean having two definitions.
If anyone can explain why the error message is so cryptic in the non-Boot case, that would be a nice complementary answer.

How to maintain, update application properties dynamically in Spring? [duplicate]

This question already has answers here:
How can I reload properties file in Spring 4 using annotations?
(3 answers)
Closed 6 years ago.
I would like to maintain a list of application properties like service endpoints, application variables, etc. in a Spring application. These properties should be able to updated dynamically (possibly through an web page by system administrator).
Does spring has an inbuilt feature to accomplish this requirement?
I am not sure spring has an implementation for updating the properties file dynamically.
You can do something like reading the properties file using FileInputStream into a Properties object. Then you will be able to update the properties. Later you can write back the properties to the same file using the FileOutputStream.
// reading the existing properties
FileInputStream in = new FileInputStream("propertiesFile");
Properties props = new Properties();
props.load(in);
in.close();
// writing back the properties after updation
FileOutputStream out = new FileOutputStream("propertiesFile");
props.setProperty("property", "value");
props.store(out, null);
out.close();
Externalizing properties, take a look here
Spring loads these properties which can be configured at runtime and accessed in your application in different ways.
Add your own implementation of a PropertySource to your Environment.
Warning: Properties used by #ConfigurationProperties and #Value annotations are only read once on application startup, so changing the actual property values at runtime will have no effect (until restarted).
I am not sure, but check if you can make use #ConfigurationProperties of Spring boot framework.
#ConfigurationProperties(locations = "classpath:application.properties", ignoreUnknownFields = false, prefix = "spring.datasource")
You can keep this application.properties file in you classpath
Change the properties in this file without redeploying the application
Java Experts - I am just trying to explore my view. Corrections are always welcome.
Edit - I read a good examples on #PropertySource here

Look up a dynamic property at run-time in Spring from PropertySourcesPlaceholderConfigurer?

Not sure of the best approach to this. We've created a jar that could be used by different projects. The other projects relying on this jar need to provide certain properties defined in one of their spring properties files. (Our jar shouldn't care what they name those property files.)
Using #Value("${some.prop}") works great for most properties, however we now have the requirement that the name of the property to look up is dynamic. For example:
int val = getSomeVal();
String propNeeded = foo.getProperty("foo."+val+".dynamic.prop");
Not sure what "foo" should be to get my access. I looked into injecting Environment, however from all my googling it looks like that will not load from an xml property-placeholder definition (even if defined as a bean def for PropertySourcesPlaceholderConfigurer.) You seem to have to use #PropertySource, yet my main config is an XML file so not sure how to get Environment to work. (I can't really go 'old skool' and look up the property file as a class path Resource either since I'm not aware of the name of the file the users defined.)
I don't mind making this particular Service class ApplicationContextAware, but if I did that how could I get access to the underlying PropertySourcesPlaceholderConfigurer ? which I would 'seem?' to need in order to get access to a property dynamically?
The other option is that I force users of the jar to declare a bean by a name that I can look up
<util:properties id="appProps" location="classpath:application.properties" />
And I then inject appProps as Properties and look up from there. I don't like this approach though since it forces the users of the library to name an file by a common id. I would think the best solution is to just get a handle in some way to the underlying PropertySourcesPlaceholderConfigurer in my service class... I'm just not sure how to do it?
Why doesn't Spring simply allow PropertySource to be defined some how via your XML config and then I could just inject Environment?
Thanks for any suggestions how to accomplish what I want.
You could have a ReloadableResourceBundleMessageSource declared to read from the same source as the PropertySourcesPlaceholderConfigurer. This way you could just #Autowire MessageSource (or make your bean implement MessageSourceAware) and use that to retrieve your properties.
Main reason for using ReloadableResourceBundleMessageSource is to retrieve I18N messages, so that would kind of hacky...

Spring Boot / Spring Data import.sql doesn't run Spring-Boot-1.0.0.RC1

I've been following the development of Spring Boot, and sometime between the initial version 0.0.5-BUILD-SNAPSHOT and the current version I am using 1.0.0.RC1 I am no longer running my import.sql script.
Here is my configuration for LocalContainerEntityManager and JpaVendorAdapter
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dataSource);
lef.setJpaVendorAdapter(jpaVendorAdapter);
lef.setPackagesToScan("foo.*");
return lef;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(true);
hibernateJpaVendorAdapter.setGenerateDdl(true);
hibernateJpaVendorAdapter.setDatabase(Database.POSTGRESQL);
return hibernateJpaVendorAdapter;
}
Interesting the hibernate.hbm2ddl.auto still seems to run, which I think is part of the definition of my SpringBootServletInitializer
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {
However, I also noticed that the tables generated no longer have underscores and changed their shape when generated?
However, that could be the result of updating my org.postgresql version like so:
Previously:
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.2-1004-jdbc41</version>
</dependency>
Now:
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.3-1100-jdbc41</version>
</dependency>
I also had to change pggetserialsequence to pg_get_serial_sequence to get the script to run at all from pgadmin?
I guess I'm confusing what's going on, but most importantly I want to get back to having my import.sql run.
I have been following the sample project: https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples/spring-boot-sample-data-jpa
And their import.sql isn't running either on 1.0.0-BUILD-SNAPSHOT
The import.sql script is a Hibernate feature I think (not Spring or Spring Boot). It must be running in the sample otherwise the tests would fail, but in any case it only runs if ddl-auto is set to create the tables. With Spring Boot you should ensure that spring.jpa.hibernate.ddl-auto is set to "create" or "create-drop" (the latter is the default in Boot for an embedded database, but not for others, e.g. postgres).
If you want to unconditionally run a SQL script, By default Spring Boot will run one independent of Hibernate settings if you put it in classpath:schema.sql (or classpath:schema-<platform>.sql where <platform> is "postgres" in your case).
I think you can probably delete the JpaVendorAdapter and also the LocalContainerEntityManagerFactoryBean (unless you are using persistence.xml) and let Boot take control. The packages to scan can be set using an #EntityScan annotation (new in Spring Boot).
The default table naming scheme was changed in Boot 1.0.0.RC1 (so nothing to do with your postgres dependency). I'm not sure that will still be the case in RC2, but anyway you can go back to the old Hibernate defaults by setting spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy.
Hey I came across similar issue. My sql script was not getting invoked initially. Then I tried renaming the file from "import.sql" to "schema.sql", it worked. May be give this a shot. My code can be found here - https://github.com/sidnan/spring-batch-example
In addition to what was already said, it's worth noting you can use the data.sql file to import/intialize data into your tables. Just put your data.sql into the root of the classpath (eg: if you're running a Spring Boot app, you put it in the src/main/resources path).
Like was said before, use it together with the property ddl-auto=create-drop, so that it won't crash trying to insert the existing data.
You can also set up which specific file to execute using the spring.datasource.data property. Check out more info here: http://docs.spring.io/spring-boot/docs/current/reference/html/howto-database-initialization.html
Note: the schema.sql mentioned before would contain the whole DB definition. If you want to use this, ensure that Hibernate doesn't try to construct the DB for you based on the Java Entities from your project. This is what de doc says:
If you want to use the schema.sql initialization in a JPA app (with
Hibernate) then ddl-auto=create-drop will lead to errors if Hibernate
tries to create the same tables. To avoid those errors set ddl-auto
explicitly to "" (preferable) or "none"

Generate schema in dropwizard-hibernate

I followed the tutorial for dropwizard and hibernate without problems. Now I have non trivial annotations in my entities, and I would like hibernate to generate the tables for me, and stuff like that.So, how can I change hibernate's configuration? Can I give it a hibernate.cfg.xml? If I can, do I have to set up the connection again?
I found this PR,
but it doesn't seem to be in the public release yet (no hibernateBundle.configure in my jars)
But maybe I'm looking for the wrong thing. So far, I'm just trying to set hibernate.hbm2dll.auto. After all, there might be an other way to enable hibernate table generation in Dropwizard... So, any help?
Thank you.
Edit: I approached the problem from another angle, to explicitly create the schema instead of using hbm2ddl.auto. See proposed answer.
Edit: Problem solved! Doing this in the YAML config currently works: (Dropwizard 0.7.1)
database:
properties:
hibernate.dialect: org.hibernate.dialect.MySQLDialect
hibernate.hbm2ddl.auto: create
(from this answer)
Old answer:
This is what I am currently using: A class that calls hibernate's SchemaExport to export the schema to a SQL file or to modify the database. I just run it after changing my entities, and before running the application.
public class HibernateSchemaGenerator {
public static void main(String[] args) {
Configuration config = new Configuration();
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
properties.put("hibernate.connection.url", "jdbc:mysql://localhost:3306/db");
properties.put("hibernate.connection.username", "user");
properties.put("hibernate.connection.password", "password");
properties.put("hibernate.connection.driver_class", "com.mysql.jdbc.Driver");
properties.put("hibernate.show_sql", "true");
config.setProperties(properties);
config.addAnnotatedClass(MyClass.class);
SchemaExport schemaExport = new SchemaExport(config);
schemaExport.setOutputFile("schema.sql");
schemaExport.create(true, true);
}
}
I didn't know about hibernate tools before. So this code example can be used in the service initialization to act like hbm2ddl.auto = create.
I'm currently using it just by running the class (from eclipse or maven) to generate and review the output SQL.

Resources