Skip to content

Commit 74092f6

Browse files
committed
Migrate GenericUtils methods to Types class
This also updates Types.raw to return the first raw type, rather than null, in the case where multiple raw type bounds exist. This returns null in fewer cases, and matches what the javadoc says. For backwards compatibility, the deprecated method preserves the legacy behavior of returning null in that case.
1 parent d87cc91 commit 74092f6

3 files changed

Lines changed: 165 additions & 198 deletions

File tree

src/main/java/org/scijava/util/GenericUtils.java

Lines changed: 35 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -32,198 +32,89 @@
3232

3333
package org.scijava.util;
3434

35-
import com.googlecode.gentyref.GenericTypeReflector;
36-
3735
import java.lang.reflect.Field;
3836
import java.lang.reflect.Method;
3937
import java.lang.reflect.Type;
4038
import java.util.List;
4139

42-
/**
43-
* Useful methods for working with {@link Type} objects, particularly generic
44-
* types.
45-
* <p>
46-
* This class leans heavily on the excellent <a
47-
* href="https://code.google.com/p/gentyref/">gentyref</a> library, and exists
48-
* mainly to keep the gentyref dependency encapsulated within SciJava Common.
49-
* </p>
50-
*
51-
* @author Curtis Rueden
52-
* @see ClassUtils For utility methods specific to {@link Class} objects.
53-
* @see ConversionUtils For utility methods that convert between {@link Type}s.
54-
*/
40+
import org.scijava.util.Types;
41+
42+
/** @deprecated Use {@link Types} instead. */
43+
@Deprecated
5544
public final class GenericUtils {
5645

5746
private GenericUtils() {
5847
// prevent instantiation of utility class
5948
}
6049

61-
/**
62-
* Gets the sole raw class corresponding to the given type, or null if none.
63-
*/
50+
/** @deprecated Use {@link Types#raw} instead. */
51+
@Deprecated
6452
public static Class<?> getClass(final Type type) {
65-
if (type == null) return null;
66-
if (type instanceof Class) return (Class<?>) type;
67-
final List<Class<?>> c = getClasses(type);
68-
if (c == null || c.size() != 1) return null;
69-
return c.get(0);
53+
final List<Class<?>> bounds = Types.raws(type);
54+
return bounds != null && bounds.size() == 1 ? bounds.get(0) : null;
7055
}
7156

72-
/**
73-
* Gets all raw classes corresponding to the given type.
74-
* <p>
75-
* For example, a type parameter {@code A extends Number & Iterable} will
76-
* return both {@link Number} and {@link Iterable} as its raw classes.
77-
* </p>
78-
*/
57+
/** @deprecated Use {@link Types#raws} instead. */
58+
@Deprecated
7959
public static List<Class<?>> getClasses(final Type type) {
80-
if (type == null) return null;
81-
return GenericTypeReflector.getUpperBoundClassAndInterfaces(type);
60+
return Types.raws(type);
8261
}
8362

84-
/**
85-
* Gets the component type of the given array type, or null if not an array.
86-
*/
63+
/** @deprecated Use {@link Types#component} instead. */
64+
@Deprecated
8765
public static Type getComponentType(final Type type) {
88-
return GenericTypeReflector.getArrayComponentType(type);
66+
return Types.component(type);
8967
}
9068

9169
/**
92-
* Gets the sole component class of the given array type, or null if none.
70+
* @deprecated Use {@link Types#component} and {@link Types#raw} instead.
9371
*/
72+
@Deprecated
9473
public static Class<?> getComponentClass(final Type type) {
95-
return getClass(getComponentType(type));
74+
return Types.raw(Types.component(type));
9675
}
9776

98-
/**
99-
* Returns the "safe" generic type of the given field, as viewed from the
100-
* given type. This may be narrower than what {@link Field#getGenericType()}
101-
* returns, if the field is declared in a superclass, or {@code type} has a
102-
* type parameter that is used in the type of the field.
103-
* <p>
104-
* For example, suppose we have the following three classes:
105-
* </p>
106-
*
107-
* <pre>
108-
* public class Thing&lt;T&gt; {
109-
* public T thing;
110-
* }
111-
*
112-
* public class NumberThing&lt;N extends Number&gt; extends Thing&lt;N&gt; { }
113-
*
114-
* public class IntegerThing extends NumberThing&lt;Integer&gt; { }
115-
* </pre>
116-
*
117-
* Then this method operates as follows:
118-
*
119-
* <pre>
120-
* field = ClassUtils.getField(Thing.class, "thing");
121-
*
122-
* field.getType(); // Object
123-
* field.getGenericType(); // T
124-
*
125-
* GenericUtils.getFieldType(field, Thing.class); // T
126-
* GenericUtils.getFieldType(field, NumberThing.class); // N extends Number
127-
* GenericUtils.getFieldType(field, IntegerThing.class); // Integer
128-
* </pre>
129-
*/
77+
/** @deprecated Use {@link Types#type(Field, Class)} instead. */
78+
@Deprecated
13079
public static Type getFieldType(final Field field, final Class<?> type) {
131-
final Type wildType = GenericTypeReflector.addWildcardParameters(type);
132-
return GenericTypeReflector.getExactFieldType(field, wildType);
80+
return Types.type(field, type);
13381
}
13482

13583
/**
136-
* Returns the "safe" class(es) of the given field, as viewed from the
137-
* specified type. This may be narrower than what {@link Field#getType()}
138-
* returns, if the field is declared in a superclass, or {@code type} has a
139-
* type parameter that is used in the type of the field.
140-
* <p>
141-
* For example, suppose we have the following three classes:
142-
* </p>
143-
*
144-
* <pre>
145-
*
146-
* public class Thing&lt;T&gt; {
147-
*
148-
* public T thing;
149-
* }
150-
*
151-
* public class NumberThing&lt;N extends Number&gt; extends Thing&lt;N&gt; {}
152-
*
153-
* public class IntegerThing extends NumberThing&lt;Integer&gt; {}
154-
* </pre>
155-
*
156-
* Then this method operates as follows:
157-
*
158-
* <pre>
159-
* field = ClassUtils.getField(Thing.class, &quot;thing&quot;);
160-
*
161-
* field.getType(); // Object
162-
*
163-
* ClassUtils.getTypes(field, Thing.class).get(0); // Object
164-
* ClassUtils.getTypes(field, NumberThing.class).get(0); // Number
165-
* ClassUtils.getTypes(field, IntegerThing.class).get(0); // Integer
166-
* </pre>
167-
* <p>
168-
* In cases of complex generics which take the intersection of multiple types
169-
* using the {@code &} operator, there may be multiple types returned by this
170-
* method. For example:
171-
* </p>
172-
*
173-
* <pre>
174-
* public class ComplexThing&lt;T extends Serializable &amp; Cloneable&gt; extends Thing&lt;T&gt; {}
175-
*
176-
* ClassUtils.getTypes(field, ComplexThing.class); // Serializable, Cloneable
177-
* </pre>
178-
*
179-
* @see #getFieldType(Field, Class)
180-
* @see #getClasses(Type)
84+
* @deprecated Use {@link Types#type(Field, Class)} and {@link Types#raws}
85+
* instead.
18186
*/
87+
@Deprecated
18288
public static List<Class<?>> getFieldClasses(final Field field,
18389
final Class<?> type)
18490
{
185-
final Type genericType = getFieldType(field, type);
186-
return getClasses(genericType);
91+
return Types.raws(Types.type(field, type));
18792
}
18893

189-
/**
190-
* As {@link #getFieldType(Field, Class)}, but with respect to the return
191-
* type of the given {@link Method} rather than a {@link Field}.
192-
*/
94+
/** @deprecated Use {@link Types#returnType} instead. */
95+
@Deprecated
19396
public static Type getMethodReturnType(final Method method,
19497
final Class<?> type)
19598
{
196-
final Type wildType = GenericTypeReflector.addWildcardParameters(type);
197-
return GenericTypeReflector.getExactReturnType(method, wildType);
99+
return Types.returnType(method, type);
198100
}
199101

200102
/**
201-
* As {@link #getFieldClasses(Field, Class)}, but with respect to the return
202-
* type of the given {@link Method} rather than a {@link Field}.
203-
*
204-
* @see #getMethodReturnType(Method, Class)
205-
* @see #getClasses(Type)
103+
* @deprecated Use {@link Types#returnType} and {@link Types#raws} instead.
206104
*/
207-
public static List<Class<?>>
208-
getMethodReturnClasses(final Method method, final Class<?> type)
105+
@Deprecated
106+
public static List<Class<?>> getMethodReturnClasses(final Method method,
107+
final Class<?> type)
209108
{
210-
final Type genericType = getMethodReturnType(method, type);
211-
return getClasses(genericType);
109+
return Types.raws(Types.returnType(method, type));
212110
}
213111

214-
/**
215-
* Gets the given type's {@code n}th type parameter of the specified class.
216-
* <p>
217-
* For example, with class {@code StringList implements List<String>},
218-
* {@code getTypeParameter(StringList.class, Collection.class, 0)} returns
219-
* {@code String}.
220-
* </p>
221-
*/
112+
/** @deprecated Use {@link Types#param} instead. */
113+
@Deprecated
222114
public static Type getTypeParameter(final Type type, final Class<?> c,
223115
final int paramNo)
224116
{
225-
return GenericTypeReflector.getTypeParameter(type,
226-
c.getTypeParameters()[paramNo]);
117+
return Types.param(type, c, paramNo);
227118
}
228119

229120
}

