org.jboss.weld.introspector.jlr.WeldConstructorImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.weld.introspector.jlr.WeldConstructorImpl.java

Source

/*
 * JBoss, Home of Professional Open Source
 * Copyright 2008, Red Hat, Inc., and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * Licensed 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.jboss.weld.introspector.jlr;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.enterprise.inject.spi.AnnotatedConstructor;
import javax.enterprise.inject.spi.AnnotatedParameter;

import org.jboss.weld.exceptions.DefinitionException;
import org.jboss.weld.introspector.ConstructorSignature;
import org.jboss.weld.introspector.WeldClass;
import org.jboss.weld.introspector.WeldConstructor;
import org.jboss.weld.introspector.WeldParameter;
import org.jboss.weld.logging.messages.ReflectionMessage;
import org.jboss.weld.manager.BeanManagerImpl;
import org.jboss.weld.resources.ClassTransformer;
import org.jboss.weld.util.reflection.Formats;
import org.jboss.weld.util.reflection.HierarchyDiscovery;
import org.jboss.weld.util.reflection.Reflections;
import org.jboss.weld.util.reflection.SecureReflections;

import com.google.common.base.Supplier;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;

/**
 * Represents an annotated constructor
 * 
 * This class is immutable, and therefore threadsafe
 * 
 * @author Pete Muir
 * 
 * @param <T>
 */
