I would like to know the correct way to validate isWrapperFor
and unwrap functions in JDBC. Here HIRAConnection
and the standard Connection
classes are used.
HIRAConnection hiraCon1 = (HIRAConnection) ds.getConnection();
Connection conn = ds.getConnection();
if (hiraCon1 instanceof Wrapper) {
// try to use java 6 unwrapping
try {
Wrapper w = conn;
if (hiraCon1.isWrapperFor(Connection.class)) {
hiraCon1 = conn.unwrap(HIRAConnection.class);
hiraCon1= hiraCon1.unwrap(HIRAConnection.class);
hiraCon1= ds.unwrap(HIRAConnection.class);//returns SQLException
}
if (hiraCon1.isWrapperFor(HIRAConnection.class)) {
hiraCon1 = conn.unwrap(HIRAConnection.class);
hiraCon1 = hiraCon1.unwrap(HIRAConnection.class);
}
if (conn.isWrapperFor(com.hira.HIRAConnection.class)) {
hiraCon1 = conn.unwrap(com.hira.HIRAConnection.class);
}
if (conn.isWrapperFor(Connection.class)) {
hiraCon1 = conn.unwrap(com.hira.HIRAConnection.class);
}
} catch (Throwable t) {
System.out.println("Failed to unwrap connection using java 6 facilities");
}
}
The correct way to use java.sql.Wrapper
is documented in its javadoc.
For isWrapperFor(Class<?> iface)
:
Returns true if this either implements the interface argument or is directly or indirectly a wrapper for an object that does. Returns false otherwise. If this implements the interface then return true, else if this is a wrapper then return the result of recursively calling
isWrapperFor
on the wrapped object. If this does not implement the interface and is not a wrapper, return false. This method should be implemented as a low-cost operation compared tounwrap
so that callers can use this method to avoid expensiveunwrap
calls that may fail. If this method returns true then callingunwrap
with the same argument should succeed.Parameters :
iface
- a Class defining an interface.
Returns :
true if this implements the interface or directly or indirectly wraps an object that does.
And for unwrap(Class<T> iface)
:
Returns an object that implements the given interface to allow access to non-standard methods, or standard methods not exposed by the proxy. If the receiver implements the interface then the result is the receiver or a proxy for the receiver. If the receiver is a wrapper and the wrapped object implements the interface then the result is the wrapped object or a proxy for the wrapped object. Otherwise return the the result of calling
unwrap
recursively on the wrapped object or a proxy for that result. If the receiver is not a wrapper and does not implement the interface, then anSQLException
is thrown.Type Parameters :
T
- the type of the class modeled by this Class object
Parameters :
iface
- A Class defining an interface that the result must implement.
Returns :
an object that implements the interface. May be a proxy for the actual implementing object.
Throws :
SQLException
- If no object found that implements the interface
In other words, you can first check using wrapperFor
if the wrapper can unwrap to the interface, and then you can use unwrap
to really unwrap to that interface. Be aware that the specification only mentions support to unwrap to interface, so unwrapping to concrete classes may not actually be possible.
Whether this works, depends on the driver used (not all drivers support unwrapping or maybe they have nothing useful to unwrap), and if you are using a connection pool library, then it is entirely possible that it doesn't allow you to unwrap to - for example - the underlying connection, because doing that could allow you to circumvent or break certain limits and requirements of the connection pool.
So the correct way to use wrapping would be:
Connection conn = ds.getConnection();
if (conn.isWrapperFor(HiraConnection.class)) {
HIRAConnection hiraCon1 = conn.unwrap(HiraConnection.class);
// use hiraCon1...
)
However if HiraConnection
is a concrete class instead of an interface, this might not work. And unwrapping will usually also lead to brittle code. It is usually better to avoid relying on driver specific interface unless absolutely necessary.
Some remarks on the code in your question:
HIRAConnection hiraCon1 = (HIRAConnection) ds.getConnection();
works, then you don't need to unwrap at all. hiraCon1 instanceof Wrapper
is a useless check, because if HIRAConnection
implements java.sql.Connection
, then it will always implement java.sql.Wrapper
(and otherwise running your code would yield a ClassNotFoundException
for java.sql.Wrapper
meaning you ran it on Java 5 or lower). hiraCon1.isWrapperFor(Connection.class)
and then unwrapping conn
to HIRAConnection
is unsafe and makes no sense. If you want to unwrap conn
to HIRAConnection
, then you need to use conn.isWrapperFor(HiraConnection.class)
hiraCon1= ds.unwrap(HIRAConnection.class);
throws an SQLException
: it is unlikely that a javax.sql.DataSource
implementation considers itself a wrapper for connections. hiraCon1.isWrapperFor(HIRAConnection.class)
is a bit odd: you already know hiraCon1
is a HIRAConnection
conn
after checking hiraCon1
makes no sense. conn.isWrapperFor(Connection.class)
is a bit odd: you already know conn
is a Connection
conn.isWrapperFor(Connection.class)
and then using conn.unwrap(com.hira.HIRAConnection.class)
is unsafe, as you have only checked whether conn
unwraps to Connection
, not to HIRAConnection
. They are not really for use by applications, except as noted by @MarkRotteveel below. They are used more by JDBC driver authors, for example the Apache DBCP.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.