commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mben...@apache.org
Subject svn commit: r835975 - in /commons/proper/lang/trunk/src: java/org/apache/commons/lang/reflect/ test/org/apache/commons/lang/reflect/ test/org/apache/commons/lang/reflect/testbed/
Date Fri, 13 Nov 2009 20:17:47 GMT
Author: mbenson
Date: Fri Nov 13 20:17:47 2009
New Revision: 835975

URL: http://svn.apache.org/viewvc?rev=835975&view=rev
Log:
[LANG-553] Add TypeUtils

Added:
    commons/proper/lang/trunk/src/java/org/apache/commons/lang/reflect/TypeUtils.java   (with
props)
    commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/TypeUtilsTest.java
  (with props)
    commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/GenericParent.java
  (with props)
    commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/GenericTypeHolder.java
  (with props)
    commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/StringParameterizedChild.java
  (with props)

Added: commons/proper/lang/trunk/src/java/org/apache/commons/lang/reflect/TypeUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/java/org/apache/commons/lang/reflect/TypeUtils.java?rev=835975&view=auto
==============================================================================
--- commons/proper/lang/trunk/src/java/org/apache/commons/lang/reflect/TypeUtils.java (added)
+++ commons/proper/lang/trunk/src/java/org/apache/commons/lang/reflect/TypeUtils.java Fri
Nov 13 20:17:47 2009
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.lang.reflect;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+
+import org.apache.commons.lang.Validate;
+
+/**
+ * <p>Utility methods focusing on type inspection, particularly with regard to
+ * generics.</p>
+ * @author James Carman
+ * @author Matt Benson
+ * @since 3.0
+ * @version $Id$
+ */
+public class TypeUtils {
+
+    /**
+     * Get the raw type of a Java type, given its context. Primarily for use
+     * with {@link TypeVariable}s and {@link GenericArrayType}s, or when you do
+     * not know the runtime type of <code>type</code>: if you know you have a
+     * {@link Class} instance, it is already raw; if you know you have a
+     * {@link ParameterizedType}, its raw type is only a method call away.
+     * @param enclosingType context
+     * @param type to read
+     * @return Class<?>
+     */
+    // original code stolen from commons [proxy]'s 2.0 branch, then kneaded until firm
+    public static Class<?> getRawType(Type enclosingType, Type type) {
+        if (type instanceof Class<?>) {
+            // it is raw, no problem
+            return (Class<?>) type;
+        }
+        if (type instanceof ParameterizedType) {
+            // simple enough to get the raw type of a ParameterizedType
+            return (Class<?>) ((ParameterizedType) type).getRawType();
+        }
+        if (type instanceof TypeVariable<?>) {
+            Validate.notNull(enclosingType,
+                    "Cannot get raw type of TypeVariable without enclosing type");
+            // resolve the variable against the enclosing type, hope for the best (casting)
+            return (Class<?>) resolveVariable(enclosingType, (TypeVariable<?>)
type);
+        }
+        if (type instanceof GenericArrayType) {
+            Validate.notNull(enclosingType,
+                    "Cannot get raw type of GenericArrayType without enclosing type");
+            // not included in original code, but not too difficult:  just have to get raw
component type...
+            Class<?> rawComponentType = getRawType(enclosingType, ((GenericArrayType)
type)
+                    .getGenericComponentType());
+            // ...and know how to reflectively create array types, uncommon but not unheard
of:
+            return Array.newInstance(rawComponentType, 0).getClass();
+        }
+        throw new IllegalArgumentException(String.valueOf(type));
+    }
+
+    /**
+     * We plan to return Class<?> from the top-level call, as evidenced by the
+     * cast in the above method, but to handle recursion and falling back up the
+     * graph, as it were, return Type
+     * @param enclosingType
+     * @param typeVar
+     * @return Type resolved
+     */
+    // original code stolen from commons [proxy]'s 2.0 branch, then kneaded until firm
+    private static Type resolveVariable(Type enclosingType, TypeVariable<?> typeVar)
{
+        if (enclosingType instanceof ParameterizedType) {
+            ParameterizedType parameterizedEnclosingType = (ParameterizedType) enclosingType;
+            TypeVariable<?>[] typeVariables = getRawType(null,
+                    parameterizedEnclosingType.getRawType()).getTypeParameters();
+            //look for the matching variable:
+            for (int i = 0; i < typeVariables.length; i++) {
+                if (typeVariables[i].equals(typeVar)) {
+                    return parameterizedEnclosingType.getActualTypeArguments()[i];
+                }
+            }
+            //otherwise recurse to try against raw class
+            Type result = resolveVariable(parameterizedEnclosingType.getRawType(), typeVar);
+            //unroll variable if returned
+            if (result instanceof TypeVariable<?>) {
+                return resolveVariable(enclosingType, (TypeVariable<?>) result);
+            }
+            return result;
+        }
+        if (enclosingType instanceof Class<?>) {
+            Class<?> enclosingClass = (Class<?>) enclosingType;
+            Type result = null;
+            Type genericSuperclass = enclosingClass.getGenericSuperclass();
+            if (genericSuperclass != null && !Object.class.equals(genericSuperclass))
{
+                result = resolveVariable(genericSuperclass, typeVar);
+            }
+            if (result == null) {
+                for (Type genericInterface : enclosingClass.getGenericInterfaces()) {
+                    result = resolveVariable(genericInterface, typeVar);
+                    if (result != null) {
+                        break;
+                    }
+                }
+            }
+            if (result != null) {
+                return result;
+            }
+        }
+        throw new IllegalArgumentException(String.valueOf(typeVar));
+    }
+
+}

