What I'm trying to do is to get a generic typearg of a Field using
Type type = f.getGenericType();
if (type instanceof ParameterizedType) {
ParameterizedType ptype = (ParameterizedType) type;
// ...
Class<?> typearg0 = ??? // ptype.getActualTypeArguments()[0]
}
(where f
is an instance of java.lang.Field
). I need that instance of Class<?>
to perform a Foo.class.isAssignableFrom(typearg0)
check later, which only takes Class<T>
es as an argument. At the same time, I know (or expect) said typearg0
to be a parameterized type as well , so there's a contradiction: typearg0
cannot be Class<?>
and ParameterizedType
at the same time, because Class<?>
is itself a class and does not implement ParameterizedType
.
Can I achieve the isAssignableFrom()
check in any other way? Or is my goal generally impossible to achieve?
Thank you very much!
Edit:
Here is an example:
Suppose you expect a Field of type Map<Foo, Set<Bar>>
, but all you got is a java.lang.reflect.Field
instance. Now, you don't want it to precisely match Map<Foo, Set<Bar>>
, you just want the respective types to be instances of Map
or Set
. It is not a rigid specification check, it's more of a "sanity check". I would attempt this check like this:
.getType()
)Map
is assignable from the field type.getGenericType()
)Foo
(this should be an exact match)Set
is assignable from this nested typeParameterizedType
and cast itBar
(this should be an exact match)However, I don't know how to achieve 5 and/or 6.
(using java 11)
Just like you've done with Map
, Set
is likely to be an instance of ParameterizedType
so you can check it and then cast it.
From that ParameterizedType
(which represents the Set<Something>
), you can get use getRawType
to get a Set
. That's a Type
too -- but this should be safely castable to Class
. Just in case it's not, you can use a fallback and load the class using its name.
final Type valueType = mapType.getActualTypeArguments()[1];
final ParameterizedType pValueType = (ParameterizedType) valueType;
final Class<?> valueClass = pValueType.getRawType() instanceof Class ?
((Class<?>) pValueType.getRawType()) :
// Should be castable, but just in case it's not, fallback
getClass().getClassLoader().loadClass(
pValueType.getRawType().getTypeName()
);
if (Set.class.isAssignableFrom(valueClass)) { /* do something*/ }
Here's a full runnable example .
class Foo {}
class Bar {}
interface MyValidMap extends Map<Foo, Set<Bar>> {}
public class Application {
public final HashMap<Foo, HashSet<Bar>> good = null;
public final Map<Foo, Set<Bar>> better = null;
public final String notAMap = null;
public final Map<String, Set<Bar>> badKey = null;
public final Map<Foo, List<String>> badValue = null;
public final Map<Foo, Set<String>> badSetElems = null;
public final MyValidMap noTypeParamMap = null;
public static void main(String[] args) throws Exception {
for (Field field : Application.class.getFields()) {
System.out.println(field.getName() + " - " + fieldMatches(field));
}
}
private static String fieldMatches(Field mapField) throws Exception {
if (!Map.class.isAssignableFrom(mapField.getType())) {
return "Field is not a Map";
}
if (!(mapField.getGenericType() instanceof ParameterizedType)) {
// We know it's a map, but it doesn't have type params. Probably something
// like this: class MyStringMap implements Map<String, String>. You can do
// something with getGenericInterfaces() but this seems so unlikely that
// it could just be ignored.
return "TODO";
}
final ParameterizedType mapType = (ParameterizedType) mapField.getGenericType();
final Type keyType = mapType.getActualTypeArguments()[0];
final Type valueType = mapType.getActualTypeArguments()[1];
if (Foo.class != keyType) {
return "Map's key type is not Foo";
}
if (!(valueType instanceof ParameterizedType)) {
// Same problem as above. May be a Set without type params
return "Map's value is (probably) not a Set";
}
final ParameterizedType pValueType = (ParameterizedType) valueType;
final Class<?> valueClass = pValueType.getRawType() instanceof Class ?
((Class<?>) pValueType.getRawType()) :
Application.class.getClassLoader().loadClass(
pValueType.getRawType().getTypeName()
);
if (!Set.class.isAssignableFrom(valueClass)) {
return "Map's value is not a Set";
}
final Type setElemType = pValueType.getActualTypeArguments()[0];
if (setElemType != Bar.class) {
return "Set's elements are not Bars";
}
return "Looks good";
}
}
Output:
good - Looks good
better - Looks good
notAMap - Field is not a Map
badKey - Map's key type is not Foo
badValue - Map's value is (probably) not a Set
badSetElems - Set's elements are not Bars
noTypeParamMap - TODO
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.