package org.etk.reflect.core; import java.util.HashMap; import java.util.Map; import org.etk.reflect.api.TypeInfo; import org.etk.reflect.api.TypeResolver; import org.etk.reflect.api.definition.TypeKind; import org.etk.reflect.api.metadata.AnnotationMetadata; import org.etk.reflect.api.metadata.FieldMetadata; import org.etk.reflect.api.metadata.MethodMetadata; import org.etk.reflect.api.metadata.ReflectionMetadata; import org.etk.reflect.api.metadata.TypeMetadata; public class TypeResolverImpl<T, M, A, P, F> implements TypeResolver<T> { public static <T, M, A, P, F> TypeResolver<T> create(ReflectionMetadata<T, M, A, P, F> model) { return new TypeResolverImpl<T, M, A, P, F>(model, true); } public static <T, M, A, P, F> TypeResolver<T> create(ReflectionMetadata<T, M, A, P, F> model, boolean cache) { return new TypeResolverImpl<T, M, A, P, F>(model, cache); } /** * Define the typeOfModel */ final TypeMetadata<T> typeMetadata; /** * Define the fields which belong the class. */ final FieldMetadata<T, F> fieldMetadata; final MethodMetadata<T, M> methodMetadata; final AnnotationMetadata<T, T, A, P> typeAnnotationMetadata; final AnnotationMetadata<T, F, A, P> fieldAnnotationMetadata; final AnnotationMetadata<T, M, A, P> methodAnnotationMetadata; final Map<T, AbstractTypeInfo<T, M, A, P, F>> cache; private TypeResolverImpl(ReflectionMetadata<T, M, A, P, F> model, boolean cache) { this.typeMetadata = model.getTypeModel(); this.fieldMetadata = model.getFieldModel(); this.methodMetadata = model.getMethodModel(); this.typeAnnotationMetadata = model.getTypeAnnotationMetadata(); this.fieldAnnotationMetadata = model.getFieldAnnotationMetadata(); this.methodAnnotationMetadata = model.getMethodAnnotationMetadata(); this.cache = cache ? new HashMap<T, AbstractTypeInfo<T, M, A, P, F>>() : null; } public TypeInfo resolve(T type) throws NullPointerException { if (type == null) { throw new NullPointerException("No null type accepted"); } return getType(type); } public void clear() { if (cache != null) { cache.clear(); } } /** * Getting the TypeInfo base on the type parameter. * @param type * @return AbstractTypeInfo */ AbstractTypeInfo<T, M, A, P, F> getType(T type) { if (cache == null) { return build(type); } else { AbstractTypeInfo<T, M, A, P, F> cached = cache.get(type); if (cached == null) { cached = build(type); cache.put(type, cached); } return cached; } } /** * Building the InfoType base on the type parameter. * @param type * @return */ private AbstractTypeInfo<T, M, A, P, F> build(T type) { //Determines the TypeKind of a given TypeInfo. TypeKind kind = typeMetadata.getKind(type); switch (kind) { case SIMPLE: return new SimpleTypeInfoImpl<T, M, A, P, F>(this, type); case VOID: return new VoidTypeInfoImpl<T, M, A, P, F>(this, type); case CLASS: return new ClassTypeInfoImpl<T, M, A, P, F>(this, type); case PARAMETERIZED: return new ParameterizedTypeInfoImpl<T, M, A, P, F>(this, type); case VARIABLE: return new TypeVariableInfoImpl<T, M, A, P, F>(this, type); case WILDCARD: return new WildcardTypeInfoImpl<T, M, A, P, F>(this, type); case ARRAY: return new ArrayTypeInfoImpl<T, M, A, P, F>(this, type); default: throw new AssertionError("Cannot handle type " + type + " with kind " + kind); } } }