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