[POL-324] org.apache.commons.pool2.impl.GenericObjectPool.getFactoryType() throws java.lang.ClassCastException.
Project: http://git-wip-us.apache.org/repos/asf/commons-pool/repo Commit: http://git-wip-us.apache.org/repos/asf/commons-pool/commit/41bf71b0 Tree: http://git-wip-us.apache.org/repos/asf/commons-pool/tree/41bf71b0 Diff: http://git-wip-us.apache.org/repos/asf/commons-pool/diff/41bf71b0 Branch: refs/heads/master Commit: 41bf71b0f1e861008515b20672f86e98fbc8284f Parents: 5499672 Author: Gary Gregory <garydgreg...@gmail.com> Authored: Sat May 26 11:21:51 2018 -0600 Committer: Gary Gregory <garydgreg...@gmail.com> Committed: Sat May 26 11:21:51 2018 -0600 ---------------------------------------------------------------------- src/changes/changes.xml | 7 ++ .../commons/pool2/impl/PoolImplUtils.java | 105 +++++++++++++------ .../pool2/impl/TestGenericObjectPool.java | 7 +- 3 files changed, 80 insertions(+), 39 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/commons-pool/blob/41bf71b0/src/changes/changes.xml ---------------------------------------------------------------------- diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 8f5f9c9..7d0bd85 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -62,6 +62,9 @@ The <action> type attribute can be add,update,fix,remove. <action dev="ggregory" issue="POOL-338" type="fix" due-to="Michael C, Gary Gregory"> GenericObjectPool constructor may throw an exception under OSGi. </action> + <action dev="ggregory" issue="POOL-324" type="fix" due-to="Jay Xu, Gary Gregory"> + org.apache.commons.pool2.impl.GenericObjectPool.getFactoryType() throws java.lang.ClassCastException. + </action> </release> <release version="2.5.0" date="2017-12-16" description="This is a minor release, updating to Java 7."> <action dev="ggregory" issue="POOL-331" type="update"> @@ -83,6 +86,10 @@ The <action> type attribute can be add,update,fix,remove. Make abandoned logging stack trace requirements configurable. This also reverts the default behavior introduced by POOL-320. </action> + <action dev="mattsicker" issue="POOL-335" type="add"> + Make abandoned logging stack trace requirements configurable. This also reverts + the default behavior introduced by POOL-320. + </action> </release> <release version="2.4.3" date="2017-10-24" description="This is a patch release, including bug fixes only."> <action dev="ggregory" issue="POOL-328" type="fix" due-to="Lorenzo Solano Martinez"> http://git-wip-us.apache.org/repos/asf/commons-pool/blob/41bf71b0/src/main/java/org/apache/commons/pool2/impl/PoolImplUtils.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/pool2/impl/PoolImplUtils.java b/src/main/java/org/apache/commons/pool2/impl/PoolImplUtils.java index d39c96f..7d7e806 100644 --- a/src/main/java/org/apache/commons/pool2/impl/PoolImplUtils.java +++ b/src/main/java/org/apache/commons/pool2/impl/PoolImplUtils.java @@ -32,51 +32,65 @@ class PoolImplUtils { /** * Identifies the concrete type of object that an object factory creates. * - * @param factoryClass The factory to examine + * @param factoryClass + * The factory to examine * * @return the type of object the factory creates */ @SuppressWarnings("rawtypes") static Class<?> getFactoryType(final Class<? extends PooledObjectFactory> factoryClass) { - return (Class<?>) getGenericType(PooledObjectFactory.class, factoryClass); + final Class<PooledObjectFactory> type = PooledObjectFactory.class; + final Object genericType = getGenericType(type, factoryClass); + if (genericType instanceof Integer) { + // POOL-324 org.apache.commons.pool2.impl.GenericObjectPool.getFactoryType() throws + // java.lang.ClassCastException + // + // A bit hackish, but we must handle cases when getGenericType() does not return a concrete types. + final ParameterizedType pi = getParameterizedType(type, factoryClass); + if (pi != null) { + final Type[] bounds = ((TypeVariable) pi.getActualTypeArguments()[(Integer) genericType]).getBounds(); + if (bounds != null && bounds.length > 0) { + final Type bound0 = bounds[0]; + if (bound0 instanceof Class) { + return (Class<?>) bound0; + } + } + } + // last resort: Always return a Class + return Object.class; + } + return (Class<?>) genericType; } - /** - * Obtains the concrete type used by an implementation of an interface that - * uses a generic type. + * Obtains the concrete type used by an implementation of an interface that uses a generic type. * - * @param type The interface that defines a generic type - * @param clazz The class that implements the interface with a concrete type - * @param <T> The interface type + * @param type + * The interface that defines a generic type + * @param clazz + * The class that implements the interface with a concrete type + * @param <T> + * The interface type * * @return concrete type used by the implementation */ - private static <T> Object getGenericType(final Class<T> type, - final Class<? extends T> clazz) { + private static <T> Object getGenericType(final Class<T> type, final Class<? extends T> clazz) { + if (type == null || clazz == null) { + // Error will be logged further up the call stack + return null; + } // Look to see if this class implements the generic interface - - // Get all the interfaces - final Type[] interfaces = clazz.getGenericInterfaces(); - for (final Type iface : interfaces) { - // Only need to check interfaces that use generics - if (iface instanceof ParameterizedType) { - final ParameterizedType pi = (ParameterizedType) iface; - // Look for the generic interface - if (pi.getRawType() instanceof Class) { - if (type.isAssignableFrom((Class<?>) pi.getRawType())) { - return getTypeParameter(clazz, pi.getActualTypeArguments()[0]); - } - } - } + final ParameterizedType pi = getParameterizedType(type, clazz); + if (pi != null) { + return getTypeParameter(clazz, pi.getActualTypeArguments()[0]); } // Interface not found on this class. Look at the superclass. @SuppressWarnings("unchecked") - final Class<? extends T> superClazz = (Class<? extends T>) clazz.getSuperclass(); + final Class<? extends T> superClass = (Class<? extends T>) clazz.getSuperclass(); - final Object result = getGenericType(type, superClazz); + final Object result = getGenericType(type, superClass); if (result instanceof Class<?>) { // Superclass implements interface and defines explicit type for generic return result; @@ -91,17 +105,42 @@ class PoolImplUtils { } } + /** + * Gets the matching parameterized type or null. + * @param type + * The interface that defines a generic type + * @param clazz + * The class that implements the interface with a concrete type + * @param <T> + * The interface type + */ + private static <T> ParameterizedType getParameterizedType(final Class<T> type, final Class<? extends T> clazz) { + for (final Type iface : clazz.getGenericInterfaces()) { + // Only need to check interfaces that use generics + if (iface instanceof ParameterizedType) { + final ParameterizedType pi = (ParameterizedType) iface; + // Look for the generic interface + if (pi.getRawType() instanceof Class) { + if (type.isAssignableFrom((Class<?>) pi.getRawType())) { + return pi; + } + } + } + } + return null; + } /** - * For a generic parameter, return either the Class used or if the type - * is unknown, the index for the type in definition of the class + * For a generic parameter, return either the Class used or if the type is unknown, the index for the type in + * definition of the class * - * @param clazz defining class - * @param argType the type argument of interest + * @param clazz + * defining class + * @param argType + * the type argument of interest * - * @return An instance of {@link Class} representing the type used by the - * type parameter or an instance of {@link Integer} representing - * the index for the type in the definition of the defining class + * @return An instance of {@link Class} representing the type used by the type parameter or an instance of + * {@link Integer} representing the index for the type in the definition of the defining class */ private static Object getTypeParameter(final Class<?> clazz, final Type argType) { if (argType instanceof Class<?>) { http://git-wip-us.apache.org/repos/asf/commons-pool/blob/41bf71b0/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java b/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java index cc71fd4..baac885 100644 --- a/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java +++ b/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java @@ -54,7 +54,6 @@ import org.apache.commons.pool2.WaiterFactory; import org.junit.After; import org.junit.Assert; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; /** @@ -2726,7 +2725,7 @@ public class TestGenericObjectPool extends TestBaseObjectPool { } }; } - + private BasePooledObjectFactory<String> createDefaultPooledObjectFactory() { return new BasePooledObjectFactory<String>() { @Override @@ -2758,7 +2757,6 @@ public class TestGenericObjectPool extends TestBaseObjectPool { } @Test - @Ignore("https://issues.apache.org/jira/browse/POOL-324") public void testGetFactoryType_PoolUtilsSynchronizedNullPooledFactory() { try (final GenericObjectPool<String> pool = new GenericObjectPool<>( PoolUtils.synchronizedPooledFactory(createNullPooledObjectFactory()))) { @@ -2767,7 +2765,6 @@ public class TestGenericObjectPool extends TestBaseObjectPool { } @Test - @Ignore("https://issues.apache.org/jira/browse/POOL-324") public void testGetFactoryType_PoolUtilsSynchronizedDefaultPooledFactory() { try (final GenericObjectPool<String> pool = new GenericObjectPool<>( PoolUtils.synchronizedPooledFactory(createDefaultPooledObjectFactory()))) { @@ -2776,7 +2773,6 @@ public class TestGenericObjectPool extends TestBaseObjectPool { } @Test - @Ignore("https://issues.apache.org/jira/browse/POOL-324") public void testGetFactoryType_SynchronizedNullPooledObjectFactory() { try (final GenericObjectPool<String> pool = new GenericObjectPool<>( new TestSynchronizedPooledObjectFactory<>(createNullPooledObjectFactory()))) { @@ -2785,7 +2781,6 @@ public class TestGenericObjectPool extends TestBaseObjectPool { } @Test - @Ignore("https://issues.apache.org/jira/browse/POOL-324") public void testGetFactoryType_SynchronizedDefaultPooledObjectFactory() { try (final GenericObjectPool<String> pool = new GenericObjectPool<>( new TestSynchronizedPooledObjectFactory<>(createDefaultPooledObjectFactory()))) {