ClassCastException trying to get OracleConnection from JdbcTemplate - spring

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

Related

Using JDBC Pool in oracle weblogic Server,

I have a question that puzzles me these days. I am using JDBC connection pool in oracle weblogc server for my REST API calls. The package was deployed and was able to handle the incoming requests correctly.
But somehow, after a new request is made, in the db session level, I will get a new session row of "INACTIVE" status, even if I have purposely have the db connection closed in the code. And seems to me, this session will kept for ever. Eventually it kills the pool.
Here is the sample of my code, where "apple" is my connection pool name.
Connection connection = JDBCConnection.getJDBCConnction(apple);
Statement stmt = null;
String query ="select name from user";
String hosts="";
try {
stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
name = rs.getString("name");
}
} finally {
connection.close();
}
Is there anything extra I need to do ?
Thanks,
Jack
You are likely running into an issue where you are closing the Connection but it does not result in closing the ResultSet or the Statement.
The topic has been explained extensively here and here on SO.

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

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).

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 ?

SqlDependency not working with Entity Framework

I have an issue when trying to start the SqlDependency.
The error informs me: Keyword not supported: 'metadata'.
The connectionstring is the following when retrieved from the immediate window right before it crashes.
?objectContext.Connection.ConnectionString
"metadata=res://*/YeagerTech.csdl|res://*/YeagerTech.ssdl|res://*/YeagerTech.msl;provider=System.Data.SqlClient;provider connection string=\"data source=Bill-PC;initial catalog=YeagerTech;integrated security=True;multipleactiveresultsets=True;App=EntityFramework\""
Here is the code. It crashes on the Start method. Apparently, it doesn't think the EF connectionstring is valid. Any idea of how I can correctly use this?
YeagerTechEntities dbContext = new YeagerTechEntities();
ObjectContext objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
SqlDependency.Start(objectContext.Connection.ConnectionString);
Because EF connection string is not valid for SqlDependency. It works only with EntityConnection but SqlDependency uses SqlConnection. So you must either use direct connection string in your dbContext or extract database connection string from entity connection.
Either:
var connectionString = dbContext.Database.Connection.ConnectionString;
Or
var connectionString = ((EnityConnection)objectContext.Connection).StoreConnection.ConnectionString;
Anyway EF doesn't play very well with SqlDependency. SqlDependency expects that you write SQL queries yourselves and have them under your control.
Actually, the code snippet that I got it to work is the following:
YeagerTechEntities dbContext = new YeagerTechEntities();
ObjectContext objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
Application["dbContext"] = dbContext;
objectContext.Connection.ConnectionString =
ConfigurationManager.ConnectionStrings["YeagerTechEntities"].ConnectionString;
SqlDependency.Start(((System.Data.EntityClient.EntityConnection)objectContext.Connection)
.StoreConnection.ConnectionString);
YeagerTechEntities is the EF connectionstring.

Oracle and Transaction naming

I've been programing with SQL Server and C# for quite some time and I have some code that I need to change to work with Oracle:
SqlConnection connection = (SqlConnection)CreateDBConnection();
IDbTransaction transaction = connection.BeginTransaction(level, "name");
The problem is: if I use OracleConnection instead of SqlConnection there is no way to specify a name for my transaction. I know that the syntax in Oracle allows named transactions, but I don't seem to find a way to do it through .net code.
You can not set the transaction name.
But it is possible to specify a name for the SAVEPOINT.
OracleConnection oracleConnection = new OracleConnection((string.Format("Data Source={0};User Id={1};Password={2}", DATABASE, USERNAME, PASSWORD));
oracleConnection.Open();
OracleCommand oracleCommand = oracleConnection.CreateCommand();
oracleConnection.BeginTransaction();
OracleTransaction oracleTransaction = oracleCommand.Transaction;
oracleTransaction.Save("name");
//...
oracleTransaction.Rollback("name");

Resources