src/main/java/org/scijava/util/Types.java

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,13 @@
3838
// under the Apache 2 license.
3939
// See lines below starting with "BEGIN FORK".
4040

41+
import com.googlecode.gentyref.GenericTypeReflector;
42+
4143
import java.lang.reflect.Array;
4244
import java.lang.reflect.Field;
4345
import java.lang.reflect.GenericArrayType;
4446
import java.lang.reflect.GenericDeclaration;
47+
import java.lang.reflect.Method;
4548
import java.lang.reflect.ParameterizedType;
4649
import java.lang.reflect.Type;
4750
import java.lang.reflect.TypeVariable;
@@ -57,7 +60,6 @@
5760
import java.util.Set;
5861

5962
import org.scijava.util.ConversionUtils;
60-
import org.scijava.util.GenericUtils;
6163

6264
/**
6365
* Utility class for working with generic types, fields and methods.
@@ -80,8 +82,6 @@ private Types() {
8082
// NB: Prevent instantiation of utility class.
8183
}
8284

83-
// TODO: Migrate all GenericUtils methods here.
84-
8585
/**
8686
* Gets a string representation of the given type.
8787
*
@@ -115,8 +115,11 @@ public static String name(final Type t) {
115115
* @return The type's first raw class.
116116
*/
117117
public static Class<?> raw(final Type type) {
118-
// TODO: Consolidate with GenericUtils.
119-
return GenericUtils.getClass(type);
118+
if (type == null) return null;
119+
if (type instanceof Class) return (Class<?>) type;
120+
final List<Class<?>> c = raws(type);
121+
if (c == null || c.size() == 0) return null;
122+
return c.get(0);
120123
}
121124

