Skip to contentMethod: getClass(Type)
1: /*
2: * *********************************************************************************************************************
3: *
4: * TheseFoolishThings: Miscellaneous utilities
5: * http://tidalwave.it/projects/thesefoolishthings
6: *
7: * Copyright (C) 2009 - 2023 by Tidalwave s.a.s. (http://tidalwave.it)
8: *
9: * *********************************************************************************************************************
10: *
11: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
12: * the License. You may obtain a copy of the License at
13: *
14: * http://www.apache.org/licenses/LICENSE-2.0
15: *
16: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
17: * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
18: * specific language governing permissions and limitations under the License.
19: *
20: * *********************************************************************************************************************
21: *
22: * git clone https://bitbucket.org/tidalwave/thesefoolishthings-src
23: * git clone https://github.com/tidalwave-it/thesefoolishthings-src
24: *
25: * *********************************************************************************************************************
26: */
27: package it.tidalwave.util;
28:
29: import java.lang.reflect.Array;
30: import java.lang.reflect.GenericArrayType;
31: import java.lang.reflect.ParameterizedType;
32: import java.lang.reflect.Type;
33: import java.lang.reflect.TypeVariable;
34: import javax.annotation.Nonnull;
35: import java.util.ArrayList;
36: import java.util.HashMap;
37: import java.util.List;
38: import java.util.Map;
39:
40: /***********************************************************************************************************************
41: *
42: * Just slightly adapted from http://www.artima.com/weblogs/viewpost.jsp?thread=208860
43: *
44: * @author Ian Robertson
45: * @author Fabrizio Giudici
46: *
47: **********************************************************************************************************************/
48: public class ReflectionUtils
49: {
50: /*******************************************************************************************************************
51: *
52: * Get the actual type arguments a subclass has used to extend a generic base class.
53: *
54: * @param <T> the static type of the base class
55: * @param baseClass the base class
56: * @param childClass the subclass
57: * @return a list of the raw classes for the actual type arguments.
58: *
59: ******************************************************************************************************************/
60: @Nonnull
61: public static <T> List<Class<?>> getTypeArguments (@Nonnull final Class<T> baseClass,
62: @Nonnull final Class<? extends T> childClass)
63: {
64: final Map<Type, Type> resolvedTypes = new HashMap<>();
65: Type type = childClass;
66:
67: // start walking up the inheritance hierarchy until we hit baseClass
68: while (!getClass(type).equals(baseClass))
69: {
70: if (type instanceof Class<?>)
71: {
72: // there is no useful information for us in raw types, so just keep going.
73: type = ((Class<?>)type).getGenericSuperclass();
74: }
75: else
76: {
77: final ParameterizedType parameterizedType = (ParameterizedType) type;
78: final Class<?> rawType = (Class<?>) parameterizedType.getRawType();
79: final Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
80: final TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
81:
82: for (int i = 0; i < actualTypeArguments.length; i++)
83: {
84: resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
85: }
86:
87: if (!rawType.equals(baseClass))
88: {
89: type = rawType.getGenericSuperclass();
90: }
91: }
92: }
93:
94: // finally, for each actual type argument provided to baseClass, determine (if possible)
95: // the raw class for that type argument.
96: final Type[] actualTypeArguments;
97:
98: if (type instanceof Class)
99: {
100: actualTypeArguments = ((Class<?>)type).getTypeParameters();
101: }
102: else
103: {
104: actualTypeArguments = ((ParameterizedType)type).getActualTypeArguments();
105: }
106:
107: final List<Class<?>> typeArgumentsAsClasses = new ArrayList<>();
108: // resolve types by chasing down type variables.
109: for (Type baseType : actualTypeArguments)
110: {
111: while (resolvedTypes.containsKey(baseType))
112: {
113: baseType = resolvedTypes.get(baseType);
114: }
115:
116: typeArgumentsAsClasses.add(getClass(baseType));
117: }
118:
119: return typeArgumentsAsClasses;
120: }
121:
122: @Nonnull
123: public static Class<?> getClass (@Nonnull final Type type)
124: {
125:• if (type == null)
126: {
127: throw new IllegalArgumentException("null Type");
128: }
129:
130:• if (type instanceof Class<?>)
131: {
132: return (Class<?>)type;
133: }
134:• else if (type instanceof ParameterizedType)
135: {
136: return getClass(((ParameterizedType)type).getRawType());
137: }
138:• else if (type instanceof GenericArrayType)
139: {
140: final Type componentType = ((GenericArrayType)type).getGenericComponentType();
141: final Class<?> componentClass = getClass(componentType);
142: return Array.newInstance(componentClass, 0).getClass();
143: }
144:
145: throw new IllegalArgumentException(type.toString());
146: }
147: }