All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.weld.resolution.ResolvableBuilder Maven / Gradle / Ivy

Go to download

This jar bundles all the bits of Weld and CDI required for running in a Servlet container.

There is a newer version: 6.0.0.Beta4
Show newest version
/*
 * 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.resolution;

import java.lang.annotation.Annotation;
import java.lang.annotation.Repeatable;
import java.lang.reflect.Executable;
import java.lang.reflect.Member;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import javax.enterprise.event.Event;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.New;
import javax.enterprise.inject.spi.AnnotatedParameter;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.Decorator;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.enterprise.inject.spi.InterceptionFactory;
import javax.enterprise.inject.spi.Interceptor;
import javax.inject.Named;
import javax.inject.Provider;

import org.jboss.weld.events.WeldEvent;
import org.jboss.weld.inject.WeldInstance;
import org.jboss.weld.literal.NamedLiteral;
import org.jboss.weld.logging.BeanManagerLogger;
import org.jboss.weld.logging.ResolutionLogger;
import org.jboss.weld.manager.BeanManagerImpl;
import org.jboss.weld.metadata.cache.MetaAnnotationStore;
import org.jboss.weld.util.reflection.Reflections;

public class ResolvableBuilder {

    private static final Class[] FACADE_TYPES = new Class[] { Event.class, Instance.class, WeldEvent.class,
        WeldInstance.class, Provider.class, InterceptionFactory.class };
    private static final Class[] METADATA_TYPES = new Class[] { Interceptor.class, Decorator.class, Bean.class };
    private static final Set ANY_SINGLETON = Collections.singleton(QualifierInstance.ANY);

    protected Class rawType;
    protected final Set types;
    protected final Set qualifierInstances;
    protected Bean declaringBean;
    private final MetaAnnotationStore store;
    protected boolean delegate;

    public ResolvableBuilder(final MetaAnnotationStore store) {
        this.store = store;
        this.types = new HashSet();
        this.qualifierInstances = new HashSet();
    }

    public ResolvableBuilder(BeanManagerImpl manager) {
        this(manager.getServices().get(MetaAnnotationStore.class));
    }

    public ResolvableBuilder(Type type, final BeanManagerImpl beanManager) {
        this(beanManager);
        if (type != null) {
            this.rawType = Reflections.getRawType(type);
            if (rawType == null || type instanceof TypeVariable) {
                throw ResolutionLogger.LOG.cannotExtractRawType(type);
            }
            this.types.add(type);
        }
    }

    public ResolvableBuilder(InjectionPoint injectionPoint, final BeanManagerImpl manager) {
        this(injectionPoint.getType(), manager);
        addQualifiers(injectionPoint.getQualifiers(), injectionPoint);
        setDeclaringBean(injectionPoint.getBean());
        this.delegate = injectionPoint.isDelegate();
    }

    public ResolvableBuilder setDeclaringBean(Bean declaringBean) {
        this.declaringBean = declaringBean;
        return this;
    }

    public ResolvableBuilder addType(Type type) {
        this.types.add(type);
        return this;
    }

    public ResolvableBuilder addTypes(Set types) {
        this.types.addAll(types);
        return this;
    }

    public boolean isDelegate() {
        return delegate;
    }

    public void setDelegate(boolean delegate) {
        this.delegate = delegate;
    }

    public Resolvable create() {
        if (qualifierInstances.isEmpty()) {
            this.qualifierInstances.add(QualifierInstance.DEFAULT);
        }
        for (Type type : types) {
            Class rawType = Reflections.getRawType(type);
            for (Class facadeType : FACADE_TYPES) {
                if (facadeType.equals(rawType)) {
                    return createFacade(facadeType);
                }
            }
            for (Class metadataType : METADATA_TYPES) {
                if (metadataType.equals(rawType)) {
                    return createMetadataProvider(metadataType);
                }
            }
        }
        return new ResolvableImpl(rawType, types, declaringBean, qualifierInstances, delegate);
    }

    private Resolvable createFacade(Class rawType) {
        Set types = Collections.singleton(rawType);
        return new ResolvableImpl(rawType, types, declaringBean, ANY_SINGLETON, delegate);
    }

    // just as facade but we keep the qualifiers so that we can recognize Bean from @Intercepted Bean.
    private Resolvable createMetadataProvider(Class rawType) {
        Set types = Collections.singleton(rawType);
        return new ResolvableImpl(rawType, types, declaringBean, qualifierInstances, delegate);
    }

    public ResolvableBuilder addQualifier(Annotation qualifier) {
        return addQualifier(qualifier, null);
    }

    private ResolvableBuilder addQualifier(Annotation qualifier, InjectionPoint injectionPoint) {
        QualifierInstance qualifierInstance = QualifierInstance.of(qualifier, store);
        final Class annotationType = qualifierInstance.getAnnotationClass();
        // Handle the @New qualifier special case
        if (annotationType.equals(New.class)) {
            New newQualifier = New.class.cast(qualifier);
            if (newQualifier.value().equals(New.class) && rawType == null) {
                throw new IllegalStateException("Cannot transform @New when there is no known raw type");
            } else if (newQualifier.value().equals(New.class)) {
                qualifier = New.Literal.of(rawType);
                qualifierInstance = QualifierInstance.of(qualifier, store);
            }
        } else if (injectionPoint != null && annotationType.equals(Named.class)) {
            Named named = (Named) qualifier;
            if (named.value().equals("")) {
                // WELD-1739
                // This is an injection point with an @Named qualifier, with no value specified, we need to assume the name of the field or parameter is the
                // value
                Member member = injectionPoint.getMember();
                if (member instanceof Executable) {
                    // Method or constructor injection
                    Executable executable = (Executable) member;
                    AnnotatedParameter annotatedParameter = (AnnotatedParameter) injectionPoint.getAnnotated();
                    Parameter parameter = executable.getParameters()[annotatedParameter.getPosition()];
                    named = new NamedLiteral(parameter.getName());
                } else {
                    named = new NamedLiteral(injectionPoint.getMember().getName());
                }

                qualifier = named;
                qualifierInstance = QualifierInstance.of(named, store);

            }
        }

        checkQualifier(qualifier, qualifierInstance, annotationType);
        this.qualifierInstances.add(qualifierInstance);
        return this;
    }

    /**
     * Adds a given qualifier without any checks. This method should be used with care.
     */
    public ResolvableBuilder addQualifierUnchecked(QualifierInstance qualifier) {
        this.qualifierInstances.add(qualifier);
        return this;
    }

    public ResolvableBuilder addQualifiers(Annotation[] qualifiers) {
        for (Annotation qualifier : qualifiers) {
            addQualifier(qualifier);
        }
        return this;
    }

    public ResolvableBuilder addQualifiers(Collection qualifiers) {
        return addQualifiers(qualifiers, null);
    }

    private ResolvableBuilder addQualifiers(Collection qualifiers, InjectionPoint injectionPoint) {
        for (Annotation qualifier : qualifiers) {
            addQualifier(qualifier, injectionPoint);
        }
        return this;
    }

    protected void checkQualifier(Annotation qualifier, final QualifierInstance qualifierInstance, Class annotationType) {
        if (!store.getBindingTypeModel(annotationType).isValid()) {
            throw BeanManagerLogger.LOG.invalidQualifier(qualifierInstance);
        }
        if (!annotationType.isAnnotationPresent(Repeatable.class)) {
            for (QualifierInstance checkedQualifier : qualifierInstances) {
                if (annotationType.equals(checkedQualifier.getAnnotationClass())) {
                    throw BeanManagerLogger.LOG.duplicateQualifiers(qualifierInstances);
                }
            }
        }
    }

    protected static class ResolvableImpl implements Resolvable {

        private final Set qualifierInstances;
        private final Set typeClosure;
        private final Class rawType;
        private final Bean declaringBean;
        private final boolean delegate;
        private final int hashCode;

        protected ResolvableImpl(Class rawType, Set typeClosure, Bean declaringBean, final Set qualifierInstances, boolean delegate) {
            this.typeClosure = typeClosure;
            this.rawType = rawType;
            this.declaringBean = declaringBean;
            this.qualifierInstances = qualifierInstances;
            this.delegate = delegate;
            this.hashCode = calculateHashCode();
        }

        @SuppressWarnings("checkstyle:magicnumber")
        private int calculateHashCode() {
            int hashCode = 17;
            hashCode = 31 * hashCode + this.getTypes().hashCode();
            return 31 * hashCode + this.qualifierInstances.hashCode();
        }

        @Override
        public Set getQualifiers() {
            return qualifierInstances;
        }

        @Override
        public Set getTypes() {
            return typeClosure;
        }

        @Override
        public Class getJavaClass() {
            return rawType;
        }

        @Override
        public Bean getDeclaringBean() {
            return declaringBean;
        }

        @Override
        public String toString() {
            return "Types: " + getTypes() + "; Bindings: " + getQualifiers();
        }

        @Override
        public int hashCode() {
            return hashCode;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o instanceof ResolvableImpl) {
                ResolvableImpl r = (ResolvableImpl) o;
                return this.getTypes().equals(r.getTypes()) && this.qualifierInstances.equals(r.qualifierInstances);
            }
            return false;
        }

        @Override
        public boolean isDelegate() {
            return delegate;
        }
    }

    protected MetaAnnotationStore getMetaAnnotationStore() {
        return store;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy