Spring jdbc exception: B cannot be cast to oracle.sql.BLOB - spring

I'm trying to insert a byte[] into an oracle.sql.BLOB column using spring jdbc 3.0. And I got the following exception:
java.lang.ClassCastException: [B cannot be cast to oracle.sql.BLOB|
at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:8752)|
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:8286)|
at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:8868)|
at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:240)|
at org.apache.commons.dbcp.DelegatingPreparedStatement.setObject(DelegatingPreparedStatement.java:166)|
at org.apache.commons.dbcp.DelegatingPreparedStatement.setObject(DelegatingPreparedStatement.java:166)|
at org.springframework.jdbc.core.StatementCreatorUtils.setValue(StatementCreatorUtils.java:356)|
at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValueInternal(StatementCreatorUtils.java:216)|
at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValue(StatementCreatorUtils.java:144)|
at org.springframework.jdbc.core.ArgTypePreparedStatementSetter.doSetValue(ArgTypePreparedStatementSetter.java:97)|
at org.springframework.jdbc.core.ArgTypePreparedStatementSetter.setValues(ArgTypePreparedStatementSetter.java:79)|
at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:815)|
at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:811)|
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:586)|at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:811)|
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:867)|
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:871)|
at org.springframework.jdbc.core.simple.AbstractJdbcInsert.executeInsertInternal(AbstractJdbcInsert.java:366)|
at org.springframework.jdbc.core.simple.AbstractJdbcInsert.doExecute(AbstractJdbcInsert.java:356)|
at org.springframework.jdbc.core.simple.SimpleJdbcInsert.execute(SimpleJdbcInsert.java:118)|
....
The byte[] is being constructed from a ByteBuffer object.
byte[] byte_array = byte_buffer.array();
I tried inserting a java.sql.Blob type as well, but that gave a similar exception:
java.lang.ClassCastException: javax.sql.rowset.serial.SerialBlob cannot be cast to oracle.sql.BLOB|
at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:8752)|
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:8286)|
at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:8868)|
at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:240)|
at org.apache.commons.dbcp.DelegatingPreparedStatement.setObject(DelegatingPreparedStatement.java:166)|
at org.apache.commons.dbcp.DelegatingPreparedStatement.setObject(DelegatingPreparedStatement.java:166)|
at org.springframework.jdbc.core.StatementCreatorUtils.setValue(StatementCreatorUtils.java:356)|
at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValueInternal(StatementCreatorUtils.java:216)|
at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValue(StatementCreatorUtils.java:144)
....
The java.sql.Blob is also being created from a ByteBuffer object.
Blob blob = new SerialBlob(byte_buffer.array());
It looks like StatementCreatorUtils does not handle java.sql.Blob the way it handles CLOB or NCLOB. Is there a work-around for this? Or is there a different java sql type that I should be using?

Let the type to be BINARY instead of BLOB (Types.BINARY)
I used this way and it's executed successfully

You might want to take a look at Spring's SqlLobValue. Attach your byte[] value to the query parameter map like this:
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("blobParam", new SqlLobValue(byteArrayValue, lobHandler), Types.BLOB);
Where lobHandler is a LobHandler bean (i.e org.springframework.jdbc.support.lob.DefaultLobHandler).

Related

Java MongoDb driver serialization works in UpdateOne but not when i call toJson

