We have existing SpringMVC J2EE application that runs on Orale WebLogic which we are attempting to migrate to Apache Tomcat. Everything seems to work except we are having issues binding array values through JDBC into the Database. Here is how that was being done successfully on WebLogic.
SqlParameterSource in = new MapSqlParameterSource()
.addValue("i_username", user.getUsername())
.addValue("i_statuses",
new SqlArrayValue<String>(statuses,
"VARCHAR_TABLE_T"));
Map<String, Object> out = myDatabaseProc.execute(in);
The statuses variable is a String array and VARCHAR_TABLE_T is an Oracle DB type of the same. SqlArrayValue is a Spring class specifically for Oracle array handling in JDBC.
When the code is executed we get the following error (again, this is only broken on Tomcat).
java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp2.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to oracle.jdbc.OracleConnection
at oracle.sql.TypeDescriptor.setPhysicalConnectionOf(TypeDescriptor.java:803) ~[ojdbc8.jar:12.2.0.1.0]
at oracle.sql.TypeDescriptor.<init>(TypeDescriptor.java:585) ~[ojdbc8.jar:12.2.0.1.0]
at oracle.sql.ArrayDescriptor.<init>(ArrayDescriptor.java:258) ~[ojdbc8.jar:12.2.0.1.0]
at org.springframework.data.jdbc.support.oracle.SqlArrayValue.createTypeValue(SqlArrayValue.java:90) ~[spring-data-oracle-1.2.1.RELEASE.jar:?]
at org.springframework.jdbc.core.support.AbstractSqlTypeValue.setTypeValue(AbstractSqlTypeValue.java:60) ~[spring-jdbc-5.2.3.RELEASE.jar:5.2.3.RELEASE]
at org.springframework.jdbc.core.StatementCreatorUtils.setValue(StatementCreatorUtils.java:293) ~[spring-jdbc-5.2.3.RELEASE.jar:5.2.3.RELEASE]
at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValueInternal(StatementCreatorUtils.java:232) ~[spring-jdbc-5.2.3.RELEASE.jar:5.2.3.RELEASE]
at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValue(StatementCreatorUtils.java:147) ~[spring-jdbc-5.2.3.RELEASE.jar:5.2.3.RELEASE]
at org.springframework.jdbc.core.CallableStatementCreatorFactory$CallableStatementCreatorImpl.createCallableStatement(CallableStatementCreatorFactory.java:209) ~[spring-jdbc-5.2.3.RELEASE.jar:5.2.3.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:1090) ~[spring-jdbc-5.2.3.RELEASE.jar:5.2.3.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.call(JdbcTemplate.java:1147) ~[spring-jdbc-5.2.3.RELEASE.jar:5.2.3.RELEASE]
at org.springframework.jdbc.core.simple.AbstractJdbcCall.executeCallInternal(AbstractJdbcCall.java:412) ~[spring-jdbc-5.2.3.RELEASE.jar:5.2.3.RELEASE]
at org.springframework.jdbc.core.simple.AbstractJdbcCall.doExecute(AbstractJdbcCall.java:372) ~[spring-jdbc-5.2.3.RELEASE.jar:5.2.3.RELEASE]
at org.springframework.jdbc.core.simple.SimpleJdbcCall.execute(SimpleJdbcCall.java:198) ~[spring-jdbc-5.2.3.RELEASE.jar:5.2.3.RELEASE]
I found a bunch online about unwrapping the connection to be able to perform vendor specific actions, however it seems that Spring should be doing that for me? I tried setting accessToUnderlyingConnectionAllowed to true in Tomcat's server.xml (something I had found online) where we have the connection resource setup, but that did not affect the behavior.
Here is the resource from server.xml.
<Resource name="jdbc/datasource" auth="Container"
type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:@//db.domain.com:port/sid"
username="user" password="password"
maxTotal="15" maxIdle="3" maxWaitMillis="-1"
accessToUnderlyingConnectionAllowed="true" />