TypeReference usage clarification (#25719)

This change makes TypeReference usage a little bit easier

- Marking it abstract make it so that usages cannot "forget" subclassing (or omitting the { } part). Previously the error message would be confusing as the supertype would be Object.
- Removing the instanceof check and relying on exception since instantiating TypeReference without a type parameter (new TypeReference() ) *is* exceptional as it goes against the intention of this class altogether.
- Added some clarification to the javadoc regarding intended usage, and a link to prior art for further reading.
This commit is contained in:
Ken Egozi 2020-09-10 15:02:21 -07:00 committed by GitHub
parent 3692e122ff
commit cc0665cb6f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 21 additions and 9 deletions

View File

@ -3,36 +3,48 @@
package com.microsoft.signalr; package com.microsoft.signalr;
import java.lang.ClassCastException;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
/** /**
* A utility for getting a Java Type from a literal Class. * A utility for getting a Java Type from a literal generic Class.
*/ */
public class TypeReference<T> { public abstract class TypeReference<T> {
private final Type type; private final Type type;
/** /**
* Creates a new instance of {@link TypeReference}. * Creates a new instance of {@link TypeReference}.
* *
* To get the Type of Class Foo, use the following syntax: * This class implements Super Type Tokens (Gafter's Gadget) as a way to get a reference to generic types in
* spite of type erasure since, sadly, {@code Foo<Bar>.class} is not valid Java.
*
* To get the Type of Class {@code Foo<Bar>}, use the following syntax:
* <pre>{@code * <pre>{@code
* Type fooType = (new TypeReference<Foo>() { }).getType(); * Type fooBarType = (new TypeReference<Foo<Bar>>() { }).getType();
* }</pre> * }</pre>
*
* To get the Type of class Foo, use a regular Type Token:
* <pre>{@code
* Type fooType = Foo.class;
* }</pre>
*
* @see <a href="http://gafter.blogspot.com/2006/12/super-type-tokens.html">Super Type Tokens</a>
*/ */
public TypeReference() { public TypeReference() {
Type superclass = getClass().getGenericSuperclass(); try {
if (superclass instanceof Class) { this.type = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
throw new RuntimeException("Missing type parameter."); } catch (ClassCastException ex) {
throw new RuntimeException("TypeReference must be instantiated with a type parameter such as (new TypeReference<Foo<Bar>>() {}).");
} }
this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0];
} }
/** /**
* Gets the referenced type. * Gets the referenced type.
* @return The Type encapsulated by this TypeReference * @return The Type encapsulated by this TypeReference
*/ */
public Type getType() { public Type getType() {
return this.type; return this.type;
} }