JDBCTemplate and MYSQL JSON
I am writing a rest service where i need to add few details at mysql table.
My mysql table as a column area_json as type json.
I got a pojo object from post call in rest service and i tried to insert it using jdbctemplate like
jdbcTemplate.update("insert into site(area_id,area_json) values(?,?)", area.getareaID(), area.getareaJson());
Once I do a post call using post man i get the below error
Invalid argument value: java.io.NotSerializableException;
nested exception is java.sql.SQLException: Invalid argument value: java.io.NotSerializableException"
Please help
In the first place, be sure to use a version of Connector/J no older than v5.1.37, where support for the JSON datatype was added, and preferrably no older than v5.1.40, which fixed some JSON-related bugs. But if that's an issue for you, then it is at best secondary.
Before that even matters, JdbcTemplate needs to understand your JSONObject argument. The particular method you are using documents that the variable arguments, including your JSONObject are
arguments to bind to the query (leaving it to the PreparedStatement to
guess the corresponding SQL type); may also contain SqlParameterValue
objects which indicate not only the argument value but also the SQL
type and optionally the scale
When it says the PreparedStatement will guess, it can only mean the two-arg version of PreparedStatement.setObject() which documents:
The JDBC specification specifies a standard mapping from Java Object
types to SQL types. The given argument will be converted to the
corresponding SQL type before being sent to the database.
Note that this method may be used to pass datatabase- specific
abstract data types, by using a driver-specific Java type. If the
object is of a class implementing the interface SQLData, the JDBC
driver should call the method SQLData.writeSQL to write it to the SQL
data stream. If, on the other hand, the object is of a class
implementing Ref, Blob, Clob, NClob, Struct, java.net.URL, RowId,
SQLXML or Array, the driver should pass it to the database as a value
of the corresponding SQL type.
(Emphasis added.)
JDBC does not have built-in support for a JSON datatype. The docs do allow for Connector/J to provide a driver-specific type corresponding to the JSON SQL datatype, but just because MySQL and Connector/J support JSON does not mean you can pull a random JSON-representing object off the shelf and present it to them, nor indeed that they provide or accommodate a JSON-specific Java datatype at all. Inasmuch as MySQL seems not to publish or reference any documentation of JDBC extension APIs in its Connector/J developer guide, I'm inclined to doubt that it recognizes any such type.
It seems, then, that you should rely on the same technique that you would do when programming directly in MySQL's SQL dialect:
In MySQL, JSON values are written as strings. MySQL parses any string
used in a context that requires a JSON value, and produces an error if
it is not valid as JSON. These contexts include inserting a value into
a column that has the JSON data type and passing an argument to a
function that expects a JSON value [...].
(MySQL 5.7 Reference Manual, section 11.6)
That is, convert your JSONObject to a JSON-format String, and present it to your template that way. On retrieval, expect to have to do the reverse.
Related
Summary
I am calling a stored procedure(SP) in an Oracle 12c database from a Spring-boot application. I am using CallableStatement to do this. One of the OUT parameters of the SP is an associative array with elements of a custom object type. I am having trouble retrieving the data in a proper method.
Code
TYPE trans_list IS TABLE OF T_RPT_TXN_DTLS_OBJ INDEX BY PLS_INTEGER;
TYPE T_RPT_TXN_DTLS_OBJ AS OBJECT( id VARCHAR2(20), amount NUMBER(10,2), desc VARCHAR2(100))
Connection connection = jdbcTemplate.getDataSource().getConnection();
OracleCallableStatement callableStatement = connection.prepareCall("{call SAMPLE_PROC(?,?)}").unwrap(OracleCallableStatement.class);
callableStatement.setString(1, ID);
--Here I don't know what to do--
callableStatement.registerIndexTableOutParameter(2, 500, OracleTypes.OTHER, 0);
--------------------------------
Things I have tried
I looked through different websites using google. Went through stackoverflow as well. The above code is where I am stuck at. Since the 3rd argument is the datatype of the array elements, I put in OracleTypes.OTHER but that throws an SQLException: invalid column type 1111.
I read in the official docs that for custom object types, we can map them to Java objects. I have no idea how to do that either. Please refer to User_defined types in https://docs.oracle.com/cd/B19306_01/java.102/b14355/datacc.htm#BHCGCBJC
What I am asking in brief
Any sample code, detailed docmentation, links to online examples that fits my case. I specifically need to know arg[2] of the out parameter registration, and how I might go about mapping to a custom Java object from the callableStatement (perhaps using .getObject(int) but I don't know about the mapping).
See this answer.
You cannot.
You need to define the data type in the SQL scope (using CREATE TYPE) rather than in the PL/SQL scope, in a package as JDBC can only work with SQL defined data types.
A consequence of point 1 is that JDBC does not support associative arrays, as they are a PL/SQL only data type, and you need to use collections (unlike C#, which only supports associative arrays and does not support collections). So you need to remove the INDEX BY clause from the type.
You need to be able to map from the type in the array to a Java data structure; one way of doing this is to use the SQLData interface. An example is in this answer.
Define:
callableStatement.registerOutParameter(2, OracleTypes.ARRAY,"trans_list");
Call proc:
callableStatement.executeUpdate();
Then get out parameter as
java.sql.Array array = callableStatement.getArray(2);
Object outputParamValue = array.getArray();
Type Caste outputParamValue if needed.
I'm making a custom Hibernate type using AbstractSingleColumnStandardBasicType to automatically convert the SQL UDT into a Java type. The SQL uses database functions to construct and serialize the column data from BLOBs and/or CLOBs, and I want to hide that from a user. So they don't have to use #ColumnTransformer(read="_serializer(column_name)", write="_constructor(?)") for every column.
I've made types using the BLOB SqlTypeDescriptor and a custom JavaTypeDescriptor to do the conversion at the JDBC level, but how can I have my custom type wrap the column and parameters in the proper SQL functions? I'm not finding anything describing anything like this.
Edit:
To make this more concrete, this UDT (SDE ST_GEOMETRY) must be build via database functions (ST_LineFromText) or the defined UDT constructor (ST_LineString). Likewise, to read them from the database, you have to "export" them into a certain format (ST_AsText) for Java to read it. The regular approach of reading the fields of the type doesn't work in this case.
So:
create table geo_lines (
line SDE.ST_GEOMETRY
);
And:
#Entity
#Table(name="geo_lines")
public class GeoLine {
#Column(name="line")
#Type(type="org.example.MyStLineType")
// i'm wanting to be able to omit the following annotation
#ColumnTransformer(read="SDE.ST_AsText(line)",
write="SDE.ST_ST_LineFromText(?, 3857)")
private Polyline line;
}
So, all my type really needs from the user is the number (3857 in this case), which can be passed as a parameter, and everything else is standard boilerplate for any line. Repeat for the other types like points, polygons, etc.
So I'm using JPA (Eclipselink as the provider) for persistence in a project of mine. I know a MySQL Function:
SELECT ENCODE('text','key');
This encodes the string 'text' using 'key'. And to decode it, I use its counterpart
SELECT DECODE('****','key');
Where '****' is the result of the encoding in the first function. I require these functions to encode and decode certain columns on my database.
I would like to use these functions in JPA and I thought of a clever way to do so using native queries. But casting the result of either function to String always throws an Exception saying I cannot cast whatever object was returned to a String. What data type do these functions return? Is there another alternative to encode a column in the database without having to do this?
I am working with JDBC template(SPRING) which wrraps JDBC. during runtime all my variables values (bind variables) are held as strings(with some recognition of their actual type: bigint\varchar etc.).
While I'm using setObject, I'm not sure if I need to cast the variable value to it's real type or I can send the variable as string to setObject and the database will convert it according to the column name in the database(i.e. if it is compared with BigInt then it will convert the string to big int and then query and etc.)
Thanks,
If I am understanding your question correctly then I think you CAN NOT use setObject to pass a String that will be converted to a non-String SQL type (int, bigint).
Look at this question. Below is the answer from that question.
It is not the job of setObject to determine the correct conversion to the
column type. The setObject javadoc says, "The JDBC specification
specifies a standard mapping from Java Object types to SQL types. The
given argument will be converted to the corresponding SQL type before
being sent to the database." So it is solely looking at the Java type of
the object passed to it and converting that to a SQL type. So you pass it
a String and it converts it to a varchar which is appropriate. If you
want setObject to do a conversion to a different type, that is the reason
for the additional setObject variant which takes a target sql type to
convert to, but that doesn't help your situation where you don't know what
the target type is.
I'm trying to figure out a basic approach to querying FHIR resources. My first task is to query using a REST interface. Using the information on the Search page, I see there are 7 search parameter types (NUMBER, DATE, STRING, TOKEN, REFERENCE, COMPOSITE, QUANTITY). My question is:
How does one determine a parameter's type when it's passed to the server in a URL's query string?
Since modifiers like :exact and :token only apply to certain parameter types, it seems important to identify the type of each parameter in the query string. I'm hoping the server is not expected to look up parameter types based on the resource being queried.
I'm using FHIR 0.81 with Java and JSON.
Thanks,
Rich
The server does need to look up the parameter types depending on the resource being queried. The server has to actually recognise the parameters to do anything with them anyway.
(and I assume you mean 0.0.81)