Proposal: Add a type token class for representing generic types

Brian Goetz brian.goetz at oracle.com
Wed Jan 4 22:17:51 UTC 2017


One of the known defects of this approach, as implemented in various 
places, is that while it increases the range of Java language types that 
can be expressed via reflective tokens, it still falls short of 
describing all the types that occur in real programs.

For example, it does not support variance.  Suppose I want to do this, 
in your type-safe hetergeneous container example:

     container.put(aListOfInts, (type literal for List<Integer>));
     List<? extends Number> numList
         = container.get( (type literal for List<? extends Number>) );

Now, you could claim that this is too esoteric an example, but if the goal is patching the inadequacies of an existing facility...  And one could pull on this thread further -- such as intersection types.  Pulling on this thread means building in subtyping too, not just "do I describe the same type."  Which isn't trivial.

Now, this isn't a slam-dunk indictment, but its a concern.

That said, Valhalla will need something to describe at least the portion of parameterized types that are reified, such as ArrayList<int>.  And type tokens for value types too.  Whether this is lumped in with Class, or whether it is a new thing, is still under exploration.  Some revamp of reflection will certainly be in order after Valhalla -- so probably best to wait and see how that settles out.




On 12/23/2016 3:08 AM, Gunnar Morling wrote:
> Hi,
>
> I've sent this proposal to core-libs-dev recently and it has been
> suggested that it may fall into the scope of project Valhalla, hence
> I'm proposing it here, too. Any feedback would be very welcome.
>
> Thanks,
>
> --Gunnar
>
> =====
> 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>.
>
> 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 valhalla-dev mailing list