Hibernate Envers audit Table Column Changes from jsonb to uuid - spring

I have a jsonb column in an Entity annotated as shown in the sample code. Everything works fine without the #Audited annotation. Adding the Audited annotation creates the org_master_aud table with the column custom_fields of type uuid instead of jsonb and the insert fails
#TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
#Audited
public class OrgMaster {
#Type(type = "jsonb")
#Column(columnDefinition = "jsonb",name="custom_fields",nullable=false)
private JsonNode customFields;
}
org.springframework.orm.jpa.JpaSystemException: Unable to perform beforeTransactionCompletion callback: org.hibernate.exception.DataException: could not execute statement; nested exception is org.hibernate.HibernateException: Unable to perform beforeTransactionCompletion callback: org.hibernate.exception.DataException: could not execute statement
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:353)
.
.
.
.
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1352)
... 94 more
Caused by: org.postgresql.util.PSQLException: ERROR: invalid input syntax for type uuid: "{}"
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2578)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2313)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:331)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:448)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:369)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:159)
at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:125)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
... 105 more
Find below the Snapshots of the custom_fields column in main and audit table where the audit table column is uuid whereas the main table is jsonb. Both are autogenerated.

This issue was resolved after updating the hibernate version from 5.4.12.Final to 5.4.14.Final.
This was a bug introduced in versions > 5.4.10 and was fixed in 5.4.14. Here is the link to jira issue.
https://hibernate.atlassian.net/browse/HHH-13886

Related

Wrong column type after upgrading from Hibernate Spatial 5.4.3 to 5.6.9

We're trying to upgrade Hibernate and Hibernate Spatial from version 5.4 to 5.6 (we're using MySQL 5.6) but when starting our Spring Boot application (running spring boot 2.7.0) we run into the following exception:
Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: wrong column type encountered in column [my_polygon] in table [my_table]; found [geometry (Types#BINARY)], but expecting [polygon (Types#ARRAY)]
at org.hibernate.tool.schema.internal.AbstractSchemaValidator.validateColumnType(AbstractSchemaValidator.java:167)
at org.hibernate.tool.schema.internal.AbstractSchemaValidator.validateTable(AbstractSchemaValidator.java:151)
at org.hibernate.tool.schema.internal.GroupedSchemaValidatorImpl.validateTables(GroupedSchemaValidatorImpl.java:42)
at org.hibernate.tool.schema.internal.AbstractSchemaValidator.performValidation(AbstractSchemaValidator.java:97)
at org.hibernate.tool.schema.internal.AbstractSchemaValidator.doValidation(AbstractSchemaValidator.java:76)
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:204)
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:85)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:335)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:471)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1498)
at org.hibernate.jpa.HibernatePersistenceProvider.createContainerEntityManagerFactory(HibernatePersistenceProvider.java:141)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409)
... 195 common frames omitted
MyTable is defined like this:
#Entity
public class MyTable {
#Type(type = "jts_geometry")
#Column(name = "my_polygon", columnDefinition = "polygon")
public Polygon myPolygon;
// Other properties
}
I've tried removing the #Type annotation altogether but I still get the same error. How can I make this work?
I actually got it working by changing columnDefinition from polygon to geometry:
#Entity
public class MyTable {
#Type(type = "jts_geometry")
#Column(name = "my_polygon", columnDefinition = "geometry")
public Polygon myPolygon;
// Other properties
}

Trying to reuse Spring JdbcTemplate connection for Postgres JDBC copyIn - getting 'relation does not exist'