I am updating a record on my mongoDb database.
The update is performed in a wrapper for a series of reason, it goes like:
Contact contact = generateContact();
UpdateResult updateResult = performUpdateOne("collection",new Document("field",fieldValue), new Document("$push", new Document("contacts", contact)),updateOptions);
Please keep in mind the new Document("$set", new Document("contacts", contact)) parameter because is the only mongoDb document that contains a reference to a Pojo, this field is used in the the method performUpdateOne
private UpdateResult performUpdateOne(String collectionName, Document filter, Document set, UpdateOptions updateOptions) {
...
...
LOG.debugf("Performing MongoDb UpdateOne command, collection[%s] query[%s] update[%s].", collectionName, filter.toJson(), set.toJson());
UpdateResult updateResult = collection.updateOne(filter, set, updateOptions);
The set.toJson() call gives me the exception:
Exception: : org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class ...Contact. at org.bson.internal.CodecCache.lambda$getOrThrow$1(CodecCache.java:52)
If I comment the LOG:debugf line the collection.updateOne(filter, set, updateOptions) gives me no problem.
Why is the set document serialized correctly in the updateOne method while giving an error when i call .toJson() on it?
Thanks a lot
I am using mongo sync java driver 4.3.4

How to remove table names in JDBC response in SOAPUI

In SOAPUI tool, in response for any DB step, response contains with tableName.column.
please refer the below image.
How can remove the tableName attribute from the response.
I mean to ask, is there any setting in SOAPUI or is there any properties file I need to update...
This doesn't depends on settings from SOAPUI, it's depends on DB drivers.
I follow the SOAPUI code from github, and I finally found that internally JDBCTestSteps constructs the XML node names from response based on the follow code fragment:
...
public static Document addResultSetXmlPart(Element resultsElement, ResultSet rs, Document xmlDocumentResult)
throws SQLException {
ResultSetMetaData rsmd = rs.getMetaData();
...
...
String columnName = "";
if (!StringUtils.isNullOrEmpty(rsmd.getTableName(ii))) {
columnName += (rsmd.getTableName(ii)).toUpperCase() + ".";
}
columnName += (rsmd.getColumnName(ii)).toUpperCase();
String value = rs.getString(ii);
Element node = xmlDocumentResult.createElement(StringUtils.createXmlName(columnName));
...
(You can see the whole method addResultSetXmlPart method form XMLUtils class here)
So as you can see the node name on the XML depends on ResultSetMetaData getTableName and getColumnName methods. This class is an interface and the implementation of these methods depends on specific DB driver version.
So to have the same behavior as your client, simply check that both have the same DB drivers in SOAPUI_HOME\bin\ext.
REMARK: Once you or your client change the .jar in SOAPUI_HOME\bin\ext restart SOAPUI in order to load the new ones.
Hope this helps,
"postgresql-9.1-903.jdbc4" should return the resultset without the table names. I got it working without placing the db driver to the SOAPUI_HOME\bin\ext.

ClassCastException trying to get OracleConnection from JdbcTemplate

I am creating an ArrayDescriptor in order to pass CLOB data to an Oracle function. I have a class in which I have injected (#Inject) a jdbcTemplate...this is an implementation class which has calls out to Oracle. I am creating the ArrayDescriptor like:
Connection conn = auditJdbcTemplate.getDataSource().getConnection();
ArrayDescriptor keyArryDesc = ArrayDescriptor.createDescriptor("VC_ARR", conn);
The error I am receiving is:
java.lang.ClassCastException: com.sun.proxy.$Proxy183 cannot be cast to oracle.jdbc.OracleConnection
at oracle.sql.ArrayDescriptor.createDescriptor(ArrayDescriptor.java:105
As I stated, I have direct calls in this class to auditJdbcTemplate.update that work successfully so I am not sure why it can't return a valid connection object from the template. I have seen several answers in StackOverflow to get the underlying connection and I have not been able to get that to work.
Maybe someone find it useful:
Connection conn = jdbcTemplate.getDataSource().getConnection().unwrap(OracleConnection.class);

Hbase Issue | google protobuf tag mismatch error while deserialising SCAN string

Context: I am in the process of migrating my MR jobs on HBase from CDH 2.0.0-cdh4.5.0 (Hadoop1) to HDP 2.2.0.0-2041 (YARN). After minor changes the code was compiled against HDP 2.2.0.0-2041.
Problem: I am trying to run a oozie workflow that executes a series of MR jobs after creating a scan on HBase. The scan is created programatically and then serialised-deserialised before handing it to the mapper to fetch batches from HBase.
Issue: When TableInputFormat internally tries to deserialise the scan string, it throws an error indicating that under the hood google protobuf was not able to deserialise the string. The stack trace looks as follows.
Exception in thread "main" java.io.IOException: com.google.protobuf.InvalidProtocolBufferException: Protocol message end-group tag did not match expected tag. at com.flipkart.yarn.test.TestScanSerialiseDeserialise.convertStringToScan(TestScanSerialiseDeserialise.java:37) at com.flipkart.yarn.test.TestScanSerialiseDeserialise.main(TestScanSerialiseDeserialise.java:25) Caused by: ......
Reproducable: I am able to reproduce this in the sample code I am pasting
Sample code:
Scan scan1 = constructScanObjectForUsers("A");
String json = scan1.toJSON();
Scan scan2 = convertStringToScan(Base64.encodeBytes(json.getBytes()));
.......
private static Scan convertStringToScan(String base64) throws IOException {
byte[] decoded = Base64.decode(base64);
// System.out.println(new String(decoded));
ClientProtos.Scan scan;
try {
scan = ClientProtos.Scan.parseFrom(decoded);
} catch (InvalidProtocolBufferException ipbe) {
throw new IOException(ipbe);
}
return ProtobufUtil.toScan(scan);
}
Possible causes: I am suspecting that I missed supplying some dependency or there is some dependency mismatch in underlying jars.
Appreciate any help in solving this?
Scan scan1 = constructScanObjectForUsers("A");
String json = scan1.toJSON();
Scan scan2 = convertStringToScan(Base64.encodeBytes(json.getBytes()));
Here you appear to be encoding the message as JSON. Then you are applying base64 to the JSON text. Usually base64 only applies to binary, but JSON is text.
byte[] decoded = Base64.decode(base64);
// System.out.println(new String(decoded));
ClientProtos.Scan scan;
try {
scan = ClientProtos.Scan.parseFrom(decoded);
Here you are un-base64'ing some text and then decoding it as a protobuf. Is this the same data from above? Because if so, this won't work: JSON and Protobuf are different formats. If you want to decode as Protobuf, you need to encode as Protobuf, not JSON.

Retrieving Native Connection from JBOSS wrapped Connection

I need to pass an array Object to Oracle 11 DB. I am using annotations based Spring 3.1 and using SimpleJdbcCall to call the procedure on JBOSS server. Here is the relevant jdbcCall.
SimpleJdbcCall call = new SimpleJdbcCall(dataSource)
.withoutProcedureColumnMetaDataAccess()
.withProcedureName(IbeginDataBaseConstants.PROCEDURE_CREATE_NEW_ADMIN.VAL)
.declareParameters(new SqlParameter("inUserEmpID", OracleTypes.INTEGER))
.declareParameters(new SqlParameter("inCountryIDs", OracleTypes.ARRAY, "ibo_number_array" ))
.declareParameters(new SqlParameter("inSysRoleID", OracleTypes.INTEGER))
.declareParameters(new SqlParameter("inLoggedIn", OracleTypes.INTEGER))
.declareParameters(new SqlOutParameter("outStatus", OracleTypes.CHAR))
.declareParameters(new SqlOutParameter("outMsg", OracleTypes.VARCHAR));
As you can see inCountryIDsis an array that I need to send.
With help from google, I was able to get multiple ways through which I can send Array to DB. Here is the first one.
SqlTypeValue value = new AbstractSqlTypeValue() {
protected Object createTypeValue(Connection conn, int sqlType, String typeName) throws SQLException {
ArrayDescriptor arrayDescriptor = new ArrayDescriptor(typeName, conn);
ARRAY idArray = new ARRAY(arrayDescriptor, conn, ids);
return idArray;
}
And I added it to parameter source using
sourceMap.addValue("inUserEmpID", newAdmin.getEmpId());
sourceMap.addValue("inCountryIDs", value);
sourceMap.addValue("inSysRoleID", newAdmin.getRoleId());
sourceMap.addValue("inLoggedIn", newAdmin.getLoggedInId());
And the Exception that I got was
org.jboss.jca.adapters.jdbc.jdk6.WrappedConnectionJDK6 cannot be cast to oracle.jdbc.OracleConnection
I understood the reason, SqlTypeValue implemention requires a OracleConnection whereas Spring passes WrappedConnection.
So, I tried to unwrap the connection using WrappedConnection class with this code.
WrappedConnection wrappedConnection = conn.unwrap(WrappedConnection.class);
But here the exception was
Not a wrapper for: org.jboss.jca.adapters.jdbc.WrappedConnection
In another try, I tried to cast existing connection to WrappedConnection using explicit cast with this.
WrappedConnection wrappedConn = (WrappedConnection)conn;
And still no luck.
Exception.
org.jboss.jca.adapters.jdbc.jdk6.WrappedConnectionJDK6 cannot be cast to org.jboss.jca.adapters.jdbc.WrappedConnection
Well, All I had to do is to retrieve the underlying connection, so I tried to cast it into WrappedConnectionJDK6 so that I would be able to call the relevent method there.
WrappedConnectionJDK6 wrappedConnection = (WrappedConnectionJDK6)conn;
leads to
org.jboss.jca.adapters.jdbc.jdk6.WrappedConnectionJDK6 cannot be cast to org.jboss.jca.adapters.jdbc.jdk6.WrappedConnectionJDK6
And the second approach
Map in = Collections.singletonMap("inCountryIDs", new SqlArrayValue(idsArray));
The problem with this approach is that Collections.singletonMap returns an immutable map. So, I can't use it to add more parameters.
Is there any way through which I can retrieve the underlying connection in JBoss Wrapped Connection ? Or is there any other mechanism through which I can pass an array paramter without having to interact with connection ?

Resources