122125
/**
@@ -131,8 +134,8 @@ public static Class<?> raw(final Type type) {
131134
* @see #raw
132135
*/
133136
public static List<Class<?>> raws(final Type type) {
134-
// TODO: Consolidate with GenericUtils.
135-
return GenericUtils.getClasses(type);
137+
if (type == null) return null;
138+
return GenericTypeReflector.getUpperBoundClassAndInterfaces(type);
136139
}
137140

138141
public static Field field(final Class<?> c, final String name) {
@@ -144,6 +147,73 @@ public static Field field(final Class<?> c, final String name) {
144147
return field(c.getSuperclass(), name);
145148
}
146149

150+
/**
151+
* Gets the component type of the given array type, or null if not an array.
152+
*/
153+
public static Type component(final Type type) {
154+
return GenericTypeReflector.getArrayComponentType(type);
155+
}
156+
157+
/**
158+
* Returns the "safe" generic type of the given field, as viewed from the
159+
* given type. This may be narrower than what {@link Field#getGenericType()}
160+
* returns, if the field is declared in a superclass, or {@code type} has a
161+
* type parameter that is used in the type of the field.
162+
* <p>
163+
* For example, suppose we have the following three classes:
164+
* </p>
165+
*
166+
* <pre>
167+
* public class Thing&lt;T&gt; {
168+
*
169+
* public T thing;
170+
* }
171+
*
172+
* public class NumberThing&lt;N extends Number&gt; extends Thing&lt;N&gt; {}
173+
*
174+
* public class IntegerThing extends NumberThing&lt;Integer&gt; {}
175+
* </pre>
176+
*
177+
* Then this method operates as follows:
178+
*
179+
* <pre>
180+
* field = Types.field(Thing.class, "thing");
181+
*
182+
* field.getType(); // Object
183+
* field.getGenericType(); // T
184+
*
185+
* Types.type(field, Thing.class); // T
186+
* Types.type(field, NumberThing.class); // N extends Number
187+
* Types.type(field, IntegerThing.class); // Integer
188+
* </pre>
189+
*/
190+
public static Type type(final Field field, final Class<?> type) {
191+
final Type wildType = GenericTypeReflector.addWildcardParameters(type);
192+
return GenericTypeReflector.getExactFieldType(field, wildType);
193+
}
194+
195+
/**
196+
* As {@link #type(Field, Class)}, but with respect to the return type of the
197+
* given {@link Method} rather than a {@link Field}.
198+
*/
199+
public static Type returnType(final Method method, final Class<?> type) {
200+
final Type wildType = GenericTypeReflector.addWildcardParameters(type);
201+
return GenericTypeReflector.getExactReturnType(method, wildType);
202+
}
203+
204+
/**
205+
* Gets the given type's {@code n}th type parameter of the specified class.
206+
* <p>
207+
* For example, with class {@code StringList implements List<String>},
208+
* {@code Types.param(StringList.class, Collection.class, 0)} returns
209+
* {@code String}.
210+
* </p>
211+
*/
212+
public static Type param(final Type type, final Class<?> c, final int no) {
213+
return GenericTypeReflector.getTypeParameter(type, c
214+
.getTypeParameters()[no]);
215+
}
216+
147217
/**
148218
* Discerns whether it would be legal to assign a reference of type
149219
* {@code source} to a reference of type {@code target}.

0 commit comments

Comments
 (0)