有没有办法将java Map<String, Object>
绑定到JDBI @BindBean批注中的varchar。
例如,我有一个班级Something.class
,我创建了一个
@SqlBatch("INSERT INTO Something (name, payload) VALUES(:name, :payload)")
。
现在在我的java类中,name
的类型为String
而payload
的类型为Map<String, Object>
,我希望在数据库表中类型为varchar(...)
}。现在我想将Map
对象作为JSON对象插入到列中,是否可以通过http://jdbi.org/sql_object_api_argument_binding/中的定义创建自己的复杂Binder来实现某种方式?而不是让我的有效载荷在java中是String类型。
答案 0 :(得分:1)
修复了this post中建议的创建ArgumentFactory绑定器的问题。
所以我需要的是创建一个只包含一个Map<String, Object>
类型字段的类,从Arugment
实现了org.skife.jdbi.v2.tweak
接口,所以我最终得到了以下内容
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();
}
}
为了完成这项工作,我当然需要实现一个Factory类,它使用我新创建的类型实现org.skife.jdbi.v2.tweak.ArgumentFactory<T>
接口,因此工厂最终结束了:
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;
}
}
当然最后也在Does JDBI accept UUID parameters?中提到我必须注册我的工厂:
jdbi.registerArgumentFactory(new NotificationPayloadFactory());
我试图用Map<String, Object>
的工厂来做这件事,但却无法使其发挥作用,并且NPE存在风险。
我覆盖toString()
中NotificationPayload
的原因是因为我需要json格式的有效负载,我需要一些String对象。但是,可以删除它,然后只使用调用new JSONObject(payload).toString()
的{{1}}中的preparedStatement.setString()
。
答案 1 :(得分:1)
public class MapArgument implements Argument {
private Map<String, Object> payload;
private ObjectMapper objectMapper;
public MapArgument(ObjectMapper objectMapper, Map<String, Object> payload) {
this.objectMapper = objectMapper;
this.payload = payload;
}
@Override
public void apply(int i, PreparedStatement statement, StatementContext statementContext) throws SQLException {
try {
statement.setString(i, objectMapper.writeValueAsString(payload));
} catch (JsonProcessingException e) {
log.info("Failed to serialize payload ", e);
}
}
}
public class MapArgumentFactory implements ArgumentFactory<Map<String, Object>> {
private ObjectMapper mapper;
public MapArgumentFactory(ObjectMapper mapper) {
this.mapper = mapper;
}
@Override
public boolean accepts(Class<?> type, Object value, StatementContext statementContext) {
return value instanceof Map;
}
@Override
public Argument build(Class<?> type, Map<String, Object> map, StatementContext statementContext) {
return new MapArgument(mapper, map);
}
}