-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Add TypeReference.createInstance(Class<T>) #13600
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,9 @@ | |
import com.azure.core.util.logging.ClientLogger; | ||
|
||
import java.lang.reflect.ParameterizedType; | ||
import java.lang.reflect.Type; | ||
import java.util.Map; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
|
||
/** | ||
* This class represents a generic Java type, retaining information about generics. | ||
|
@@ -16,6 +19,8 @@ public abstract class TypeReference<T> { | |
private static final ClientLogger LOGGER = new ClientLogger(TypeReference.class); | ||
private static final String MISSING_TYPE = "Type constructed without type information."; | ||
|
||
private static final Map<Class<?>, TypeReference<?>> CACHE = new ConcurrentHashMap<>(); | ||
|
||
private final java.lang.reflect.Type javaType; | ||
|
||
/** | ||
|
@@ -24,19 +29,44 @@ public abstract class TypeReference<T> { | |
* @throws IllegalArgumentException If the reference is constructed without type information. | ||
*/ | ||
public TypeReference() { | ||
java.lang.reflect.Type superClass = this.getClass().getGenericSuperclass(); | ||
Type superClass = this.getClass().getGenericSuperclass(); | ||
if (superClass instanceof Class) { | ||
throw LOGGER.logExceptionAsError(new IllegalArgumentException(MISSING_TYPE)); | ||
} else { | ||
this.javaType = ((ParameterizedType) superClass).getActualTypeArguments()[0]; | ||
} | ||
} | ||
|
||
private TypeReference(Class<T> clazz) { | ||
this.javaType = clazz; | ||
} | ||
|
||
/** | ||
* Return class T type | ||
* @return type | ||
* Returns the {@link Type} representing {@code T}. | ||
* | ||
* @return The {@link Type} representing {@code T}. | ||
*/ | ||
public java.lang.reflect.Type getJavaType() { | ||
public Type getJavaType() { | ||
return javaType; | ||
} | ||
|
||
/** | ||
* Creates and instance of {@link TypeReference} which maintains the generic {@code T} of the passed {@link Class}. | ||
* <p> | ||
* This method will cache the instance of {@link TypeReference} using the passed {@link Class} as the key. This is | ||
* meant to be used with non-generic types such as primitive object types and POJOs, not {@code Map<String, Object>} | ||
* or {@code List<Integer>} parameterized types. | ||
* | ||
* @param clazz {@link Class} that contains generic information used to create the {@link TypeReference}. | ||
* @param <T> The generic type. | ||
* @return Either the cached or new instance of {@link TypeReference}. | ||
*/ | ||
@SuppressWarnings("unchecked") | ||
public static <T> TypeReference<T> createInstance(Class<T> clazz) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks a little weird by having both createInstance and public constructor. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They serve different purposes. The public constructor is for anonymous instances that use parameterized types for their There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, this is a bit odd. They serve different purposes but the constructor works for all cases and if the caller always uses the ctor not knowing about the static There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The public constructor work with most of the cases like (concrete class, paramterized type), but not the clazz variable cases.
In this case, we must use the So both APIs have hard limitations and caching strategy are different behind the API. If I am not expert users I would confuse of the usage here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed @sima-zhu, having both does lead to some confusion. Luckily, this type is mainly going to be used internally where determining whether to use |
||
/* | ||
* When computing the TypeReference if the key is absent ignore the parameter from the compute function. The | ||
* compute function wildcards to T type which causes the type system to breakdown. | ||
*/ | ||
return (TypeReference<T>) CACHE.computeIfAbsent(clazz, c -> new TypeReference<T>(clazz) { }); | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.