我正在尝试使用带有dropwizard和jdbi的JSONB数据类型将JSON存储在postgresql 9.4数据库中。我能够存储数据,但是如果我的json比单个级别更深,则json会变成字符串而不是嵌套的json。
例如,以下json
{
"type":"unit",
"nested": {
"key":"embedded"
}
}
实际上存储为
{
"type":"unit",
"nested":"{key=embedded}"
}
我的DAO中的方法签名是
@SqlUpdate("insert into entity_json(id, content) values(:id, :content\\:\\:jsonb)")
protected abstract void createJson(@Bind("id") String id, @Bind("content") Map content);
我显然有些不对劲,但我似乎无法找出存储此嵌套数据的正确方法。
答案 0 :(得分:2)
您可以使用PGObject
在Java中构建JSONB数据类型。这样,您可以避免任何特殊处理作为SQL的一部分:
PGobject dataObject = new PGobject();
dataObject.setType("jsonb");
dataObject.setValue(value.toString());
完整示例包括将对象转换为树,并使用ArgumentFactory将其转换为PGobject,如下所示:
public class JsonbTest {
@Test
public void tryoutjson() throws Exception {
final DBI dbi = new DBI("jdbc:postgresql://localhost:5432/sighting", "postgres", "admin");
dbi.registerArgumentFactory(new ObjectNodeArgumentFactor());
Sample sample = dbi.onDemand(Sample.class);
ObjectMapper mapper = new ObjectMapper();
int id = 2;
User user = new User();
user.emailaddress = "me@home.com";
user.posts = 123;
user.username = "test";
sample.insert(id, mapper.valueToTree(user));
}
public static class User {
public String username, emailaddress;
public long posts;
}
public interface Sample {
@SqlUpdate("INSERT INTO sample (id, data) VALUES (:id, :data)")
int insert(@Bind("id") long id, @Bind("data") TreeNode data);
}
public static class ObjectNodeArgumentFactor implements ArgumentFactory<TreeNode> {
private static class ObjectNodeArgument implements Argument {
private final PGobject value;
private ObjectNodeArgument(PGobject value) {
this.value = value;
}
@Override
public void apply(int position,
PreparedStatement statement,
StatementContext ctx) throws SQLException {
statement.setObject(position, value);
}
}
@Override
public boolean accepts(Class<?> expectedType, Object value, StatementContext ctx) {
return value instanceof TreeNode;
}
@Override
public Argument build(Class<?> expectedType, TreeNode value, StatementContext ctx) {
try {
PGobject dataObject = new PGobject();
dataObject.setType("jsonb");
dataObject.setValue(value.toString());
return new ObjectNodeArgument(dataObject);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
答案 1 :(得分:1)
我能够通过传入一个在Jackson ObjectMapper上调用writeValueAsString(Map)
获得的字符串来解决这个问题。我的createJson方法变成了:
@SqlUpdate("insert into entity_json(id, content) values(:id, :content\\:\\:jsonb)")
public abstract void createJson(@Bind("id")String id, @Bind("content")String content);
我通过创建一个mapper来获取要传入的字符串:
private ObjectMapper mapper = Jackson.newObjectMapper();
然后致电:
mapper.writeValueAsString(map);
这给了我正在寻找的嵌套json。