Proposal: Add a type token class for representing generic types
Steven Schlansker
stevenschlansker at gmail.com
Fri Dec 16 17:33:15 UTC 2016
> On Dec 16, 2016, at 8:18 AM, Gunnar Morling <gunnar at hibernate.org> wrote:
>
> Hi,
>
> I'd like to suggest the addition of a type token class to the Java
> class library, to be used for representing generic types such as
> List<String>.
I don't have much clout on this list to throw around, but a huge
+1 from me! I maintain a library that tries to be zero-dependency
and we found that we also had to introduce a type token.
If you try to avoid reusing existing names (as you mention, there are
like 5 different implementations in very common libraries) it is hard
to even come up with a unique class name at this point.
And it just feels wrong to have so many unique implementations of a simple concept...
Having this in the core libraries would be great for us.
>
> Actual class literals can only represent raw types. But often
> libraries have the need to apply some sort of configuration to
> specific generic types, link specific behaviour to them or expose
> (meta) data related to them. The suggested type token class would
> allow to implement such cases in a type-safe fashion.
>
> # Example use cases
>
> * The "type-safe heterogenous container" pattern from Joshua Bloch's
> book "Effective Java" introduces a container which allows to safely
> store and retrieve objects of different types. They are keyed by
> Class<?>, which means that one cannot have a value for a List<String>
> and another value for a List<Integer> in such container. Also one
> cannot obtain a List<String> without casting from such container. Type
> literals would allow this:
>
> <T> void put(TypeLiteral<T> type, T value);
> <T> T get(TypeLiteral<T> type);
>
> TypeLiteral<List<String>> stringListType = ...;
> List<String> stringList = container.get( stringListType );
>
> * JAX-RS allows to read response message entities into parameterized
> types using its GenericType class:
>
> List<Customer> customers = response.readEntity( new
> GenericType<List<Customer>>() {} );
>
> * CDI allows to dynamically obtain beans of specific parameterized
> types using its TypeLiteral class:
>
> @Inject @Any Instance<PaymentProcessor> anyPaymentProcessor;
>
> public PaymentProcessor<Cheque> getChequePaymentProcessor() {
> PaymentProcessor<Cheque> pp = anyPaymentProcessor
> .select( new TypeLiteral<PaymentProcessor<Cheque>>() {} ).get();
> }
>
> # Proposed solution
>
> Type literals would be represented by a new type
> java.lang.reflect.TypeLiteral<T>. Instances would be created via
> sub-classing, capturing the <T> parameter and baking it into the
> sub-class:
>
> TypeLiteral<List<String>> stringListType = new
> TypeLiteral<List<String>>(){};
>
> That'd allow to provide type-safe APIs around generic types as shown
> in the examples above. The following methods should be defined on
> TypeLiteral in order to make it useful for implementers of such APIs:
>
> Type getType();
> Class<?> getRawType();
> boolean equals(Object obj);
> int hashCode();
> String toString();
>
> # Prior art
>
> The idea of type tokens based on capturing a generic type in a
> sub-class has been around for a long time. The first reference I've
> found is Neal Gafter's blog post on "Super Type Tokens" from 2006 [1].
> Examples in real-world APIs and libraries are TypeLiteral<T> in CDI
> [2], GenericType<T> in JAX-RS [3], TypeLiteral<T> in commons-lang [4]
> and TypeToken<T> in Guava [5].
>
> # Alternatives and shortcomings
>
> The obvious alternative would be reified generics, but I think it's
> commonly agreed upon that these will not come to the Java language any
> time soon. Without native support in the language itself the proposed
> type literal class is the best way to support the mentioned use cases
> as far as I can say.
>
> Shortcomings are the creation of a sub-class per literal instantiation
> (probably more an aesthetic problem, though) and failure of the
> pattern when type variables are included anywhere in the represented
> type [6]. Unfortunately, this can only be detected at runtime when
> instantiating a literal but not by the compiler (although, I reckon it
> technically could, by handling this case specifically).
>
> # Conclusion
>
> Lacking reified generics, the Java platform would benefit from the
> addition of new type token class java.lang.reflect.TypeLiteral. The
> pattern's presence in common APIs and libraries shows that there is a
> wide-spread need for such mechanism and the community would benefit
> very much from a standardized solution in the JDK itself. This will
> allow for more unified API designs as well as foster integration of
> different libraries.
>
> I'm eager to learn about your feedback and the OpenJDK team's
> assessment of this proposal.
>
> --Gunnar
>
> [1] http://gafter.blogspot.de/2006/12/super-type-tokens.html
> [2] https://docs.oracle.com/javaee/7/api/index.html?javax/enterprise/util/TypeLiteral.html
> [3] https://docs.oracle.com/javaee/7/api/index.html?javax/ws/rs/core/GenericType.html
> [4] https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/reflect/TypeLiteral.html
> [5] https://google.github.io/guava/releases/20.0/api/docs/index.html?com/google/common/reflect/TypeToken.html
> [6] http://gafter.blogspot.de/2007/05/limitation-of-super-type-tokens.html
More information about the core-libs-dev
mailing list