Is there a way to bind a java Map<String, Object>
to a varchar in the the JDBI @BindBean annotation.
So for example I have a class Something.class
and I create a
@SqlBatch("INSERT INTO Something (name, payload) VALUES(:name, :payload)")
.
Now in my java class the name
is of type String
and payload
is of type Map<String, Object>
and I want in the DB table the types are varchar(...)
. Now I want the Map
object to be inserted in the column as a JSON object, is that somehow achievable wihtout creating my own complex Binder as defined in http://jdbi.org/sql_object_api_argument_binding/ ? and other than making my payload be of type String in java.
Fixed my problem with creating an ArgumentFactory binder suggested in this post.
So what I needed was to create a class that just contained one field of type Map<String, Object>
implemented the Arugment
interface from org.skife.jdbi.v2.tweak
so I ended up with the following
public class NotificationPayloadArgument implements Argument {
private NotificationPayload payload;
NotificationPayloadArgument(NotificationPayload payload) {
this.payload = payload;
}
@Override
public void apply(int i, PreparedStatement preparedStatement, StatementContext statementContext)
throws SQLException {
preparedStatement.setString(i, toString());
}
@Override
public String toString() {
return new JSONObject(payload).toString();
}
}
To make this work I of course needed to implement a Factory class which implements the org.skife.jdbi.v2.tweak.ArgumentFactory<T>
interface with my newly created type, so the factory ended up as such:
public class NotificationPayloadFactory implements ArgumentFactory<NotificationPayload> {
@Override
public boolean accepts(Class<?> expectedType, Object value, StatementContext ctx) {
return value instanceof NotificationPayload;
}
@Override
public Argument build(Class<?> expectedType, NotificationPayload value, StatementContext ctx) {
return value;
}
}
and of course lastly also as mentioned in Does JDBI accept UUID parameters? I had to register my factory:
jdbi.registerArgumentFactory(new NotificationPayloadFactory());
I tried to do this with just a factory for a Map<String, Object>
but could not make it work for that, and there was a risk for NPE.
The reason I am Overriding the toString()
in NotificationPayload
is because I need the payload in json format some places where I need a String object. But else it can be removed and then just use the new JSONObject(payload).toString()
in the preparedStatement.setString()
where toString()
is called.