> On Dec 16, 2016, at 8:18 AM, Gunnar Morling <gun...@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