You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by li...@apache.org on 2012/01/18 00:19:58 UTC

[6/14] [DELTASPIKE-45] Adding AnnotatedTypeBuilder and needed classes

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/952aa26f/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/metadata/builder/AnnotatedTypeBuilder.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/metadata/builder/AnnotatedTypeBuilder.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/metadata/builder/AnnotatedTypeBuilder.java
new file mode 100644
index 0000000..5b70ae2
--- /dev/null
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/metadata/builder/AnnotatedTypeBuilder.java
@@ -0,0 +1,987 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.deltaspike.core.api.metadata.builder;
+
+import org.apache.deltaspike.core.api.metadata.AnnotatedTypeImpl;
+import org.apache.deltaspike.core.api.metadata.AnnotationRedefiner;
+import org.apache.deltaspike.core.api.metadata.AnnotationStore;
+import org.apache.deltaspike.core.api.metadata.Parameter;
+import org.apache.deltaspike.core.api.metadata.RedefinitionContext;
+import org.apache.deltaspike.core.api.util.Reflections;
+
+import javax.enterprise.inject.spi.Annotated;
+import javax.enterprise.inject.spi.AnnotatedConstructor;
+import javax.enterprise.inject.spi.AnnotatedField;
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.inject.spi.AnnotatedParameter;
+import javax.enterprise.inject.spi.AnnotatedType;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ */
+//X TODO: Javadoc
+public class AnnotatedTypeBuilder<X>
+{
+    private Class<X> javaClass;
+    private final AnnotationBuilder typeAnnotations;
+
+    private final Map<Constructor<?>, AnnotationBuilder> constructors;
+    private final Map<Constructor<?>, Map<Integer, AnnotationBuilder>> constructorParameters;
+    private final Map<Constructor<?>, Map<Integer, Type>> constructorParameterTypes;
+
+    private final Map<Field, AnnotationBuilder> fields;
+    private final Map<Field, Type> fieldTypes;
+
+    private final Map<Method, AnnotationBuilder> methods;
+    private final Map<Method, Map<Integer, AnnotationBuilder>> methodParameters;
+    private final Map<Method, Map<Integer, Type>> methodParameterTypes;
+
+    /**
+     * Create a new builder. A new builder has no annotations and no members.
+     *
+     * @see #readFromType(AnnotatedType)
+     * @see #readFromType(Class)
+     * @see #readFromType(AnnotatedType, boolean)
+     * @see #readFromType(Class, boolean)
+     */
+    public AnnotatedTypeBuilder()
+    {
+        this.typeAnnotations = new AnnotationBuilder();
+        this.constructors = new HashMap<Constructor<?>, AnnotationBuilder>();
+        this.constructorParameters = new HashMap<Constructor<?>, Map<Integer, AnnotationBuilder>>();
+        this.constructorParameterTypes = new HashMap<Constructor<?>, Map<Integer, Type>>();
+        this.fields = new HashMap<Field, AnnotationBuilder>();
+        this.fieldTypes = new HashMap<Field, Type>();
+        this.methods = new HashMap<Method, AnnotationBuilder>();
+        this.methodParameters = new HashMap<Method, Map<Integer, AnnotationBuilder>>();
+        this.methodParameterTypes = new HashMap<Method, Map<Integer, Type>>();
+    }
+
+    /**
+     * Add an annotation to the type declaration.
+     *
+     * @param annotation the annotation instance to add
+     * @throws IllegalArgumentException if the annotation is null
+     */
+    public AnnotatedTypeBuilder<X> addToClass(Annotation annotation)
+    {
+        typeAnnotations.add(annotation);
+        return this;
+    }
+
+    /**
+     * Remove an annotation from the type
+     *
+     * @param annotationType the annotation type to remove
+     * @throws IllegalArgumentException if the annotationType
+     */
+    public AnnotatedTypeBuilder<X> removeFromClass(Class<? extends Annotation> annotationType)
+    {
+        typeAnnotations.remove(annotationType);
+        return this;
+    }
+
+    /**
+     * Add an annotation to the specified field. If the field is not already
+     * present, it will be added.
+     *
+     * @param field      the field to add the annotation to
+     * @param annotation the annotation to add
+     * @throws IllegalArgumentException if the annotation is null
+     */
+    public AnnotatedTypeBuilder<X> addToField(Field field, Annotation annotation)
+    {
+        if (fields.get(field) == null)
+        {
+            fields.put(field, new AnnotationBuilder());
+        }
+        fields.get(field).add(annotation);
+        return this;
+    }
+
+    /**
+     * Add an annotation to the specified field. If the field is not already
+     * present, it will be added.
+     *
+     * @param field      the field to add the annotation to
+     * @param annotation the annotation to add
+     * @throws IllegalArgumentException if the annotation is null
+     */
+    public AnnotatedTypeBuilder<X> addToField(AnnotatedField<? super X> field, Annotation annotation)
+    {
+        return addToField(field.getJavaMember(), annotation);
+    }
+
+    /**
+     * Remove an annotation from the specified field.
+     *
+     * @param field          the field to remove the annotation from
+     * @param annotationType the annotation type to remove
+     * @throws IllegalArgumentException if the annotationType is null or if the
+     *                                  field is not currently declared on the type
+     */
+    public AnnotatedTypeBuilder<X> removeFromField(Field field, Class<? extends Annotation> annotationType)
+    {
+        if (fields.get(field) == null)
+        {
+            throw new IllegalArgumentException("field " + field + " not present on class " + getJavaClass());
+        }
+        else
+        {
+            fields.get(field).remove(annotationType);
+        }
+        return this;
+    }
+
+    /**
+     * Remove an annotation from the specified field.
+     *
+     * @param field          the field to remove the annotation from
+     * @param annotationType the annotation type to remove
+     * @throws IllegalArgumentException if the annotationType is null or if the
+     *                                  field is not currently declared on the type
+     */
+    public AnnotatedTypeBuilder<X> removeFromField(AnnotatedField<? super X> field, Class<? extends Annotation> annotationType)
+    {
+        return removeFromField(field.getJavaMember(), annotationType);
+    }
+
+    /**
+     * Add an annotation to the specified method. If the method is not already
+     * present, it will be added.
+     *
+     * @param method     the method to add the annotation to
+     * @param annotation the annotation to add
+     * @throws IllegalArgumentException if the annotation is null
+     */
+    public AnnotatedTypeBuilder<X> addToMethod(Method method, Annotation annotation)
+    {
+        if (methods.get(method) == null)
+        {
+            methods.put(method, new AnnotationBuilder());
+        }
+        methods.get(method).add(annotation);
+        return this;
+    }
+
+    /**
+     * Add an annotation to the specified method. If the method is not already
+     * present, it will be added.
+     *
+     * @param method     the method to add the annotation to
+     * @param annotation the annotation to add
+     * @throws IllegalArgumentException if the annotation is null
+     */
+    public AnnotatedTypeBuilder<X> addToMethod(AnnotatedMethod<? super X> method, Annotation annotation)
+    {
+        return addToMethod(method.getJavaMember(), annotation);
+    }
+
+    /**
+     * Remove an annotation from the specified method.
+     *
+     * @param method         the method to remove the annotation from
+     * @param annotationType the annotation type to remove
+     * @throws IllegalArgumentException if the annotationType is null or if the
+     *                                  method is not currently declared on the type
+     */
+    public AnnotatedTypeBuilder<X> removeFromMethod(Method method, Class<? extends Annotation> annotationType)
+    {
+        if (methods.get(method) == null)
+        {
+            throw new IllegalArgumentException("Method " + method + " not present on class" + getJavaClass());
+        }
+        else
+        {
+            methods.get(method).remove(annotationType);
+        }
+        return this;
+    }
+
+    /**
+     * Remove an annotation from the specified method.
+     *
+     * @param method         the method to remove the annotation from
+     * @param annotationType the annotation type to remove
+     * @throws IllegalArgumentException if the annotationType is null or if the
+     *                                  method is not currently declared on the type
+     */
+    public AnnotatedTypeBuilder<X> removeFromMethod(AnnotatedMethod<? super X> method, Class<? extends Annotation> annotationType)
+    {
+        return removeFromMethod(method.getJavaMember(), annotationType);
+    }
+
+    /**
+     * Add an annotation to the specified method parameter. If the method is not
+     * already present, it will be added. If the method parameter is not already
+     * present, it will be added.
+     *
+     * @param method     the method to add the annotation to
+     * @param position   the position of the parameter to add
+     * @param annotation the annotation to add
+     * @throws IllegalArgumentException if the annotation is null
+     */
+    public AnnotatedTypeBuilder<X> addToMethodParameter(Method method, int position, Annotation annotation)
+    {
+        if (!methods.containsKey(method))
+        {
+            methods.put(method, new AnnotationBuilder());
+        }
+        if (methodParameters.get(method) == null)
+        {
+            methodParameters.put(method, new HashMap<Integer, AnnotationBuilder>());
+        }
+        if (methodParameters.get(method).get(position) == null)
+        {
+            methodParameters.get(method).put(position, new AnnotationBuilder());
+        }
+        methodParameters.get(method).get(position).add(annotation);
+        return this;
+    }
+
+    /**
+     * Remove an annotation from the specified method parameter.
+     *
+     * @param method         the method to remove the annotation from
+     * @param position       the position of the parameter to remove
+     * @param annotationType the annotation type to remove
+     * @throws IllegalArgumentException if the annotationType is null, if the
+     *                                  method is not currently declared on the type or if the
+     *                                  parameter is not declared on the method
+     */
+    public AnnotatedTypeBuilder<X> removeFromMethodParameter(Method method, int position, Class<? extends Annotation> annotationType)
+    {
+        if (methods.get(method) == null)
+        {
+            throw new IllegalArgumentException("Method " + method + " not present on class " + getJavaClass());
+        }
+        else
+        {
+            if (methodParameters.get(method).get(position) == null)
+            {
+                throw new IllegalArgumentException(String.format("parameter %s not present on method %s declared on class %s",
+                        method, position, getJavaClass()));
+            }
+            else
+            {
+                methodParameters.get(method).get(position).remove(annotationType);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Add an annotation to the specified constructor. If the constructor is not
+     * already present, it will be added.
+     *
+     * @param constructor the constructor to add the annotation to
+     * @param annotation  the annotation to add
+     * @throws IllegalArgumentException if the annotation is null
+     */
+    public AnnotatedTypeBuilder<X> addToConstructor(Constructor<X> constructor, Annotation annotation)
+    {
+        if (constructors.get(constructor) == null)
+        {
+            constructors.put(constructor, new AnnotationBuilder());
+        }
+        constructors.get(constructor).add(annotation);
+        return this;
+    }
+
+    /**
+     * Add an annotation to the specified constructor. If the constructor is not
+     * already present, it will be added.
+     *
+     * @param constructor the constructor to add the annotation to
+     * @param annotation  the annotation to add
+     * @throws IllegalArgumentException if the annotation is null
+     */
+    public AnnotatedTypeBuilder<X> addToConstructor(AnnotatedConstructor<X> constructor, Annotation annotation)
+    {
+        return addToConstructor(constructor.getJavaMember(), annotation);
+    }
+
+    /**
+     * Remove an annotation from the specified constructor.
+     *
+     * @param constructor    the constructor to add the annotation to
+     * @param annotationType the annotation to add
+     * @throws IllegalArgumentException if the annotationType is null or if the
+     *                                  constructor is not currently declared on the type
+     */
+    public AnnotatedTypeBuilder<X> removeFromConstructor(Constructor<X> constructor, Class<? extends Annotation> annotationType)
+    {
+        if (constructors.get(constructor) != null)
+        {
+            constructors.get(constructor).remove(annotationType);
+        }
+        return this;
+    }
+
+    /**
+     * Remove an annotation from the specified constructor.
+     *
+     * @param constructor    the constructor to add the annotation to
+     * @param annotationType the annotation to add
+     * @throws IllegalArgumentException if the annotationType is null, if the
+     *                                  annotation does not exist on the type or if the constructor is
+     *                                  not currently declared on the type
+     */
+    public AnnotatedTypeBuilder<X> removeFromConstructor(AnnotatedConstructor<X> constructor, Class<? extends Annotation> annotationType)
+    {
+        return removeFromConstructor(constructor.getJavaMember(), annotationType);
+    }
+
+    /**
+     * Add an annotation to the specified constructor parameter. If the
+     * constructor is not already present, it will be added. If the constructor
+     * parameter is not already present, it will be added.
+     *
+     * @param constructor the constructor to add the annotation to
+     * @param position    the position of the parameter to add
+     * @param annotation  the annotation to add
+     * @throws IllegalArgumentException if the annotation is null
+     */
+    public AnnotatedTypeBuilder<X> addToConstructorParameter(Constructor<X> constructor, int position, Annotation annotation)
+    {
+        if (!constructors.containsKey(constructor))
+        {
+            constructors.put(constructor, new AnnotationBuilder());
+        }
+        if (constructorParameters.get(constructor) == null)
+        {
+            constructorParameters.put(constructor, new HashMap<Integer, AnnotationBuilder>());
+        }
+        if (constructorParameters.get(constructor).get(position) == null)
+        {
+            constructorParameters.get(constructor).put(position, new AnnotationBuilder());
+        }
+        constructorParameters.get(constructor).get(position).add(annotation);
+        return this;
+    }
+
+    /**
+     * Remove an annotation from the specified constructor parameter.
+     *
+     * @param constructor    the constructor to remove the annotation from
+     * @param position       the position of the parameter to remove
+     * @param annotationType the annotation type to remove
+     * @throws IllegalArgumentException if the annotationType is null, if the
+     *                                  constructor is not currently declared on the type or if the
+     *                                  parameter is not declared on the constructor
+     */
+    public AnnotatedTypeBuilder<X> removeFromConstructorParameter(Constructor<X> constructor, int position, Class<? extends Annotation> annotationType)
+    {
+        if (constructorParameters.get(constructor) != null)
+        {
+            if (constructorParameters.get(constructor).get(position) != null)
+            {
+                constructorParameters.get(constructor).get(position).remove(annotationType);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Remove an annotation from the specified parameter.
+     *
+     * @param parameter      the parameter to remove the annotation from
+     * @param annotationType the annotation type to remove
+     * @throws IllegalArgumentException if the annotationType is null, if the
+     *                                  callable which declares the parameter is not currently declared
+     *                                  on the type or if the parameter is not declared on either a
+     *                                  constructor or a method
+     */
+    public AnnotatedTypeBuilder<X> removeFromParameter(AnnotatedParameter<? super X> parameter, Class<? extends Annotation> annotationType)
+    {
+        if (parameter.getDeclaringCallable().getJavaMember() instanceof Method)
+        {
+            Method method = (Method) parameter.getDeclaringCallable().getJavaMember();
+            return removeFromMethodParameter(method, parameter.getPosition(), annotationType);
+        }
+        if (parameter.getDeclaringCallable().getJavaMember() instanceof Constructor<?>)
+        {
+            @SuppressWarnings("unchecked")
+            Constructor<X> constructor = (Constructor<X>) parameter.getDeclaringCallable().getJavaMember();
+            return removeFromConstructorParameter(constructor, parameter.getPosition(), annotationType);
+        }
+        else
+        {
+            throw new IllegalArgumentException("Cannot remove from parameter " + parameter + " - cannot operate on member " + parameter.getDeclaringCallable().getJavaMember());
+        }
+    }
+
+    /**
+     * Add an annotation to the specified parameter. If the callable which
+     * declares the parameter is not already present, it will be added. If the
+     * parameter is not already present on the callable, it will be added.
+     *
+     * @param parameter  the parameter to add the annotation to
+     * @param annotation the annotation to add
+     * @throws IllegalArgumentException if the annotation is null or if the
+     *                                  parameter is not declared on either a constructor or a method
+     */
+    public AnnotatedTypeBuilder<X> addToParameter(AnnotatedParameter<? super X> parameter, Annotation annotation)
+    {
+        if (parameter.getDeclaringCallable().getJavaMember() instanceof Method)
+        {
+            Method method = (Method) parameter.getDeclaringCallable().getJavaMember();
+            return addToMethodParameter(method, parameter.getPosition(), annotation);
+        }
+        if (parameter.getDeclaringCallable().getJavaMember() instanceof Constructor<?>)
+        {
+            @SuppressWarnings("unchecked")
+            Constructor<X> constructor = (Constructor<X>) parameter.getDeclaringCallable().getJavaMember();
+            return addToConstructorParameter(constructor, parameter.getPosition(), annotation);
+        }
+        else
+        {
+            throw new IllegalArgumentException("Cannot remove from parameter " + parameter + " - cannot operate on member " + parameter.getDeclaringCallable().getJavaMember());
+        }
+    }
+
+    /**
+     * Remove annotations from the type, and all of it's members. If an
+     * annotation of the specified type appears on the type declaration, or any
+     * of it's members it will be removed.
+     *
+     * @param annotationType the type of annotation to remove
+     * @throws IllegalArgumentException if the annotationType is null
+     */
+    public AnnotatedTypeBuilder<X> removeFromAll(Class<? extends Annotation> annotationType)
+    {
+        if (annotationType == null)
+        {
+            throw new IllegalArgumentException(String.format("%s parameter must not be null", "annotationType"));
+        }
+        removeFromClass(annotationType);
+        for (Map.Entry<Field, AnnotationBuilder> field : fields.entrySet())
+        {
+            field.getValue().remove(annotationType);
+        }
+        for (Map.Entry<Method, AnnotationBuilder> method : methods.entrySet())
+        {
+            method.getValue().remove(annotationType);
+            if (methodParameters.get(method.getKey()) != null)
+            {
+                for (Map.Entry<Integer, AnnotationBuilder> parameter : methodParameters.get(method.getKey()).entrySet())
+                {
+                    parameter.getValue().remove(annotationType);
+                }
+            }
+        }
+        for (Map.Entry<Constructor<?>, AnnotationBuilder> constructor : constructors.entrySet())
+        {
+            constructor.getValue().remove(annotationType);
+            if (constructorParameters.get(constructor.getKey()) != null)
+            {
+                for (Map.Entry<Integer, AnnotationBuilder> parameter : constructorParameters.get(constructor.getKey()).entrySet())
+                {
+                    parameter.getValue().remove(annotationType);
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Redefine any annotations of the specified type. The redefinition callback
+     * will be invoked for any annotation on the type definition or any of it's
+     * members.
+     *
+     * @param annotationType the type of the annotation for which to call the
+     *                       redefinition
+     * @param redefinition   the redefiniton callback
+     * @throws IllegalArgumentException if the annotationType or redefinition is
+     *                                  null
+     */
+    public <A extends Annotation> AnnotatedTypeBuilder<X> redefine(Class<A> annotationType, AnnotationRedefiner<A> redefinition)
+    {
+        if (annotationType == null)
+        {
+            throw new IllegalArgumentException(String.format("%s parameter must not be null", "annotationType"));
+        }
+        if (redefinition == null)
+        {
+            throw new IllegalArgumentException(String.format("%s parameter must not be null", "redefinition"));
+        }
+        redefineAnnotationBuilder(annotationType, redefinition, javaClass, javaClass, typeAnnotations, null);
+        for (Map.Entry<Field, AnnotationBuilder> field : fields.entrySet())
+        {
+            redefineAnnotationBuilder(annotationType, redefinition, field.getKey(), field.getKey().getGenericType(), field.getValue(), field.getKey().getName());
+        }
+        for (Map.Entry<Method, AnnotationBuilder> method : methods.entrySet())
+        {
+            redefineAnnotationBuilder(annotationType, redefinition, method.getKey(), method.getKey().getGenericReturnType(), method.getValue(), method.getKey().getName());
+        }
+        for (Map.Entry<Constructor<?>, AnnotationBuilder> constructor : constructors.entrySet())
+        {
+            redefineAnnotationBuilder(annotationType, redefinition, constructor.getKey(), constructor.getKey().getDeclaringClass(), constructor.getValue(), null);
+        }
+        for (Map.Entry<Method, AnnotationBuilder> method : methods.entrySet())
+        {
+            if (methodParameters.get(method.getKey()) != null)
+            {
+                for (Map.Entry<Integer, AnnotationBuilder> parameter : methodParameters.get(method.getKey()).entrySet())
+                {
+                    Parameter<?> p = Parameter.create(method.getKey(), parameter.getKey());
+                    redefineAnnotationBuilder(annotationType, redefinition, p, p.getBaseType(), parameter.getValue(), null);
+                }
+            }
+        }
+        for (Map.Entry<Constructor<?>, AnnotationBuilder> constructor : constructors.entrySet())
+        {
+            if (constructorParameters.get(constructor.getKey()) != null)
+            {
+                for (Map.Entry<Integer, AnnotationBuilder> parameter : constructorParameters.get(constructor.getKey()).entrySet())
+                {
+                    Parameter<?> p = Parameter.create(constructor.getKey(), parameter.getKey());
+                    redefineAnnotationBuilder(annotationType, redefinition, p, p.getBaseType(), parameter.getValue(), null);
+                }
+            }
+        }
+        return this;
+    }
+
+    protected <A extends Annotation> void redefineAnnotationBuilder(Class<A> annotationType, AnnotationRedefiner<A> redefinition, AnnotatedElement annotated, Type baseType, AnnotationBuilder builder, String elementName)
+    {
+        if (builder.isAnnotationPresent(annotationType))
+        {
+            redefinition.redefine(new RedefinitionContext<A>(annotated, baseType, builder, elementName));
+        }
+    }
+
+    /**
+     * Reads in from an existing AnnotatedType. Any elements not present are
+     * added. The javaClass will be read in. If the annotation already exists on
+     * that element in the builder the read annotation will be used.
+     *
+     * @param type the type to read from
+     * @throws IllegalArgumentException if type is null
+     */
+    public AnnotatedTypeBuilder<X> readFromType(AnnotatedType<X> type)
+    {
+        return readFromType(type, true);
+    }
+
+    /**
+     * Reads in from an existing AnnotatedType. Any elements not present are
+     * added. The javaClass will be read in if overwrite is true. If the
+     * annotation already exists on that element in the builder, overwrite
+     * determines whether the original or read annotation will be used.
+     *
+     * @param type      the type to read from
+     * @param overwrite if true, the read annotation will replace any existing
+     *                  annotation
+     * @throws IllegalArgumentException if type is null
+     */
+    public AnnotatedTypeBuilder<X> readFromType(AnnotatedType<X> type, boolean overwrite)
+    {
+        if (type == null)
+        {
+            throw new IllegalArgumentException(String.format("%s parameter must not be null", "type"));
+        }
+        if (javaClass == null || overwrite)
+        {
+            this.javaClass = type.getJavaClass();
+        }
+        mergeAnnotationsOnElement(type, overwrite, typeAnnotations);
+        for (AnnotatedField<? super X> field : type.getFields())
+        {
+            if (fields.get(field.getJavaMember()) == null)
+            {
+                fields.put(field.getJavaMember(), new AnnotationBuilder());
+            }
+            mergeAnnotationsOnElement(field, overwrite, fields.get(field.getJavaMember()));
+        }
+        for (AnnotatedMethod<? super X> method : type.getMethods())
+        {
+            if (methods.get(method.getJavaMember()) == null)
+            {
+                methods.put(method.getJavaMember(), new AnnotationBuilder());
+            }
+            mergeAnnotationsOnElement(method, overwrite, methods.get(method.getJavaMember()));
+            for (AnnotatedParameter<? super X> p : method.getParameters())
+            {
+                if (methodParameters.get(method.getJavaMember()) == null)
+                {
+                    methodParameters.put(method.getJavaMember(), new HashMap<Integer, AnnotationBuilder>());
+                }
+                if (methodParameters.get(method.getJavaMember()).get(p.getPosition()) == null)
+                {
+                    methodParameters.get(method.getJavaMember()).put(p.getPosition(), new AnnotationBuilder());
+                }
+                mergeAnnotationsOnElement(p, overwrite, methodParameters.get(method.getJavaMember()).get(p.getPosition()));
+            }
+        }
+        for (AnnotatedConstructor<? super X> constructor : type.getConstructors())
+        {
+            if (constructors.get(constructor.getJavaMember()) == null)
+            {
+                constructors.put(constructor.getJavaMember(), new AnnotationBuilder());
+            }
+            mergeAnnotationsOnElement(constructor, overwrite, constructors.get(constructor.getJavaMember()));
+            for (AnnotatedParameter<? super X> p : constructor.getParameters())
+            {
+                if (constructorParameters.get(constructor.getJavaMember()) == null)
+                {
+                    constructorParameters.put(constructor.getJavaMember(), new HashMap<Integer, AnnotationBuilder>());
+                }
+                if (constructorParameters.get(constructor.getJavaMember()).get(p.getPosition()) == null)
+                {
+                    constructorParameters.get(constructor.getJavaMember()).put(p.getPosition(), new AnnotationBuilder());
+                }
+                mergeAnnotationsOnElement(p, overwrite, constructorParameters.get(constructor.getJavaMember()).get(p.getPosition()));
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Reads the annotations from an existing java type. Annotations already
+     * present will be overwritten
+     *
+     * @param type the type to read from
+     * @throws IllegalArgumentException if type is null
+     */
+    public AnnotatedTypeBuilder<X> readFromType(Class<X> type)
+    {
+        return readFromType(type, true);
+    }
+
+    /**
+     * Reads the annotations from an existing java type. If overwrite is true
+     * then existing annotations will be overwritten
+     *
+     * @param type      the type to read from
+     * @param overwrite if true, the read annotation will replace any existing
+     *                  annotation
+     */
+    public AnnotatedTypeBuilder<X> readFromType(Class<X> type, boolean overwrite)
+    {
+        if (type == null)
+        {
+            throw new IllegalArgumentException(String.format("%s parameter must not be null", "type"));
+        }
+        if (javaClass == null || overwrite)
+        {
+            this.javaClass = type;
+        }
+        for (Annotation annotation : type.getAnnotations())
+        {
+            if (overwrite || !typeAnnotations.isAnnotationPresent(annotation.annotationType()))
+            {
+                typeAnnotations.add(annotation);
+            }
+        }
+
+        for (Field field : Reflections.getAllDeclaredFields(type))
+        {
+            AnnotationBuilder annotationBuilder = fields.get(field);
+            if (annotationBuilder == null)
+            {
+                annotationBuilder = new AnnotationBuilder();
+                fields.put(field, annotationBuilder);
+            }
+            field.setAccessible(true);
+            for (Annotation annotation : field.getAnnotations())
+            {
+                if (overwrite || !annotationBuilder.isAnnotationPresent(annotation.annotationType()))
+                {
+                    annotationBuilder.add(annotation);
+                }
+            }
+        }
+
+        for (Method method : Reflections.getAllDeclaredMethods(type))
+        {
+            AnnotationBuilder annotationBuilder = methods.get(method);
+            if (annotationBuilder == null)
+            {
+                annotationBuilder = new AnnotationBuilder();
+                methods.put(method, annotationBuilder);
+            }
+            method.setAccessible(true);
+            for (Annotation annotation : method.getAnnotations())
+            {
+                if (overwrite || !annotationBuilder.isAnnotationPresent(annotation.annotationType()))
+                {
+                    annotationBuilder.add(annotation);
+                }
+            }
+
+            Map<Integer, AnnotationBuilder> parameters = methodParameters.get(method);
+            if (parameters == null)
+            {
+                parameters = new HashMap<Integer, AnnotationBuilder>();
+                methodParameters.put(method, parameters);
+            }
+            for (int i = 0; i < method.getParameterTypes().length; ++i)
+            {
+                AnnotationBuilder parameterAnnotationBuilder = parameters.get(i);
+                if (parameterAnnotationBuilder == null)
+                {
+                    parameterAnnotationBuilder = new AnnotationBuilder();
+                    parameters.put(i, parameterAnnotationBuilder);
+                }
+                for (Annotation annotation : method.getParameterAnnotations()[i])
+                {
+                    if (overwrite || !parameterAnnotationBuilder.isAnnotationPresent(annotation.annotationType()))
+                    {
+                        parameterAnnotationBuilder.add(annotation);
+                    }
+                }
+            }
+        }
+
+        for (Constructor<?> constructor : type.getDeclaredConstructors())
+        {
+            AnnotationBuilder annotationBuilder = constructors.get(constructor);
+            if (annotationBuilder == null)
+            {
+                annotationBuilder = new AnnotationBuilder();
+                constructors.put(constructor, annotationBuilder);
+            }
+            constructor.setAccessible(true);
+            for (Annotation annotation : constructor.getAnnotations())
+            {
+                if (overwrite || !annotationBuilder.isAnnotationPresent(annotation.annotationType()))
+                {
+                    annotationBuilder.add(annotation);
+                }
+            }
+            Map<Integer, AnnotationBuilder> mparams = constructorParameters.get(constructor);
+            if (mparams == null)
+            {
+                mparams = new HashMap<Integer, AnnotationBuilder>();
+                constructorParameters.put(constructor, mparams);
+            }
+            for (int i = 0; i < constructor.getParameterTypes().length; ++i)
+            {
+                AnnotationBuilder parameterAnnotationBuilder = mparams.get(i);
+                if (parameterAnnotationBuilder == null)
+                {
+                    parameterAnnotationBuilder = new AnnotationBuilder();
+                    mparams.put(i, parameterAnnotationBuilder);
+                }
+                for (Annotation annotation : constructor.getParameterAnnotations()[i])
+                {
+                    if (overwrite || !parameterAnnotationBuilder.isAnnotationPresent(annotation.annotationType()))
+                    {
+                        annotationBuilder.add(annotation);
+                    }
+                }
+            }
+        }
+        return this;
+    }
+
+    protected void mergeAnnotationsOnElement(Annotated annotated, boolean overwriteExisting, AnnotationBuilder typeAnnotations)
+    {
+        for (Annotation annotation : annotated.getAnnotations())
+        {
+            if (typeAnnotations.getAnnotation(annotation.annotationType()) != null)
+            {
+                if (overwriteExisting)
+                {
+                    typeAnnotations.remove(annotation.annotationType());
+                    typeAnnotations.add(annotation);
+                }
+            }
+            else
+            {
+                typeAnnotations.add(annotation);
+            }
+        }
+    }
+
+    /**
+     * Create an {@link AnnotatedType}. Any public members present on the
+     * underlying class and not overridden by the builder will be automatically
+     * added.
+     */
+    public AnnotatedType<X> create()
+    {
+        Map<Constructor<?>, Map<Integer, AnnotationStore>> constructorParameterAnnnotations = new HashMap<Constructor<?>, Map<Integer, AnnotationStore>>();
+        Map<Constructor<?>, AnnotationStore> constructorAnnotations = new HashMap<Constructor<?>, AnnotationStore>();
+        Map<Method, Map<Integer, AnnotationStore>> methodParameterAnnnotations = new HashMap<Method, Map<Integer, AnnotationStore>>();
+        Map<Method, AnnotationStore> methodAnnotations = new HashMap<Method, AnnotationStore>();
+        Map<Field, AnnotationStore> fieldAnnotations = new HashMap<Field, AnnotationStore>();
+
+        for (Map.Entry<Field, AnnotationBuilder> field : fields.entrySet())
+        {
+            fieldAnnotations.put(field.getKey(), field.getValue().create());
+        }
+
+        for (Map.Entry<Method, AnnotationBuilder> method : methods.entrySet())
+        {
+            methodAnnotations.put(method.getKey(), method.getValue().create());
+        }
+        for (Map.Entry<Method, Map<Integer, AnnotationBuilder>> parameters : methodParameters.entrySet())
+        {
+            Map<Integer, AnnotationStore> parameterAnnotations = new HashMap<Integer, AnnotationStore>();
+            methodParameterAnnnotations.put(parameters.getKey(), parameterAnnotations);
+            for (Map.Entry<Integer, AnnotationBuilder> parameter : parameters.getValue().entrySet())
+            {
+                parameterAnnotations.put(parameter.getKey(), parameter.getValue().create());
+            }
+        }
+
+        for (Map.Entry<Constructor<?>, AnnotationBuilder> constructor : constructors.entrySet())
+        {
+            constructorAnnotations.put(constructor.getKey(), constructor.getValue().create());
+        }
+        for (Map.Entry<Constructor<?>, Map<Integer, AnnotationBuilder>> parameters : constructorParameters.entrySet())
+        {
+            Map<Integer, AnnotationStore> parameterAnnotations = new HashMap<Integer, AnnotationStore>();
+            constructorParameterAnnnotations.put(parameters.getKey(), parameterAnnotations);
+            for (Map.Entry<Integer, AnnotationBuilder> parameter : parameters.getValue().entrySet())
+            {
+                parameterAnnotations.put(parameter.getKey(), parameter.getValue().create());
+            }
+        }
+
+        return new AnnotatedTypeImpl<X>(javaClass, typeAnnotations.create(), fieldAnnotations, methodAnnotations,
+                methodParameterAnnnotations, constructorAnnotations, constructorParameterAnnnotations, fieldTypes,
+                methodParameterTypes, constructorParameterTypes);
+    }
+
+    /**
+     * Override the declared type of a field
+     *
+     * @param field the field to override the type on
+     * @param type  the new type of the field
+     * @throws IllegalArgumentException if field or type is null
+     */
+    public void overrideFieldType(Field field, Type type)
+    {
+        if (field == null)
+        {
+            throw new IllegalArgumentException(String.format("%s parameter must not be null", "field"));
+        }
+        if (type == null)
+        {
+            throw new IllegalArgumentException(String.format("%s parameter must not be null", "type"));
+        }
+        fieldTypes.put(field, type);
+    }
+
+    /**
+     * Override the declared type of a field
+     *
+     * @param field the field to override the type on
+     * @param type  the new type of the field
+     * @throws IllegalArgumentException if field or type is null
+     */
+    public void overrideFieldType(AnnotatedField<? super X> field, Type type)
+    {
+        overrideFieldType(field.getJavaMember(), type);
+    }
+
+    /**
+     * Override the declared type of a method parameter
+     *
+     * @param method   the method to override the parameter type on
+     * @param position the position of the parameter to override the type on
+     * @param type     the new type of the parameter
+     * @throws IllegalArgumentException if parameter or type is null
+     */
+    public AnnotatedTypeBuilder<X> overrideMethodParameterType(Method method, int position, Type type)
+    {
+        if (method == null)
+        {
+            throw new IllegalArgumentException(String.format("%s parameter must not be null", "method"));
+        }
+        if (type == null)
+        {
+            throw new IllegalArgumentException(String.format("%s parameter must not be null", "type"));
+        }
+        if (methodParameterTypes.get(method) == null)
+        {
+            methodParameterTypes.put(method, new HashMap<Integer, Type>());
+        }
+        methodParameterTypes.get(method).put(position, type);
+        return this;
+    }
+
+    /**
+     * Override the declared type of a constructor parameter
+     *
+     * @param constructor the constructor to override the parameter type on
+     * @param position    the position of the parameter to override the type on
+     * @param type        the new type of the parameter
+     * @throws IllegalArgumentException if parameter or type is null
+     */
+    public AnnotatedTypeBuilder<X> overrideConstructorParameterType(Constructor<X> constructor, int position, Type type)
+    {
+        if (constructor == null)
+        {
+            throw new IllegalArgumentException(String.format("%s parameter must not be null", "constructor"));
+        }
+        if (type == null)
+        {
+            throw new IllegalArgumentException(String.format("%s parameter must not be null", "type"));
+        }
+        if (constructorParameterTypes.get(constructor) == null)
+        {
+            constructorParameterTypes.put(constructor, new HashMap<Integer, Type>());
+        }
+        constructorParameterTypes.get(constructor).put(position, type);
+        return this;
+    }
+
+    public AnnotatedTypeBuilder<X> overrideParameterType(AnnotatedParameter<? super X> parameter, Type type)
+    {
+        if (parameter.getDeclaringCallable().getJavaMember() instanceof Method)
+        {
+            Method method = (Method) parameter.getDeclaringCallable().getJavaMember();
+            return overrideMethodParameterType(method, parameter.getPosition(), type);
+        }
+        if (parameter.getDeclaringCallable().getJavaMember() instanceof Constructor<?>)
+        {
+            @SuppressWarnings("unchecked")
+            Constructor<X> constructor = (Constructor<X>) parameter.getDeclaringCallable().getJavaMember();
+            return overrideConstructorParameterType(constructor, parameter.getPosition(), type);
+        }
+        else
+        {
+            throw new IllegalArgumentException("Cannot remove from parameter " + parameter + " - cannot operate on member " + parameter.getDeclaringCallable().getJavaMember());
+        }
+    }
+
+    public Class<X> getJavaClass()
+    {
+        return javaClass;
+    }
+
+    public AnnotatedTypeBuilder<X> setJavaClass(Class<X> javaClass)
+    {
+        this.javaClass = javaClass;
+        return this;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/952aa26f/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/metadata/builder/AnnotationBuilder.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/metadata/builder/AnnotationBuilder.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/metadata/builder/AnnotationBuilder.java
new file mode 100644
index 0000000..427cf6a
--- /dev/null
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/metadata/builder/AnnotationBuilder.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.deltaspike.core.api.metadata.builder;
+
+import org.apache.deltaspike.core.api.metadata.AnnotationStore;
+import org.apache.deltaspike.core.api.util.Reflections;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ *
+ */
+//X TODO: JavaDoc the methods
+public class AnnotationBuilder
+{
+    private final Map<Class<? extends Annotation>, Annotation> annotationMap;
+    private final Set<Annotation> annotationSet;
+
+    public AnnotationBuilder()
+    {
+        this.annotationMap = new HashMap<Class<? extends Annotation>, Annotation>();
+        this.annotationSet = new HashSet<Annotation>();
+    }
+
+    public AnnotationBuilder add(Annotation annotation)
+    {
+        if (annotation == null)
+        {
+            throw new IllegalArgumentException("annotation parameter must not be null");
+        }
+        annotationSet.add(annotation);
+        annotationMap.put(annotation.annotationType(), annotation);
+        return this;
+    }
+
+    public AnnotationBuilder remove(Class<? extends Annotation> annotationType)
+    {
+        if (annotationType == null)
+        {
+            throw new IllegalArgumentException("annotationType parameter must not be null");
+        }
+
+        Iterator<Annotation> it = annotationSet.iterator();
+        while (it.hasNext())
+        {
+            Annotation an = it.next();
+            if (annotationType.isAssignableFrom(an.annotationType()))
+            {
+                it.remove();
+            }
+        }
+        annotationMap.remove(annotationType);
+        return this;
+    }
+
+    public AnnotationStore create()
+    {
+        return new AnnotationStore(annotationMap, annotationSet);
+    }
+
+    public AnnotationBuilder addAll(Set<Annotation> annotations)
+    {
+        for (Annotation annotation : annotations)
+        {
+            add(annotation);
+        }
+        return this;
+    }
+
+    public AnnotationBuilder addAll(AnnotationStore annotations)
+    {
+        for (Annotation annotation : annotations.getAnnotations())
+        {
+            add(annotation);
+        }
+        return this;
+    }
+
+    public AnnotationBuilder addAll(AnnotatedElement element)
+    {
+        for (Annotation a : element.getAnnotations())
+        {
+            add(a);
+        }
+        return this;
+    }
+
+    public <T extends Annotation> T getAnnotation(Class<T> anType)
+    {
+        return Reflections.<T>cast(annotationMap.get(anType));
+    }
+
+    public boolean isAnnotationPresent(Class<?> annotationType)
+    {
+        return annotationMap.containsKey(annotationType);
+    }
+
+    @Override
+    public String toString()
+    {
+        return annotationSet.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/952aa26f/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/util/HierarchyDiscovery.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/util/HierarchyDiscovery.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/util/HierarchyDiscovery.java
new file mode 100644
index 0000000..e80bc0d
--- /dev/null
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/util/HierarchyDiscovery.java
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.deltaspike.core.api.util;
+
+import org.apache.deltaspike.core.api.metadata.ParameterizedTypeImpl;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Utility class for resolving all bean types from a given type.
+ */
+//X TODO: Look at merging this with ClassUtils perhaps
+//X TODO: JavaDoc
+public class HierarchyDiscovery
+{
+    private final Type type;
+
+    private Map<Type, Class<?>> types;
+
+    public HierarchyDiscovery(Type type)
+    {
+        this.type = type;
+    }
+
+    protected void add(Class<?> clazz, Type type)
+    {
+        types.put(type, clazz);
+    }
+
+    public Set<Type> getTypeClosure()
+    {
+        if (types == null)
+        {
+            init();
+        }
+        // Return an independent set with no ties to the BiMap used
+        return new HashSet<Type>(types.keySet());
+    }
+
+    private void init()
+    {
+        this.types = new HashMap<Type, Class<?>>();
+        try
+        {
+            discoverTypes(type);
+        }
+        catch (StackOverflowError e)
+        {
+            System.out.println("type" + type);
+            Thread.dumpStack();
+            throw e;
+        }
+    }
+
+    public Type getResolvedType()
+    {
+        if (type instanceof Class<?>)
+        {
+            Class<?> clazz = (Class<?>) type;
+            return resolveType(clazz);
+        }
+        return type;
+    }
+
+    private void discoverTypes(Type type)
+    {
+        if (type != null)
+        {
+            if (type instanceof Class<?>)
+            {
+                Class<?> clazz = (Class<?>) type;
+                add(clazz, resolveType(clazz));
+                discoverFromClass(clazz);
+            }
+            else
+            {
+                Class<?> clazz = null;
+                if (type instanceof ParameterizedType)
+                {
+                    Type rawType = ((ParameterizedType) type).getRawType();
+                    if (rawType instanceof Class<?>)
+                    {
+                        discoverFromClass((Class<?>) rawType);
+                        clazz = (Class<?>) rawType;
+                    }
+                }
+                add(clazz, type);
+            }
+        }
+    }
+
+    private Type resolveType(Class<?> clazz)
+    {
+        if (clazz.getTypeParameters().length > 0)
+        {
+            TypeVariable<?>[] actualTypeParameters = clazz.getTypeParameters();
+            ParameterizedType parameterizedType = new ParameterizedTypeImpl(clazz, actualTypeParameters, clazz.getDeclaringClass());
+            return parameterizedType;
+        }
+        else
+        {
+            return clazz;
+        }
+    }
+
+    private void discoverFromClass(Class<?> clazz)
+    {
+        discoverTypes(resolveType(type, type, clazz.getGenericSuperclass()));
+        for (Type c : clazz.getGenericInterfaces())
+        {
+            discoverTypes(resolveType(type, type, c));
+        }
+    }
+
+    /**
+     * Gets the actual types by resolving TypeParameters.
+     *
+     * @param beanType
+     * @param type
+     * @return actual type
+     */
+    private Type resolveType(Type beanType, Type beanType2, Type type)
+    {
+        if (type instanceof ParameterizedType)
+        {
+            if (beanType instanceof ParameterizedType)
+            {
+                return resolveParameterizedType((ParameterizedType) beanType, (ParameterizedType) type);
+            }
+            if (beanType instanceof Class<?>)
+            {
+                return resolveType(((Class<?>) beanType).getGenericSuperclass(), beanType2, type);
+            }
+        }
+
+        if (type instanceof TypeVariable<?>)
+        {
+            if (beanType instanceof ParameterizedType)
+            {
+                return resolveTypeParameter((ParameterizedType) beanType, beanType2, (TypeVariable<?>) type);
+            }
+            if (beanType instanceof Class<?>)
+            {
+                return resolveType(((Class<?>) beanType).getGenericSuperclass(), beanType2, type);
+            }
+        }
+        return type;
+    }
+
+    private Type resolveParameterizedType(ParameterizedType beanType, ParameterizedType parameterizedType)
+    {
+        Type rawType = parameterizedType.getRawType();
+        Type[] actualTypes = parameterizedType.getActualTypeArguments();
+
+        Type resolvedRawType = resolveType(beanType, beanType, rawType);
+        Type[] resolvedActualTypes = new Type[actualTypes.length];
+
+        for (int i = 0; i < actualTypes.length; i++)
+        {
+            resolvedActualTypes[i] = resolveType(beanType, beanType, actualTypes[i]);
+        }
+        // reconstruct ParameterizedType by types resolved TypeVariable.
+        return new ParameterizedTypeImpl(resolvedRawType, resolvedActualTypes, parameterizedType.getOwnerType());
+    }
+
+    private Type resolveTypeParameter(ParameterizedType type, Type beanType, TypeVariable<?> typeVariable)
+    {
+        // step1. raw type
+        Class<?> actualType = (Class<?>) type.getRawType();
+        TypeVariable<?>[] typeVariables = actualType.getTypeParameters();
+        Type[] actualTypes = type.getActualTypeArguments();
+        for (int i = 0; i < typeVariables.length; i++)
+        {
+            if (typeVariables[i].equals(typeVariable) && !actualTypes[i].equals(typeVariable))
+            {
+                return resolveType(this.type, beanType, actualTypes[i]);
+            }
+        }
+
+        // step2. generic super class
+        Type genericSuperType = actualType.getGenericSuperclass();
+        Type resolvedGenericSuperType = resolveType(genericSuperType, beanType, typeVariable);
+        if (!(resolvedGenericSuperType instanceof TypeVariable<?>))
+        {
+            return resolvedGenericSuperType;
+        }
+
+        // step3. generic interfaces
+        if (beanType instanceof ParameterizedType)
+        {
+            for (Type interfaceType : ((Class<?>) ((ParameterizedType) beanType).getRawType()).getGenericInterfaces())
+            {
+                Type resolvedType = resolveType(interfaceType, interfaceType, typeVariable);
+                if (!(resolvedType instanceof TypeVariable<?>))
+                {
+                    return resolvedType;
+                }
+            }
+        }
+
+        // don't resolve type variable
+        return typeVariable;
+    }
+}