Different UserType for different database in Hibernate - spring

I'm developing an application in Spring Boot and Hibernate. I've created a class implementing UserType, which maps java.time.Duration to INTERVAL in PostgreSQL. Using it in following manner:
#TypeDefs({
#TypeDef(typeClass = DurationUserType.class, defaultForType = Duration.class)
}
works fine.
I'm running unit tests with H2. Since it doesn't support INTERVAL type, Hibernate fails at initialization with H2. I'm looking for the way to somehow associate DurationUserType with PostgreSQL dialect, so this it's not used in unit tests.

Related

Set Intellij IDEA JPA Console naming strategy

I have an all-default (excepts Lombok) Spring Boot 2.5.6 + PostgreSQL project with a very basic JPA mapping open in Intellij IDEA 2021.2.3. JPA configuration is implemented with annotations (no XML). The app itself works fine, records get saved and retrieved from the DB. In "Persistence" window I can see my JPA structure correctly, datasource is assigned. Here is the entity code:
#Entity
#Data
...
public class Cover {
...
private String ageRestriction;
}
But when I try to execute a query with e.g. select c from Cover c I get an error:
jpa-ql> select c from Cover c
[2021-11-01 16:14:03] [42703] ERROR: column cover0_.agerestriction does not exist
[2021-11-01 16:14:03] Hint: Perhaps you meant to reference the column "cover0_.age_restriction".
I tried to add the naming strategy configuration to my settings but this had no effect:
spring:
jpa:
hibernate:
naming:
physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
I don't see "Assign naming strategy" in the persistence unit context menu as well (see screenshot). Is there a way to force JPA Console to use the same naming strategy my app does?
PS: I've managed to make the console work after specifying #Column for all multi-word field names and adding #Table annotation with schema and name properties. But I would prefer to be able to sync console and app JPA/Hibernate configurations somehow.

Spring boot native query and JPA Repository

I would like to share all my project Repository interfaces with different database implementation (PostgreSQL, MySQL, ...), but having also some specific Repository with native query, for every db platform.
How can I achieve it? Is it possible to annotate a Repository to be used only with a specific database?
if you can not do it with annotations you could find out the dialect of the database and act accordingly.
an example
private boolean isOracle() {
Session session = (Session) entityManager.getDelegate();
Dialect dialect = ((SessionFactoryImpl) session.getSessionFactory()).getJdbcServices().getDialect();
return dialect.getClass().getName().contains("Oracle");
}
so if (isOracle()) you would use your oracleJpaNativeRepository

How does springboot JPA knows which database will be used?

I got to know Java spring JPA a couple days ago and there is one question which really makes me confused.
As I create a repository and use 'save()' method to save some objects into it. How does it know what type of database I am using and which local location to save.
I know I can config database (h2) like:
spring.datasource.url=jdbc:h2:mem/mydb
Then JPA will know: ok you are using h2 database and url is "jdbc:h2:mem/mydb"
However, some people said this config is not mandatory. If without this config, how does JPA knows which database I gonna use?
From the spring-boot documentation:
You should at least specify the URL by setting the spring.datasource.url property. Otherwise, Spring Boot tries to auto-configure an embedded database.
The following class is responsible for providing default settings for embedded DB: org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
public String determineDatabaseName() {
...
if (this.embeddedDatabaseConnection != EmbeddedDatabaseConnection.NONE) {
return "testdb";
}
...
}
This answer can also be helpful: Where does the default datasource url for h2 come from on Spring Boot?

Hibernate ColumnTransformer and DataJpaTest

I do have a mysql database. That database reads and writes by hibernate and uses field encryption. The application is running on spring boot.
#ColumnTransformer(
read = "AES_DECRYPT(message, 'secret')",
write = "AES_ENCRYPT(?, 'secret')"
)
#Column(
columnDefinition = "varbinary(5120)"
)
private String field;
When writing unit tests I get an exception because these test is running on embedded h2 and the encryption methods are mysql based.
#RunWith(SpringRunner.class)
#DataJpaTest
I found this solution, but it does not work for me: How to Ignore Certain Fields in unit tests, Hibernate
Is there any way to test this behaviour and ignoring encryption and decryption in test configuration?
regards,
Moritz

Testing Hibernate Mappings

I'm using Hibernate to map objects to a legacy schema which contains some ginormous tables via annotations (as XML files are so 2003). Since these classes are so large, yes I occasionally make an occasional typo, which Hibernate doesn't bother to tell me about until I try to run it.
Here's what I've tried:
One: Setting hbm2ddl.auto to "validate":
This causes the String values of the class to validate against varchar(255). Since many of the column types in the database are CHAR(n), this blows up. I would have to add the columnDefinition="CHAR(n)" to several hundred mappings.
Two: Using Unitils.
Importing these via Maven causes imports of dependency libraries which blow up other sections of code. Example: I'm using Hibernate 4.1, but Unitils imported Hibernate 3.2.5 and blew up a UserType.
So, is there another way to do this? I looked at the Unitils code to see if I could simply yank the sections I needed (I do that with apache-commons fairly often when I just need a single method), but that's not a simple task.
Hibernate is configured via a Spring application context.
Any ideas out there?
I would write tests against an in-memory database (HSQLDB, H2) using the Spring testing framework. You'll quickly see any mapping errors when you attempt to run queries against the tables.
The test class would look something like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=MyTestConfig.class)
#TransactionConfiguration(transactionManager="txMgr", defaultRollback=true)
public class MyTest {
#Autowired
private SessionFactory sessionFactory;
// class body...
}
I would configure Hibernate to auto-deploy the tables as part of the tests.

Resources