Thread: Inserting JSON via Java PreparedStatment
Hello!
I’m struggling to insert a JSON object into my postgres v9.4 DB. I have defined the column called "evtjson" as type json. (not jsonb)
I am trying to use a prepared statement in Java (jdk1.8) to insert a Json object (built using JEE javax.json libraries) into the column, but I keep running into SQLException errors.
I'm using JDBC 9.4.1208
I create the JSON object using:
JsonObject mbrLogRec = Json.createObjectBuilder().build();
…
mbrLogRec = Json.createObjectBuilder() .add("New MbrID", newId) .build();
Then I pass this object as a parameter to another method to write it to the DB using a prepared statement. (along with several other fields) As:
pStmt.setObject(11, dtlRec);
Using this method, I receive the following error:
at org.postgresql.util.PSQLException: No hstore extension installed.
at org.postgresql.jdbc.PgPreparedStatement.setMap(PgPreparedStatement.java:553)
at org.postgresql.jdbc.PgPreparedStatement.setObject(PgPreparedStatement.java:1036)
I did try installing the hstore extension, but it then told me that it was not an hstore object.
I have also tried:
pStmt.setString(11, dtlRec.toString());
pStmt.setObject(11, dtlRec.toString());
Which produce a different error:
Event JSON: {"New MbrID":29}
SQLException: ERROR: column "evtjson" is of type json but expression is of type character varying
Hint: You will need to rewrite or cast the expression.
But, at least this tells me that the DB is recognizing the column as type JSON.
OracleDocs shows a number of various methods to set the parameter value in the preparedStatement, but I'd rather not try them all if someone knows the answer. (http://docs.oracle.com/javase/8/docs/api/java/sql/PreparedStatement.html) These also reference an additional parameter, SQLType, but I can't find any refernce to these.
Should I try setAsciiStream? CharacterStream? CLOB? ???
I couldn't find any help or tutes on postgres or the web.
Thanks for any help.
-Curt
pStmt.setString(11, dtlRec.toString()); pStmt.setObject(11, dtlRec.toString());
Which produce a different error:
Event JSON: {"New MbrID":29}
SQLException: ERROR: column "evtjson" is of type json but expression is of type character varying
Hint: You will need to rewrite or cast the expression.
On 03/07/2016 05:25 AM, Curt Huffman wrote: > Hello! > > I’m struggling to insert a JSON object into my postgres v9.4 DB. I have > defined the column called "evtjson" as type json. (not jsonb) > I am trying to use a prepared statement in Java (jdk1.8) to insert a > Json object (built using JEE javax.json libraries) into the column, but > I keep running into SQLException errors. > > I'm using JDBC 9.4.1208 > > I create the JSON object using: > > |JsonObjectmbrLogRec =Json.createObjectBuilder().build();…mbrLogRec > =Json.createObjectBuilder().add("New MbrID",newId).build();| > > Then I pass this object as a parameter to another method to write it to > the DB using a prepared statement. (along with several other fields) As: > > |pStmt.setObject(11,dtlRec);| You lost me here, I thought the object you are building is mbrLogRec? > > Using this method, I receive the following error: > > at org.postgresql.util.PSQLException: No hstore extension installed. > > at > org.postgresql.jdbc.PgPreparedStatement.setMap(PgPreparedStatement.java:553) > > > at > org.postgresql.jdbc.PgPreparedStatement.setObject(PgPreparedStatement.java:1036) > > I did try installing the hstore extension, but it then told me that it > was not an hstore object. > > I have also tried: > > |pStmt.setString(11,dtlRec.toString());pStmt.setObject(11,dtlRec.toString());| > > Which produce a different error: > > Event JSON: {"New MbrID":29} > > SQLException: ERROR: column "evtjson" is of type json but expression > is of type character varying > > Hint: You will need to rewrite or cast the expression. > > But, at least this tells me that the DB is recognizing the column as > type JSON. > > OracleDocs shows a number of various methods to set the parameter value > in the preparedStatement, but I'd rather not try them all if someone > knows the answer. > (http://docs.oracle.com/javase/8/docs/api/java/sql/PreparedStatement.html) > These also reference an additional parameter, SQLType, but I can't find > any refernce to these. > Should I try setAsciiStream? CharacterStream? CLOB? ??? > > I couldn't find any help or tutes on postgres or the web. > > Thanks for any help. > > -Curt > -- Adrian Klaver adrian.klaver@aklaver.com
On Mon, 2016-03-07 at 09:32 -0700, David G. Johnston wrote: > > > > > Hint: You will need to rewrite or cast the expression. > > > Take the hint, literally. You never did show the SQL but usually the > least complex way to solve this is to indeed transfer the data as a > string/text and then instruction PostgreSQL to convert (i.e., cast) > it to json. > > SELECT (?)::json; <-- that ? parameter is seen as text; then you > convert it. The parentheses should be optional but I use them to > emphasize the point. > > then > > pStmt.setString(1, dtlRec.toString()); > > David J. > For some reason there is no java.sql.Type = JSON. There is ARRAY though. I would have written this:- JsonObject mbrLogRec = Json.createObjectBuilder().build(); mbrLogRec = Json.createObjectBuilder() .add("New MbrID", newId) .build(); as JsonObject mbrLogRec = Json.createObjectBuilder().add("New MbrID", newId); pStmt.setObject(11, mbrLogRec); If you pass a string to your prepared statement and want to cast it in your INSERT/UPDATE statement, you will probably have to include the double quotes, colons and commas. Never tried it, just a guess. Could become complicated when you have multiple pairs of JSON attributes. E.g. JsonObject mbrLogRec = Json.createObjectBuilder().add("New MbrID", newId).add("Old MbrID","fred"); I'm sorry but I don't have time at the moment to knock up a test program and verify any of this. I'm not an expert on JSON objects in Java. Just my two bob's worth. HTH, Rob
Thanks Rob & David!I got it to work using the following:String qry = "INSERT INTO event "+ "(spotid, qid, userid, persid, ...., "+ "evtvalue, evtdt, evtjson) "+ "VALUES(?,?,?,?,?,?,?,?,?,?,to_json(?::json));";
andpStmt.setString (11,dtlRec.toString());(another suggestion was to use: cast(? as json) which I haven't tried yet.)
This worked with an ultra-simple, 1-pair json object. {"New MbrID":34} I'll try it with more complex structures next.Any opinions on using the postgres function, to_json, over the cast?
However, from my (limited) understanding, I think I am now just incurring additional processing overhead from all of this.I think that I am stuffing text into a JSON object, then converting it into a string for the preparedStatment, which then passes it to the JDBC driver to re-convert it into a JSON object, and gets ultimately stored as a text string in the column? Is that correct?I suspect I'll have to reverse the process to read it back out, yes?
Follow-up questions:1) Since I'm not (yet) using JSONB, but just regular JSON column, is there much point to even using a JSON column?
2) Will this method also work for JSONB column types?
On Mon, 2016-03-07 at 09:32 -0700, David G. Johnston wrote:
>
> >
> > Hint: You will need to rewrite or cast the expression.
> >
> Take the hint, literally. You never did show the SQL but usually the
> least complex way to solve this is to indeed transfer the data as a
> string/text and then instruction PostgreSQL to convert (i.e., cast)
> it to json.
>
> SELECT (?)::json; <-- that ? parameter is seen as text; then you
> convert it. The parentheses should be optional but I use them to
> emphasize the point.
>
> then
>
> pStmt.setString(1, dtlRec.toString());
>
> David J.
>
For some reason there is no java.sql.Type = JSON. There is ARRAY
though.
I would have written this:-
JsonObject mbrLogRec = Json.createObjectBuilder().build();
mbrLogRec = Json.createObjectBuilder()
.add("New MbrID", newId)
.build();
as
JsonObject mbrLogRec = Json.createObjectBuilder().add("New MbrID",
newId);
pStmt.setObject(11, mbrLogRec);
If you pass a string to your prepared statement and want to cast it in
your INSERT/UPDATE statement, you will probably have to include the
double quotes, colons and commas. Never tried it, just a guess.
Could become complicated when you have multiple pairs of JSON
attributes.
E.g.
JsonObject mbrLogRec = Json.createObjectBuilder().add("New MbrID",
newId).add("Old MbrID","fred");
I'm sorry but I don't have time at the moment to knock up a test
program and verify any of this. I'm not an expert on JSON objects in
Java.
Just my two bob's worth.
HTH,
Rob
On 03/07/2016 07:15 PM, Curt Huffman wrote: > Thanks Rob & David! > > I got it to work using the following: > > > String qry = "INSERT INTO event " > + "(spotid, qid, userid, persid, ...., " > + "evtvalue, evtdt, evtjson) " > + "VALUES(?,?,?,?,?,?,?,?,?,?,to_json(?::json));"; > > and > pStmt.setString (11,dtlRec.toString()); > > (another suggestion was to use: cast(?asjson) which I haven't tried yet.) > > This worked with an ultra-simple, 1-pair json object. {"New MbrID":34} > I'll try it with more complex structures next. > > Any opinions on using the postgres function, to_json, over the cast? > > However, from my (limited) understanding, I think I am now just > incurring additional processing overhead from all of this. > I think that I am stuffing text into a JSON object, then converting it > into a string for the preparedStatment, which then passes it to the JDBC > driver to re-convert it into a JSON object, and gets ultimately stored > as a text string in the column? Is that correct? > I suspect I'll have to reverse the process to read it back out, yes? > > Follow-up questions: > 1) Since I'm not (yet) using JSONB, but just regular JSON column, is > there much point to even using a JSON column? > 2) Will this method also work for JSONB column types? > > Finally, I humbly request a small addition to the postgres doco that > illustrates this and the 'best' way to insert, manipulate, and retrieve > JSON in postgres. Maybe even a small tutorial? The below?: http://www.postgresql.org/docs/9.5/interactive/datatype-json.html#JSON-KEYS-ELEMENTS http://www.postgresql.org/docs/9.5/interactive/functions-json.html > > Thanks again! > -Curt > -- Adrian Klaver adrian.klaver@aklaver.com