I've hit a brick wall in a Spring/Kotlin/JDBC/Postgres project and am hoping the community can help.
What I'm Trying To Do
Use Spring JDBC API (JdbcTemplate) to create a temporary table (temporary_pokemon) in a Postgres database.
Unwrap the JDBC connection from the JdbcTemplate so I can use the same connection to load a CSV into the database using the Postgres JDBC driver's copyIn method (https://jdbc.postgresql.org/documentation/publicapi/org/postgresql/copy/CopyIn.html)
What Is Going Wrong
The copyIn method errors with the message relation "temporary_pokemon" does not exist, and my assumption here is that the unwrapped connection is somehow separate/different to the db.execute command which creates the table.
Ideally there's a way to re-use the same connection while still being able to rely largely on Spring Boot's autoconfiguration and things like automatic connection pooling, etc.
What I've Tried So Far
Adding the #Transactional annotation
Creating a DataSource manually using Spring Boot's DataSourceBuilder (this seems to work, I am assuming that it only creates a single connection which gets reused)
The error message
Caused by: org.postgresql.util.PSQLException: ERROR: relation "temporary_pokemon" does not exist
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2553) ~[postgresql-42.2.18.jar:42.2.18]
at org.postgresql.core.v3.QueryExecutorImpl.processCopyResults(QueryExecutorImpl.java:1212) ~[postgresql-42.2.18.jar:42.2.18]
at org.postgresql.core.v3.QueryExecutorImpl.startCopy(QueryExecutorImpl.java:894) ~[postgresql-42.2.18.jar:42.2.18]
at org.postgresql.copy.CopyManager.copyIn(CopyManager.java:45) ~[postgresql-42.2.18.jar:42.2.18]
at org.postgresql.copy.CopyManager.copyIn(CopyManager.java:177) ~[postgresql-42.2.18.jar:42.2.18]
at org.postgresql.copy.CopyManager.copyIn(CopyManager.java:160) ~[postgresql-42.2.18.jar:42.2.18]
at com.example.demo.IngestPostgres.ingest(IngestPostgres.kt:32) ~[main/:na]
at com.example.demo.IngestPostgres$$FastClassBySpringCGLIB$$f1321c17.invoke(<generated>) ~[main/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.2.jar:5.3.2]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771) ~[spring-aop-5.3.2.jar:5.3.2]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.2.jar:5.3.2]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.3.2.jar:5.3.2]
... 14 common frames omitted
Code Snippets
My #Component for the CommandLineRunner:
#Component
class Seed : CommandLineRunner {
#Autowired
lateinit var ingester : IngestPostgres
override fun run(vararg args: String?) {
val buffer = BufferedReader(FileReader(File("src/main/resources/ingest.csv")))
ingester.ingest(buffer)
}
}
The IngestPostgres #Component:
#Component
class IngestPostgres {
#Autowired
private lateinit var db: JdbcTemplate
#Transactional
fun ingest(bufferedReader: BufferedReader) {
db.execute("""
DROP TABLE IF EXISTS temporary_pokemon;
CREATE TABLE temporary_pokemon (
pokemon_id INT,
pokemon_name VARCHAR,
pokemon_type VARCHAR
);
""".trimIndent())
val pgConnection = db.dataSource?.connection?.unwrap(PgConnection::class.java)!!
CopyManager(pgConnection).copyIn(
"COPY temporary_pokemon FROM stdin DELIMITER ',' CSV HEADER",
bufferedReader
)
// snipped - later code INSERTS contents of temporary_pokemon into main pokemon table
}
}
My dependencies in build.gradle.kts:
dependencies {
implementation("org.springframework.boot:spring-boot-starter-jdbc")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.postgresql:postgresql")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
Thanks for any help. I'm not an expert at Spring/JDBC by any means, so apologies in advance if I've missed something that's common knowledge. I've tried searching on SO and Google but to no avail.
Seems like your queries use different connections. So results of first query are not committed when the second query starts. You can get a single connection and use it for execution of both queries or use JdbcTemplate api for importing csv data to your table

Getting Postgres Table Not Found Error with #ReadOnly Annotation in Spring Boot

I am getting the error PSQLException: ERROR: relation "schema.tableName" does not exist.
I have a GET API in spring which fetches data from a table. This API internally uses a custom method to access data using JpaReporitory. This custom method is annotated with #ReadOnly and #Transactional annotations since this API only fetches data from table. This gives me the table not found error.
But when I remove the #ReadOnly annotation, the API works just fine.
Below are the signatures of the said API and the custom method that it uses:
API:
#GetMapping("/houses/{houseId}/furnitures")
public List<Furnitures> getFurnitureslist(#PathVariable("houseId") long houseId) throws InterruptedException, ExecutionException {
return this.houseService.getFurnituresList(houseId);
}
Custom method:
#Transactional
#ReadOnly
public List<Asset> getTripPicklist(long tripId){
//Bunch of read operations using jpa repository.
}
This gives me an error trace as below:
org.springframework.orm.jpa.JpaSystemException: org.hibernate.exception.SQLGrammarException: could not extract ResultSet; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
Caused by: org.postgresql.util.PSQLException: ERROR: relation "schema.tableName" does not exist
But when I remove the #ReadOnly annotation from my custom method, the API works fine and I am able fetch the expected results from the database. What am I doing wrong?

LocalDateTime mapped to Oracle DATE, but not to H2 DATE

Let's say I have JPA #Embeddable:
#Embeddable
public class SpecificationValidity {
#Column(name = "VALID_FROM", nullable = false)
private final LocalDateTime validFrom;
#Column(name = "VALID_TO")
private final LocalDateTime validTo;
}
SQL table contains columns VALID_FROM and VALID_TO and is declared using liquibase changeset as follows:
<column name="VALID_FROM" type="date">
<constraints nullable="false"/>
</column>
<column name="VALID_TO" type="date"/>
When I run this code against Oracle database, everything works.
When I run it against H2 database, Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: wrong column type encountered in column [valid_from] in table [specification]; found [date (Types#DATE)], but expecting [timestamp (Types#TIMESTAMP)]
Why is it?
Is it possible to have consistent mapping for both dbms?
I assume you use Hibernate(from your exception message). Since you are using java 8 or above, you might need to add this to your dependency for hibernate 5.0.x.
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-java8 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-java8</artifactId>
<version>5.3.7.Final</version>
</dependency>
This helps to convert to and fro from Java 8 types to JPA known types. In this case it allows LocalDateTime LocalDate and Instant etc.,
I'm putting out the mapping that comes along(referred in the article as well).
A reference article : Hibernate + java 8 datetime
P.S : For Hibernate 5.2x and above no need for this explicit dependency.
http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#basic-datetime

OpenJPA PersistenceException: java.lang.Boolean cannot be cast to java.lang.Integer

In my Oracle database I have a column IS_ID of type NUMBER which I use for storing boolean values (0,1). The corresponding entity class declares the field:
#Column(name="IS_ID")
private Integer isId;
Fetching the entity class results in an exception being thrown:
org.apache.openjpa.persistence.PersistenceException: java.lang.Boolean cannot be cast to java.lang.Integer
While debugging the code I found out that the field is actually fetched as Boolean from the database. Why is this happening? My container is ServiceMix 5.3.0 with OpenJPA version 2.3.0

Resources