Propchange: commons/proper/lang/trunk/src/java/org/apache/commons/lang/reflect/TypeUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/lang/trunk/src/java/org/apache/commons/lang/reflect/TypeUtils.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/TypeUtilsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/TypeUtilsTest.java?rev=835975&view=auto
==============================================================================
--- commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/TypeUtilsTest.java
(added)
+++ commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/TypeUtilsTest.java
Fri Nov 13 20:17:47 2009
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.lang.reflect;
+
+import static junit.framework.Assert.*;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.TypeVariable;
+import java.util.List;
+
+import org.apache.commons.lang.reflect.testbed.*;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test TypeUtils
+ * @author mbenson
+ * @version $Id$
+ */
+public class TypeUtilsTest {
+    private Field stringParentField;
+    private Field integerParentField;
+    private Field foosField;
+    private Field barParentsField;
+    private TypeVariable<?> genericParentT;
+    private TypeVariable<?> listType;
+    private TypeVariable<?> iterableType;
+
+    @Before
+    public void setup() throws Exception {
+        stringParentField = GenericTypeHolder.class.getDeclaredField("stringParent");
+        integerParentField = GenericTypeHolder.class.getDeclaredField("integerParent");
+        foosField = GenericTypeHolder.class.getDeclaredField("foos");
+        barParentsField = GenericTypeHolder.class.getDeclaredField("barParents");
+        genericParentT = GenericParent.class.getTypeParameters()[0];
+        listType = List.class.getTypeParameters()[0];
+        iterableType = Iterable.class.getTypeParameters()[0];
+    }
+
+    @Test
+    public void testGetRawTypeClass() throws Exception {
+        assertEquals(GenericParent.class, TypeUtils.getRawType(null, GenericParent.class));
+    }
+
+    @Test
+    public void testGetRawTypeParameterizedType() throws Exception {
+        assertEquals(GenericParent.class, TypeUtils.getRawType(GenericTypeHolder.class,
+                stringParentField.getGenericType()));
+        assertEquals(GenericParent.class, TypeUtils.getRawType(GenericTypeHolder.class,
+                integerParentField.getGenericType()));
+        assertEquals(List.class, TypeUtils.getRawType(GenericTypeHolder.class, foosField
+                .getGenericType()));
+    }
+
+    @Test
+    public void testGetRawTypeTypeVariable() throws Exception {
+        assertEquals(String.class, TypeUtils.getRawType(StringParameterizedChild.class,
+                genericParentT));
+        assertEquals(String.class, TypeUtils.getRawType(stringParentField.getGenericType(),
+                genericParentT));
+        assertEquals(Foo.class, TypeUtils.getRawType(foosField.getGenericType(), iterableType));
+        assertEquals(Foo.class, TypeUtils.getRawType(foosField.getGenericType(), listType));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetRawTypeUnresolvableTypeVariable() {
+        TypeUtils.getRawType(GenericParent.class, genericParentT);
+    }
+
+    @Test
+    public void testGetRawTypeGenericArray() throws Exception {
+        assertEquals(GenericParent[].class, TypeUtils.getRawType(GenericTypeHolder.class,
+                barParentsField.getGenericType()));
+    }
+}

Propchange: commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/TypeUtilsTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/TypeUtilsTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/GenericParent.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/GenericParent.java?rev=835975&view=auto
==============================================================================
--- commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/GenericParent.java
(added)
+++ commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/GenericParent.java
Fri Nov 13 20:17:47 2009
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.lang.reflect.testbed;
+
+/**
+ * Class declaring a parameter variable.
+ * @author mbenson
+ * @version $Id$
+ */
+public class GenericParent<T> {
+
+}

Propchange: commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/GenericParent.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/GenericParent.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/GenericTypeHolder.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/GenericTypeHolder.java?rev=835975&view=auto
==============================================================================
--- commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/GenericTypeHolder.java
(added)
+++ commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/GenericTypeHolder.java
Fri Nov 13 20:17:47 2009
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.lang.reflect.testbed;
+
+import java.util.List;
+
+/**
+ * Holds generic testbed types.
+ * @author mbenson
+ * @version $Id$
+ */
+public class GenericTypeHolder {
+    public GenericParent<String> stringParent;
+    public GenericParent<Integer> integerParent;
+    public List<Foo> foos;
+    public GenericParent<Bar>[] barParents;
+}

Propchange: commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/GenericTypeHolder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/GenericTypeHolder.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/StringParameterizedChild.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/StringParameterizedChild.java?rev=835975&view=auto
==============================================================================
--- commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/StringParameterizedChild.java
(added)
+++ commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/StringParameterizedChild.java
Fri Nov 13 20:17:47 2009
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.lang.reflect.testbed;
+
+/**
+ * {@link GenericParent} subclass that explicitly specifies <T> as {@link String}.
+ * @author mbenson
+ * @version $Id$
+ */
+public class StringParameterizedChild extends GenericParent<String> {
+
+}

Propchange: commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/StringParameterizedChild.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/lang/trunk/src/test/org/apache/commons/lang/reflect/testbed/StringParameterizedChild.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL



Mime
View raw message