When using Spring Data JDBC and PostgreSQL, we may need to store key-value pairs in a JSONB
column.
Let's take an example from one of my previous posts and modify it so that the extras
field does not have nested objects, but rather simple key-value pairs:
{
"friend": {
"fullName": "Anthony Edward Stark",
"alias": "Iron Man",
"extras": {
"publisher": "Marvel Comics",
"createdBy": "Stan Lee"
}
}
}
We could use the Map<String, String?>?
type for the extras
field in the entity...
@Table("friends")
class FriendsEntity(
//...
val extras: Map<String, String?>?,
) : Persistable<UUID> {
//...
}
...and the JSONB
type for the database column:
create table friends
(
-- ...
extras JSONB
);
Now, if we try to create an entity in the database, we get an error:
DEBUG o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [INSERT INTO "friends" ("alias", "extras", "full_name", "id", "superpower") VALUES (?, ?, ?, ?, ?)]
TRACE o.s.jdbc.core.StatementCreatorUtils : Setting SQL statement parameter value: column index 1, parameter value [Iron Man], value class [java.lang.String], SQL type 12
TRACE o.s.jdbc.core.StatementCreatorUtils : Setting SQL statement parameter value: column index 2, parameter value [{"publisher":"Marvel Comics","createdBy":"Stan Lee"}], value class [org.postgresql.util.PGobject], SQL type 12
...
ERROR o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.data.relational.core.conversion.DbActionExecutionException: Failed to execute InsertRoot{entity=dev.pfilaretov42.spring.data.jdbc.jsonb.entity.FriendsEntity@2f97ec4e, idValueSource=PROVIDED}] with root cause
org.postgresql.util.PSQLException: ERROR: column "extras" is of type jsonb but expression is of type character varying
For some reason, StatementCreatorUtils
treats a Map
as a String
:
value class [org.postgresql.util.PGobject], SQL type 12
To fix this, we have to change the map value type from String?
to Any?
:
@Table("friends")
class FriendsEntity(
//...
val extras: Map<String, Any?>?,
) : Persistable<UUID> {
//...
}
Please let me know in the comments if you know how to fix this another way and use Map<String, String?>?
.
The full source code is available on GitHub: pfilaretov42/spring-data-jdbc-jsonb.
Dream your code, code your dream.