在JDBI INSERT语句

时间:2017-06-22 13:23:55

标签: java sql jdbi

有没有办法将java Map<String, Object>绑定到JDBI @BindBean批注中的varchar。

例如,我有一个班级Something.class,我创建了一个

@SqlBatch("INSERT INTO Something (name, payload) VALUES(:name, :payload)")

现在在我的java类中,name的类型为Stringpayload的类型为Map<String, Object>,我希望在数据库表中类型为varchar(...) }。现在我想将Map对象作为JSON对象插入到列中,是否可以通过http://jdbi.org/sql_object_api_argument_binding/中的定义创建自己的复杂Binder来实现某种方式?而不是让我的有效载荷在java中是String类型。

2 个答案:

答案 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);
    }
}