package tc.oc.commons.core.reflect; import java.lang.reflect.TypeVariable; import com.google.common.reflect.TypeParameter; import com.google.common.reflect.TypeResolver; import com.google.common.reflect.TypeToken; import com.google.inject.TypeLiteral; /** * Extends {@link TypeLiteral} with some methods used to resolve generic types. */ public abstract class ResolvableType<T> extends TypeLiteral<T> { /** * Fully resolve this type in the context of the given type */ public TypeLiteral<T> in(Class<?> declaringClass) { return Types.assertFullySpecified(Types.resolve(this, declaringClass)); } /** * Fully resolve this type by substituting this type's formal type * parameters with the given actual type arguments */ public TypeLiteral<T> with(TypeArgument<?>... arguments) { TypeToken<T> token = Types.toToken(this); for(TypeArgument arg : arguments) { token = token.where(arg, arg.actual()); } return Types.assertFullySpecified(Types.toLiteral(token)); } public <X> TypeLiteral<T> where(TypeParameter<X> parameter, TypeLiteral<X> type) { return where(parameter, Types.toToken(type)); } public <X> TypeLiteral<T> where(TypeParameter<X> parameter, TypeToken<X> type) { return Types.toLiteral(Types.assertFullySpecified(Types.toToken(this).where(parameter, type))); } public <X> TypeLiteral<T> where(tc.oc.commons.core.reflect.TypeParameter<X> parameter, TypeLiteral<X> type) { return where(parameter.typeVariable(), type); } public <X> TypeLiteral<T> where(tc.oc.commons.core.reflect.TypeParameter<X> parameter, TypeToken<X> type) { return where(parameter.typeVariable(), type); } public TypeLiteral<T> where(String name, TypeLiteral<?> type) { return where(Types.typeVariable(getRawType(), name), type); } public TypeLiteral<T> where(String name, TypeToken<?> type) { return where(Types.typeVariable(getRawType(), name), type); } public TypeLiteral<T> where(TypeVariable<?> typeVariable, TypeLiteral<?> type) { final TypeResolver resolver = new TypeResolver().where(typeVariable, type.getType()); return (TypeLiteral<T>) TypeLiteral.get(resolver.resolveType(getType())); } public TypeLiteral<T> where(TypeVariable<?> typeVariable, TypeToken<?> type) { final TypeResolver resolver = new TypeResolver().where(typeVariable, type.getType()); return (TypeLiteral<T>) TypeLiteral.get(resolver.resolveType(getType())); } /** * Fully resolve the given type in the context of this type */ public <U> TypeLiteral<U> resolve(TypeLiteral<U> type) { return Types.assertFullySpecified(Types.resolve(type, getRawType())); } }