/** * Jooby https://jooby.io * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ package io.jooby; import io.jooby.internal.reflect.$Types; import javax.annotation.Nonnull; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; /** * Represents a generic type {@code T}. Java doesn't yet provide a way to * represent generic types, so this class does. Forces clients to create a * subclass of this class which enables retrieval the type information even at * runtime. * *
For example, to create a type literal for {@code List
* {@code Reified This syntax cannot be used to create type literals that have wildcard
* parameters, such as {@code Class>} or {@code List extends CharSequence>}.
*
* @param Clients create an empty anonymous subclass. Doing so embeds the type
* parameter in the anonymous class's type hierarchy so we can reconstitute it
* at runtime despite erasure.
*/
@SuppressWarnings("unchecked")
public Reified() {
this.type = getSuperclassTypeParameter(getClass());
this.rawType = (Class super T>) $Types.getRawType(type);
this.hashCode = type.hashCode();
}
/**
* Unsafe. Constructs a type literal manually.
*
* @param type Generic type.
*/
@SuppressWarnings("unchecked")
private Reified(Type type) {
this.type = $Types.canonicalize(type);
this.rawType = (Class super T>) $Types.getRawType(this.type);
this.hashCode = this.type.hashCode();
}
/**
* Unsafe. Constructs a type literal manually.
*
* @param type Generic type.
*/
private Reified(Class type) {
this.type = type;
this.rawType = type;
this.hashCode = type.hashCode();
}
/**
* Returns the type from super class's type parameter in {@link $Types#canonicalize
* canonical form}.
*
* @param subclass Subclass.
* @return Type.
*/
private static Type getSuperclassTypeParameter(Class> subclass) {
Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameterized = (ParameterizedType) superclass;
return $Types.canonicalize(parameterized.getActualTypeArguments()[0]);
}
/**
* Returns the raw (non-generic) type for this type.
*
* @return Returns the raw (non-generic) type for this type.
*/
public final @Nonnull Class super T> getRawType() {
return rawType;
}
/**
* Gets underlying {@code Type} instance.
*
* @return Gets underlying {@code Type} instance.
*/
public final @Nonnull Type getType() {
return type;
}
@Override public final int hashCode() {
return this.hashCode;
}
@Override public final boolean equals(Object o) {
return o instanceof Reified>
&& $Types.equals(type, ((Reified>) o).type);
}
@Override public final String toString() {
return $Types.typeToString(type);
}
/**
* Gets type literal for the given {@code Type} instance.
*
* @param type Source type.
* @return Gets type literal for the given {@code Type} instance.
*/
public static @Nonnull Reified> get(@Nonnull Type type) {
return new Reified<>(type);
}
/**
* Get raw type (class) from given type.
*
* @param type Type.
* @return Raw type.
*/
public static @Nonnull Class> rawType(@Nonnull Type type) {
if (type instanceof Class) {
return (Class>) type;
}
return new Reified<>(type).rawType;
}
/**
* Gets type literal for the given {@code Class} instance.
*
* @param type Java type.
* @param > list = new Reified
>() {};}
*
*
> list(@Nonnull Type type) {
return (Reified
>) getParameterized(List.class, type);
}
/**
* Creates a {@link Set} type literal.
*
* @param type Item type.
* @param