diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/jdbc/DelegatingConnection.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/jdbc/DelegatingConnection.java index ab323562a..4db8bbf8d 100644 --- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/jdbc/DelegatingConnection.java +++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/jdbc/DelegatingConnection.java @@ -460,12 +460,27 @@ public class DelegatingConnection implements Connection, Closeable { return iface.isAssignableFrom(getDelegate().getClass()); } + /** + * From java.sql.Wrapper javadoc: + * + * 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. + * + */ @Override public T unwrap(Class iface) throws SQLException { - if (isWrapperFor(iface)) + if (isWrapperFor(iface)) { return (T) getDelegate(); - else - return null; + } else { + return getDelegate().unwrap(iface); + } } public Array createArrayOf(String typeName, Object[] elements) throws SQLException { diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/TestUnwrap.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/TestUnwrap.java index 3c22c3a85..319afd274 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/TestUnwrap.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/TestUnwrap.java @@ -18,6 +18,9 @@ */ package org.apache.openjpa.persistence; +import java.sql.Connection; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Properties; @@ -25,7 +28,10 @@ import javax.persistence.EntityManager; import javax.persistence.EntityTransaction; import javax.persistence.Query; +import org.apache.openjpa.jdbc.conf.JDBCConfiguration; +import org.apache.openjpa.jdbc.sql.DerbyDictionary; import org.apache.openjpa.kernel.QueryLanguages; +import org.apache.openjpa.lib.jdbc.DelegatingConnection; import org.apache.openjpa.persistence.test.SingleEMFTestCase; public class TestUnwrap extends SingleEMFTestCase { @@ -90,6 +96,76 @@ public class TestUnwrap extends SingleEMFTestCase { em.close(); } + public void testConnectionUnwrap() throws Exception { + String dbDict = ((JDBCConfiguration) emf.getConfiguration()).getDBDictionaryInstance().getClass().getName(); + + EntityManager em = emf.createEntityManager(); + OpenJPAEntityManager oem = em.unwrap(OpenJPAEntityManager.class); + try { + Connection c = (Connection) oem.getConnection(); + assertNotNull(c); + assertTrue(DelegatingConnection.class.isAssignableFrom(c.getClass())); + + List acceptedConnectionClassTypes = new ArrayList(); + if (DerbyDictionary.class.getName().equals(dbDict)) { + // Connection type can be network or embedded + String[] connectionTypes = { + "org.apache.derby.impl.jdbc.EmbedConnection40", + "org.apache.derby.impl.jdbc.EmbedConnection30", + "org.apache.derby.iapi.jdbc.BrokeredConnection40", + "org.apache.derby.iapi.jdbc.BrokeredConnection30" }; + for (String ct : connectionTypes) { + try { + Class cls = Class.forName(ct); + acceptedConnectionClassTypes.add(cls); + } catch (ClassNotFoundException cnfe) { + // Swallow + } + } + } + + if (!acceptedConnectionClassTypes.isEmpty()) { + boolean pass = false; + for (Class cls : acceptedConnectionClassTypes) { + try { + Connection castC = (Connection) c.unwrap(cls); + assertNotNull(castC); + assertEquals(cls, castC.getClass()); + pass = true; + break; + } catch (Throwable t) { + // Swallow + } + + assertTrue(pass); + } + } + } finally { + em.close(); + } + } + + public void testNegativeConnectionUnwrap() { + EntityManager em = emf.createEntityManager(); + OpenJPAEntityManager oem = em.unwrap(OpenJPAEntityManager.class); + + try { + Connection c = (Connection) oem.getConnection(); + assertNotNull(c); + assertTrue(DelegatingConnection.class.isAssignableFrom(c.getClass())); + + // Make a completely bogus unwrap() attempt + try { + c.unwrap(TestUnwrap.class); + fail("Bogus unwrap should have thrown a SQLException."); + } catch (java.sql.SQLException se) { + // Expected + } + } finally { + em.close(); + } + } + /** * Tests a EntityManager can not be unwrapped as Object class, null or an interface. * And each such failure raises a Persistence Exception and causes an active transaction