diff src/main/java/nl/cwi/monetdb/jdbc/MonetWrapper.java @ 18:8e57d20b5e80

Corrected implementation of java.sql.Wrapper methods isWrapperFor() and unwrap(). They now properly return expected results instead of always return false or throw an SQLException. Added test program Test_Wrapper.java
author Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
date Thu, 13 Oct 2016 16:31:08 +0200 (2016-10-13)
parents a5a898f6886c
children b9b35ca2eec2
line wrap: on
line diff
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetWrapper.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetWrapper.java
@@ -8,66 +8,71 @@
 
 package nl.cwi.monetdb.jdbc;
 
-import java.sql.*;
+import java.sql.SQLException;
 
 /**
- * A Wrapper class that implements nothing.
- * 
- * This Class is used to simply provide JDBC4 Wrapper functions, for as
- * long as we don't really understand that they are for and what they
- * are supposed to do.  Hence the implementations are very stupid and
- * non-useful, ignoring any argument and claiming stuff doesn't work, or
- * won't work out.
+ * A Wrapper class which provide the ability to retrieve the delegate instance
+ * when the instance in question is in fact a proxy class.
  *
- * @author Fabian Groffen
- * @version 1.0
+ * The wrapper pattern is employed by many JDBC driver implementations to provide
+ * extensions beyond the traditional JDBC API that are specific to a data source.
+ * Developers may wish to gain access to these resources that are wrapped (the delegates)
+ * as proxy class instances representing the the actual resources.
+ * This class contains a standard mechanism to access these wrapped resources
+ * represented by their proxy, to permit direct access to the resource delegates.
+ *
+ * @author Fabian Groffen, Martin van Dinther
+ * @version 1.1
  */
-public class MonetWrapper implements Wrapper {
+public class MonetWrapper implements java.sql.Wrapper {
 	/**
 	 * 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
+	 * recursively calling <code>isWrapperFor</code> 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 to unwrap so that callers can use this method to avoid
-	 * expensive unwrap calls that may fail. If this method returns true
-	 * then calling unwrap with the same argument should succeed.
+	 * compared to <code>unwrap</code> so that callers can use this method to avoid
+	 * expensive <code>unwrap</code> calls that may fail.
+	 * If this method returns true then calling <code>unwrap</code> with the same argument should succeed.
 	 *
 	 * @param iface a Class defining an interface.
-	 * @return true if this implements the interface or directly or
-	 *         indirectly wraps an object that does.
-	 * @throws SQLException if an error occurs while determining
-	 *         whether this is a wrapper for an object with the given
-	 *         interface.
+	 * @return true if this implements the interface or directly or indirectly wraps an object that does.
+	 * @throws SQLException if an error occurs while determining whether this is a wrapper
+	 * 	for an object with the given interface.
+	 * @since 1.6
 	 */
 	@Override
 	public boolean isWrapperFor(Class<?> iface) throws SQLException {
-		return false;
+		return iface != null && iface.isAssignableFrom(getClass());
 	}
 
 	/**
 	 * 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 an SQLException is thrown.
+	 * access to non-standard methods, or standard methods not exposed by the proxy.
+	 * The result may be either the object found to implement the interface
+	 * or a proxy for that object.
+	 * 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 result of calling <code>unwrap</code> 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 an <code>SQLException</code> is thrown.
 	 *
-	 * @param iface A Class defining an interface that the result must
-	 *        implement.
-	 * @return 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
+	 * @param iface A Class defining an interface that the result must implement.
+	 * @return 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
+	 * @since 1.6
 	 */
 	@Override
+	@SuppressWarnings("unchecked")
 	public <T> T unwrap(Class<T> iface) throws SQLException {
-		throw new SQLException("No object found (not implemented)", "0A000");
+		if (isWrapperFor(iface)) {
+			return (T) this;
+		}
+		throw new SQLException("Cannot unwrap to interface: " + (iface != null ? iface.getName() : ""), "0A000");
 	}
 }