public class WeldConstructorImpl<T> extends AbstractWeldCallable<T, T, Constructor<T>>
        implements WeldConstructor<T> {

    // The underlying constructor
    private final Constructor<T> constructor;

    // The list of parameter abstractions
    private final List<WeldParameter<?, T>> parameters;
    // The mapping of annotation -> parameter abstraction
    private final ListMultimap<Class<? extends Annotation>, WeldParameter<?, T>> annotatedParameters;

    private final ConstructorSignature signature;

    public static <T> WeldConstructor<T> of(Constructor<T> constructor, WeldClass<T> declaringClass,
            ClassTransformer classTransformer) {
        return new WeldConstructorImpl<T>(constructor, constructor.getDeclaringClass(),
                constructor.getDeclaringClass(), null,
                new HierarchyDiscovery(constructor.getDeclaringClass()).getTypeClosure(),
                buildAnnotationMap(constructor.getAnnotations()),
                buildAnnotationMap(constructor.getDeclaredAnnotations()), declaringClass, classTransformer);
    }

    public static <T> WeldConstructor<T> of(AnnotatedConstructor<T> annotatedConstructor,
            WeldClass<T> declaringClass, ClassTransformer classTransformer) {
        return new WeldConstructorImpl<T>(annotatedConstructor.getJavaMember(),
                annotatedConstructor.getJavaMember().getDeclaringClass(), annotatedConstructor.getBaseType(),
                annotatedConstructor, annotatedConstructor.getTypeClosure(),
                buildAnnotationMap(annotatedConstructor.getAnnotations()),
                buildAnnotationMap(annotatedConstructor.getAnnotations()), declaringClass, classTransformer);
    }

    /**
     * Constructor
     * 
     * Initializes the superclass with the build annotations map
     * 
     * @param constructor The constructor method
     * @param declaringClass The declaring class
     */
    private WeldConstructorImpl(Constructor<T> constructor, final Class<T> rawType, final Type type,
            AnnotatedConstructor<T> annotatedConstructor, Set<Type> typeClosure,
            Map<Class<? extends Annotation>, Annotation> annotationMap,
            Map<Class<? extends Annotation>, Annotation> declaredAnnotationMap, WeldClass<T> declaringClass,
            ClassTransformer classTransformer) {
        super(annotationMap, declaredAnnotationMap, classTransformer, constructor, rawType, type, typeClosure,
                declaringClass);
        this.constructor = constructor;

        this.parameters = new ArrayList<WeldParameter<?, T>>();
        annotatedParameters = Multimaps.newListMultimap(
                new HashMap<Class<? extends Annotation>, Collection<WeldParameter<?, T>>>(),
                new Supplier<List<WeldParameter<?, T>>>() {

                    public List<WeldParameter<?, T>> get() {
                        return new ArrayList<WeldParameter<?, T>>();
                    }

                });

        Map<Integer, AnnotatedParameter<?>> annotatedTypeParameters = new HashMap<Integer, AnnotatedParameter<?>>();

        if (annotatedConstructor != null) {
            for (AnnotatedParameter<?> annotated : annotatedConstructor.getParameters()) {
                annotatedTypeParameters.put(annotated.getPosition(), annotated);
            }
        }

        // If the class is a (non-static) member class, its constructors
        // parameterTypes array will prefix the
        // outer class instance, whilst the genericParameterTypes array isn't
        // prefix'd
        int nesting = Reflections.getNesting(declaringClass.getJavaClass());
        if (annotatedConstructor == null) {
            for (int i = 0; i < constructor.getParameterTypes().length; i++) {
                int gi = i - nesting;
                if (constructor.getParameterAnnotations()[i].length > 0) {
                    Class<? extends Object> clazz = constructor.getParameterTypes()[i];
                    Type parameterType;
                    if (constructor.getGenericParameterTypes().length > gi && gi >= 0) {
                        parameterType = constructor.getGenericParameterTypes()[gi];
                    } else {
                        parameterType = clazz;
                    }
                    WeldParameter<?, T> parameter = WeldParameterImpl.of(constructor.getParameterAnnotations()[i],
                            clazz, parameterType, this, i, classTransformer);
                    this.parameters.add(parameter);
                    for (Annotation annotation : parameter.getAnnotations()) {
                        if (MAPPED_PARAMETER_ANNOTATIONS.contains(annotation.annotationType())) {
                            annotatedParameters.put(annotation.annotationType(), parameter);
                        }
                    }
                } else {
                    Class<? extends Object> clazz = constructor.getParameterTypes()[i];
                    Type parameterType;
                    if (constructor.getGenericParameterTypes().length > gi && gi >= 0) {
                        parameterType = constructor.getGenericParameterTypes()[gi];
                    } else {
                        parameterType = clazz;
                    }
                    WeldParameter<?, T> parameter = WeldParameterImpl.of(new Annotation[0], clazz, parameterType,
                            this, i, classTransformer);
                    this.parameters.add(parameter);
                }
            }
        } else {
            if (annotatedConstructor.getParameters().size() != constructor.getParameterTypes().length) {
                throw new DefinitionException(ReflectionMessage.INCORRECT_NUMBER_OF_ANNOTATED_PARAMETERS_METHOD,
                        annotatedConstructor.getParameters().size(), annotatedConstructor,
                        annotatedConstructor.getParameters(), Arrays.asList(constructor.getParameterTypes()));
            } else {
                for (AnnotatedParameter<T> annotatedParameter : annotatedConstructor.getParameters()) {
                    WeldParameter<?, T> parameter = WeldParameterImpl.of(annotatedParameter.getAnnotations(),
                            constructor.getParameterTypes()[annotatedParameter.getPosition()],
                            annotatedParameter.getBaseType(), this, annotatedParameter.getPosition(),
                            classTransformer);
                    this.parameters.add(parameter);
                    for (Annotation annotation : parameter.getAnnotations()) {
                        if (MAPPED_PARAMETER_ANNOTATIONS.contains(annotation.annotationType())) {
                            annotatedParameters.put(annotation.annotationType(), parameter);
                        }
                    }
                }
            }

        }
        this.signature = new ConstructorSignatureImpl(this);
    }

    /**
     * Gets the constructor
     * 
     * @return The constructor
     */
    public Constructor<T> getAnnotatedConstructor() {
        return constructor;
    }

    /**
     * Gets the delegate (constructor)
     * 
     * @return The delegate
     */
    @Override
    public Constructor<T> getDelegate() {
        return constructor;
    }

    /**
     * Gets the abstracted parameters
     * 
     * If the parameters are null, initalize them first
     * 
     * @return A list of annotated parameter abstractions
     * 
     * @see org.jboss.weld.introspector.WeldConstructor#getWeldParameters()
     */
    public List<WeldParameter<?, T>> getWeldParameters() {
        return Collections.unmodifiableList(parameters);
    }

    /**
     * Gets parameter abstractions with a given annotation type.
     * 
     * If the parameters are null, they are initializes first.
     * 
     * @param annotationType The annotation type to match
     * @return A list of matching parameter abstractions. An empty list is
     *         returned if there are no matches.
     * 
     * @see org.jboss.weld.introspector.WeldConstructor#getWeldParameters(Class)
     */
    public List<WeldParameter<?, T>> getWeldParameters(Class<? extends Annotation> annotationType) {
        return Collections.unmodifiableList(annotatedParameters.get(annotationType));
    }

    /**
     * Creates a new instance
     * 
     * @param beanManager The Bean manager
     * @return An instance
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws IllegalArgumentException
     * 
     * @see org.jboss.weld.introspector.WeldConstructor#newInstance(BeanManagerImpl)
     */
    public T newInstance(Object... parameters) throws IllegalArgumentException, InstantiationException,
            IllegalAccessException, InvocationTargetException {
        return SecureReflections.ensureAccessible(getDelegate()).newInstance(parameters);
    }

    /**
     * The overridden equals operation
     * 
     * @param other The instance to compare to
     * @return True if equal, false otherwise
     */
    @Override
    public boolean equals(Object other) {

        if (super.equals(other) && other instanceof WeldConstructor<?>) {
            WeldConstructor<?> that = (WeldConstructor<?>) other;
            return this.getJavaMember().equals(that.getJavaMember())
                    && this.getWeldParameters().equals(that.getWeldParameters());
        }
        return false;
    }

    @Override
    public int hashCode() {
        int hash = 1;
        hash = hash * 31 + getJavaMember().hashCode();
        hash = hash * 31 + getWeldParameters().hashCode();
        return hash;
    }

    /**
     * Gets a string representation of the constructor
     * 
     * @return A string representation
     */
    @Override
    public String toString() {
        return "[constructor] " + Formats.addSpaceIfNeeded(Formats.formatAnnotations(getAnnotations()))
                + Formats.addSpaceIfNeeded(Formats.formatModifiers(getJavaMember().getModifiers()))
                + getDeclaringType().getName() + Formats.formatAsFormalParameterList(getWeldParameters());
    }

    public ConstructorSignature getSignature() {
        return signature;
    }

    public List<AnnotatedParameter<T>> getParameters() {
        return Collections.<AnnotatedParameter<T>>unmodifiableList(parameters);
    }

    public boolean isGeneric() {
        return getJavaMember().getTypeParameters().length > 0;
    }

}