Search code examples
javapostgresqljacksonjdbctemplate

Keep original type for certain fields when using ObjectMapper::convertValue()


I want to generate a Map object to be passed as argument to a NamedParameterJdbcTemplate::update() as second parameter from an existing POJO. One property is of type java.util.UUID.

@Builder
@Data
static class POJOObject {
  @Builder.Default
  @NonNull
  private UUID id = UUID.randomUUID();
  @NonNull
  private String data;
}

When this object is mapped with object mapper the given property is serialized to a String and the database operation fails.

var pojo = POJOObject.builder().data("something").build();
Map<String, Object> mapFromPojo = new ObjectMapper().convertValue(pojo, Map.class);
// this throws an exception 
namedParameterJdbcTemplate.update(
    "INSERT INTO pojo_table ( id, data ) VALUES ( :id, :data )",
    mapFromPojo
);
// this works
namedParameterJdbcTemplate.update(
    "INSERT INTO pojo_table ( id, data ) VALUES ( :id, :data )",
    ImmutableMap.of("id", pojo.getId(), "data", pojo.getData()
);

The PostgreSQL table is defined as follows:

CREATE TABLE pojo_table (
   id   UUID PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
   data TEXT NOT NULL
)

Is there a way to use the ObjectMapper so that the value's type of the id key is UUID instead of being serialized into a String? Or is there even another/better way to pass the data of POJOObject instance to the NamedParameterJdbcTemplate::update() call without manually adding field by field to a Map?


Solution

  • There is a solution, that I completely oversaw before: PostgreSQL Cast. To make it work, the SQL string needs to be modified to cast types and that way all properties of the map can be passed as Strings.

    With the POJOObject from above:

    var pojo = POJOObject.builder().data("something").build();
    
    // map can be all strings, when using postgreSQL cast on non-TEXT fields  
    namedParameterJdbcTemplate.update(
        "INSERT INTO pojo_table ( id, data ) VALUES ( :id::uuid, :data )",
        new ObjectMapper().convertValue(pojo, Map.class)
    );