Need help storing nested json in postgresql using jdbi Need help storing nested json in postgresql using jdbi json json

Need help storing nested json in postgresql using jdbi


You can use PGObject to build a JSONB data type in Java. This way you can avoid any special handling as part of the SQL:

PGobject dataObject = new PGobject();dataObject.setType("jsonb");dataObject.setValue(value.toString());

A full example including converting an object to a tree, and using an ArgumentFactory to convert it to a PGobject could look like this:

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


I was able to solve this by passing in a string obtained by calling writeValueAsString(Map) on a Jackson ObjectMapper. My createJson method turned into:

@SqlUpdate("insert into entity_json(id, content) values(:id, :content\\:\\:jsonb)")public abstract void createJson(@Bind("id")String id, @Bind("content")String content);

and I obtained the string to pass in by creating a mapper:

private ObjectMapper mapper = Jackson.newObjectMapper();

and then calling:

mapper.writeValueAsString(map);

This gave me the nested json I was looking for.