A simple, zero-dependency set of tools for working with Java types.
One of the sore points with Java involves working with type information. In particular, Java's generics implementation doesn't provide a way to resolve the type information for a given class. TypeTools looks to solve this by fully resolving generic type information declared on any class, interface or method.
Add TypeTools as a Maven dependency:
<dependency>
<groupId>net.jodah</groupId>
<artifactId>typetools</artifactId>
<version>0.3.1</version>
</dependency>
Generic type resolution offered by the TypeResolver
class:
resolveRawArguments(Class<T> type, Class<S> subType)
: Resolves the raw classes representing type arguments for atype
using type variable information from asubType
.resolveRawArgument(Class<T> type, Class<S> subType)
: Resolves the raw class representing the type argument for atype
using type variable information from asubType
.resolveGenericType(Class<?> type, Type subType)
: Resolves the generictype
using type variable information from asubType
.resolveRawClass(Type genericType, Class<?> subType)
: Resolves the raw class for agenericType
using type variable information from asubType
.
A typical use case is to resolve the type arguments for a type given a sub-type:
interface Foo<T1, T2> {}
class Bar<T> implements Foo<HashSet<Integer>, T> {}
class Baz extends Bar<ArrayList<String>> {}
Class<?>[] typeArguments = TypeResolver.resolveRawArguments(Foo.class, Baz.class);
assert typeArguments[0] == HashSet.class;
assert typeArguments[1] == ArrayList.class;
We can also fully resolve the raw class for any generic type given a sub-type:
class Entity<ID extends Serializable> {
ID id;
void setId(ID id) {}
}
class SomeEntity extends Entity<Long> {}
Type fieldType = Entity.class.getDeclaredField("id").getGenericType();
Type mutatorType = Entity.class.getDeclaredMethod("setId", Serializable.class).getGenericParameterTypes()[0];
assert TypeResolver.resolveRawClass(fieldType, SomeEntity.class) == Long.class;
assert TypeResolver.resolveRawClass(mutatorType, SomeEntity.class) == Long.class;
Layer supertypes often utilize type parameters that are populated by subclasses. A common use case for TypeTools is to resolve the type arguments for a layer supertype given a sub-type.
Following is an example layer supertype implementation of a Generic DAO:
class Device {}
class Router extends Device {}
class GenericDAO<T, ID extends Serializable> {
protected Class<T> persistentClass;
protected Class<ID> idClass;
private GenericDAO() {
Class<?>[] typeArguments = TypeResolver.resolveRawArguments(GenericDAO.class, getClass());
this.persistentClass = (Class<T>) typeArguments[0];
this.idClass = (Class<ID>) typeArguments[1];
}
}
class DeviceDAO<T extends Device> extends GenericDAO<T, Long> {}
class RouterDAO extends DeviceDAO<Router> {}
void assertTypeArguments() {
RouterDAO routerDAO = new RouterDAO();
assert routerDAO.persistentClass == Router.class;
assert routerDAO.idClass == Long.class;
}
By default, type variable information for each resolved type is weakly cached by the TypeResolver
. Caching can be enabled/disabled via:
TypeResolver.enableCache();
TypeResolver.disableCache();
JavaDocs are available here.
Copyright 2010-2013 Jonathan Halterman - Released under the Apache 2.0 license.