Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/jhalterman/typetools
Tools for working with generic types
https://github.com/jhalterman/typetools
Last synced: 1 day ago
JSON representation
Tools for working with generic types
- Host: GitHub
- URL: https://github.com/jhalterman/typetools
- Owner: jhalterman
- License: apache-2.0
- Created: 2010-10-24T07:11:54.000Z (about 14 years ago)
- Default Branch: master
- Last Pushed: 2023-04-12T01:45:16.000Z (over 1 year ago)
- Last Synced: 2024-12-13T08:03:26.206Z (8 days ago)
- Language: Java
- Homepage:
- Size: 316 KB
- Stars: 626
- Watchers: 25
- Forks: 93
- Open Issues: 23
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGES.md
- Contributing: CONTRIBUTING.md
- License: LICENSE.txt
Awesome Lists containing this project
- awesome-java - TypeTools - Tools for resolving generic types. (Projects / Miscellaneous)
README
# TypeTools
[![Build Status](https://github.com/jhalterman/typetools/workflows/build/badge.svg)](https://github.com/jhalterman/typetools/actions)
[![Maven Central](https://img.shields.io/maven-central/v/net.jodah/typetools.svg?maxAge=60&colorB=53C92E)](https://maven-badges.herokuapp.com/maven-central/net.jodah/typetools)
[![License](http://img.shields.io/:license-apache-brightgreen.svg)](http://www.apache.org/licenses/LICENSE-2.0.html)
[![JavaDoc](https://img.shields.io/maven-central/v/net.jodah/typetools.svg?maxAge=60&label=javadoc&color=blue)](https://jodah.net/typetools/javadoc/)A simple, zero-dependency library for working with types. Supports Java 1.6+ and Android.
## Introduction
One of the sore points with Java involves working with type information. In particular, Java's generics do not provide a way to resolve or reify the type information for a given class. TypeTools looks to solve this by fully resolving generic type information declared on any class, interface, lambda expression or method.
## Usage
The [TypeResolver](http://jodah.net/typetools/javadoc/net/jodah/typetools/TypeResolver.html) class provides some of the following methods:
* `Type reify(Type type, Class context)`
Returns a fully reified `type` using type variable information from the `context`.
* `Type reify(Type genericType)`
Returns a fully reified `genericType` using information from the generic declaration.
* `Class>[] resolveRawArguments(Class type, Class subType)`
Resolves the raw arguments for a `type` using type variable information from a `subType`.
* `Class> resolveRawArgument(Class type, Class subType)`
Resolves the raw argument for a `type` using type variable information from a `subType`.
* `Type resolveGenericType(Class> type, Type subType)`
Resolves the generic `type` using type variable information from a `subType`.
* `Class> resolveRawClass(Type genericType, Class> subType)`
Resolves the raw class for a `genericType` using type variable information from a `subType`.## Examples
A typical use case is to [resolve arguments][resolve-raw-args] for a type, given a sub-type:
```java
interface Foo {}
class Bar implements Foo {}Class>[] typeArgs = TypeResolver.resolveRawArguments(Foo.class, Bar.class);
assert typeArgs[0] == Integer.class;
assert typeArgs[1] == String.class;
```Type arguments can also be resolved from lambda expressions:
```java
Function strToInt = s -> Integer.valueOf(s);
Class>[] typeArgs = TypeResolver.resolveRawArguments(Function.class, strToInt.getClass());assert typeArgs[0] == String.class;
assert typeArgs[1] == Integer.class;
```And from method references:
```java
Comparator comparator = String::compareToIgnoreCase;
Class> typeArg = TypeResolver.resolveRawArgument(Comparator.class, comparator.getClass());assert typeArg == String.class;
```We can [reify] more complex generic type parameters:
```java
interface Foo {}
class Bar implements Foo> {}Type typeArgs = TypeResolver.reify(Foo.class, Bar.class);
ParameterizedType paramType = (ParameterizedType) typeArgs;
Type[] actualTypeArgs = paramType.getActualTypeArguments();
ParameterizedType arg = (ParameterizedType)actualTypeArgs[0];assert paramType.getRawType() == Foo.class;
assert arg1.getRawType() == List.class;
assert arg1.getActualTypeArguments()[0] == Integer.class;
```We can also resolve the raw class for type parameters on fields and methods:
```java
class Entity {
ID id;
void setId(ID id) {}
}class SomeEntity extends Entity {}
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;
```And we can [reify generic type][reify-generic] parameters from fields or methods.
## Common Use Cases
[Layer supertypes](http://martinfowler.com/eaaCatalog/layerSupertype.html) 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 **Generic DAO** layer supertype implementation:
```java
class Device {}
class Router extends Device {}class GenericDAO {
protected Class persistentClass;
protected Class idClass;private GenericDAO() {
Class>[] typeArguments = TypeResolver.resolveRawArguments(GenericDAO.class, getClass());
this.persistentClass = (Class) typeArguments[0];
this.idClass = (Class) typeArguments[1];
}
}class DeviceDAO extends GenericDAO {}
class RouterDAO extends DeviceDAO {}
```We can assert that type arguments are resolved as expected:
```java
RouterDAO routerDAO = new RouterDAO();
assert routerDAO.persistentClass == Router.class;
assert routerDAO.idClass == Long.class;
```## Additional Features
By default, type variable information for each resolved type is weakly cached by the `TypeResolver`. Caching can be enabled/disabled via:
```java
TypeResolver.enableCache();
TypeResolver.disableCache();
```## Additional Notes
#### On Lambda Support
Lambda type argument resolution is currently supported for:
* Oracle JDK 8, 9
* Open JDK 8, 9#### On Unresolvable Lambda Type Arguments
When resolving type arguments with lambda expressions, only type parameters used in the functional interface's method signature can be resolved. Ex:
```java
interface ExtraFunction extends Function{}
ExtraFunction strToInt = s -> Integer.valueOf(s);
Class>[] typeArgs = TypeResolver.resolveRawArguments(Function.class, strToInt.getClass());assert typeArgs[0] == String.class;
assert typeArgs[1] == Integer.class;
assert typeArgs[2] == Unknown.class;
```Since the type parameter `Z` in this example is unused by `Function`, its argument resolves to `Unknown.class`.
#### On OSGi Support
When using TypeTools in an OSGi environment where lambda or method reference type argument resolution is desired, the `sun.reflect` system package should be exported to the application bundles. For example, for Felix, add the following to your config.properties file:
```
org.osgi.framework.system.packages.extra=sun.reflect
```## Docs
JavaDocs are available [here](https://jodah.net/typetools/javadoc).
## License
Copyright Jonathan Halterman and friends. Released under the [Apache 2.0 license](http://www.apache.org/licenses/LICENSE-2.0.html).
[resolve-raw-args]: http://jodah.net/typetools/javadoc/net/jodah/typetools/TypeResolver.html#resolveRawArguments-java.lang.Class-java.lang.Class-
[reify]: http://jodah.net/typetools/javadoc/net/jodah/typetools/TypeResolver.html#reify-java.lang.Class-java.lang.Class-
[reify-generic]: http://jodah.net/typetools/javadoc/net/jodah/typetools/TypeResolver.html#reify-java.lang.reflect.Type-