From cc0665cb6f12b1905a3dd3135c747e51db41a9a4 Mon Sep 17 00:00:00 2001 From: Ken Egozi Date: Thu, 10 Sep 2020 15:02:21 -0700 Subject: [PATCH] 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. --- .../com/microsoft/signalr/TypeReference.java | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/TypeReference.java b/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/TypeReference.java index 24213e663b..4bbe32e929 100644 --- a/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/TypeReference.java +++ b/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/TypeReference.java @@ -3,36 +3,48 @@ package com.microsoft.signalr; +import java.lang.ClassCastException; import java.lang.reflect.Type; 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 { +public abstract class TypeReference { private final Type type; /** * 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.class} is not valid Java. + * + * To get the Type of Class {@code Foo}, use the following syntax: *
{@code
-     * Type fooType = (new TypeReference() { }).getType();
+     * Type fooBarType = (new TypeReference>() { }).getType();
      * }
+ * + * To get the Type of class Foo, use a regular Type Token: + *
{@code
+     * Type fooType = Foo.class;
+     * }
+ * + * @see Super Type Tokens */ public TypeReference() { - Type superclass = getClass().getGenericSuperclass(); - if (superclass instanceof Class) { - throw new RuntimeException("Missing type parameter."); + try { + this.type = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; + } catch (ClassCastException ex) { + throw new RuntimeException("TypeReference must be instantiated with a type parameter such as (new TypeReference>() {})."); } - this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0]; } /** * Gets the referenced type. * @return The Type encapsulated by this TypeReference - */ + */ public Type getType() { return this.type; }