Mapping @Json property with JDBI

2.8k views Asked by At

According to JDBI document https://jdbi.org/#_jackson_2, it seems that it's quite straight forward to have a json property of your object model, however I've tried the following and it ran into many issues.

DB: Postgres with a column type of Jsonb

class Event {
    private String name;
    @Json
    private EventProperty jsonProperty;
    ...
}

Datasource has been configured with

    @Bean
    public Jdbi jdbi(TransactionAwareDataSourceProxy eventStoreTxAwareDataSourceProxy) {
        Jdbi jdbi = Jdbi.create(eventStoreTxAwareDataSourceProxy);
        jdbi.installPlugin(new PostgresPlugin());
        jdbi.installPlugin(new Jackson2Plugin());
    }

SQL for binding list of insertion

INSERT INTO event (name, json_property)
VALUES (
        :name,
        :jsonProperty)

When running the code to insert, the following error occurred:

org.jdbi.v3.core.statement.UnableToCreateStatementException: no argument factory for type com.EventProperty [statement:"INSERT INTO event (...]

If I created EventPropertyArgumentFactory and using Jackson ObjectMapper and writeValueAsString then I can save it to DB. However, when retrieving it back from DB by

 try (Handle handle = jdbi.open()) {
    EventDao dao = handle.attach(EventDao.class);
    return dao.findByName(name);
}

throws the following errors

java.lang.ClassCastException: Cannot cast org.postgresql.util.PGobject to com.EventProperty

I thought all I needed to do is declare the field annotated with @Json, the DB column has to be json/jsonb type and install the plugins, but seems like this is not the case?

Anyone has tried this successfully, without having to define custom row mapper and argument factory implementation?

Thanks

2

There are 2 answers

1
D. Mallon On

Not sure if you've figured this out by now but I just ran into this same issue and finally figured it out.

Basically, you just have to add the annotation on the getter or setter of the class, not the top-level field.

class Event {
    private String name;
    private EventProperty jsonProperty;
    ...

    @Json
    public getEventProperty() {
        return jsonProperty;
    }
}
0
Aleksandr Kravets On

The documentation says:

// use @Json qualifier:
...
// also works on bean or property-mapped objects:
class MyBean {
    private final MyJson property;
    @Json
    public MyJson getProperty() { return ...; }
}

I've checked and it's unfortunate but @Json only works when placed on a property( i.e. getter or setter) and not on a field.

You can make your work easier if you use Lombok library. Modify lombok.config file by adding this line:

lombok.copyableannotations += org.jdbi.v3.json.Json

Now in bean declaration you can do this:

@Data // will generate setters and getters among other things 
class Event {
    private String name;
    @Json // will be copied onto getter and setter due to config change we made
    private EventProperty jsonProperty;
    ...
}

Have fun!