GithubHelp home page GithubHelp logo

isabella232 / typetools Goto Github PK

View Code? Open in Web Editor NEW

This project forked from minecraftforge/typetools

0.0 0.0 0.0 375 KB

Tools for working with generic types

License: Apache License 2.0

Shell 0.51% Java 99.49%

typetools's Introduction

TypeTools

Build Status Maven Central License 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 class provides some of the following methods:

  • Type reify(Type type, Class<S> 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<T> type, Class<S> subType)
    Resolves the raw arguments for a type using type variable information from a subType.
  • Class<?> resolveRawArgument(Class<T> type, Class<S> 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 for a type, given a sub-type:

interface Foo<T1, T2> {}
class Bar implements Foo<Integer, String> {}

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:

Function<String, Integer> 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:

Comparator<String> comparator = String::compareToIgnoreCase;
Class<?> typeArg = TypeResolver.resolveRawArgument(Comparator.class, comparator.getClass());

assert typeArg == String.class;

We can reify more complex generic type parameters:

interface Foo<T> {}
class Bar implements Foo<List<Integer>> {}

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:

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;

And we can reify generic type parameters from fields or methods.

Common Use Cases

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 Generic DAO layer supertype implementation:

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> {}

We can assert that type arguments are resolved as expected:

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:

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:

interface ExtraFunction<T, R, Z> extends Function<T, R>{}
ExtraFunction<String, Integer, Long> 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.

License

Copyright 2010-2019 Jonathan Halterman and friends. Released under the Apache 2.0 license.

typetools's People

Contributors

cpw avatar csoroiu avatar glockhart avatar jhalterman avatar joshrosen avatar lexmanos avatar lorenzleutgeb avatar martino2k6 avatar mickare avatar nhojpatrick avatar pderop avatar szpak avatar takahashikzn avatar thedgofficial avatar zekerzhayard avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.