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

org.apache.deltaspike.core.api.provider.BeanProvider Maven / Gradle / Ivy

/*
 * 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.provider;

import org.apache.deltaspike.core.api.literal.AnyLiteral;
import org.apache.deltaspike.core.api.projectstage.ProjectStage;
import org.apache.deltaspike.core.util.ProjectStageProducer;

import javax.enterprise.context.Dependent;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.Typed;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.InjectionTarget;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 

This class contains utility methods to resolve contextual references * in situations where no injection is available because the * current class is not managed by the CDI Container. This can happen * in e.g. a JPA-2.0 EntityListener, a ServletFilter, a Spring managed * Bean, etc.

* *

Attention: This method is intended for being used in user code at runtime. * If this method gets used during Container boot (in an Extension), non-portable * behaviour results. The CDI specification only allows injection of the * BeanManager during CDI-Container boot time.

* * @see BeanManagerProvider */ @Typed() public final class BeanProvider { private static final Logger LOG = Logger.getLogger(BeanProvider.class.getName()); private static final boolean LOG_DEPENDENT_WARNINGS; static { ProjectStage ps = ProjectStageProducer.getInstance().getProjectStage(); LOG_DEPENDENT_WARNINGS = ps.equals(ProjectStage.Development) || ps.equals(ProjectStage.UnitTest); } private BeanProvider() { // this is a utility class which doesn't get instantiated. } /** *

Get a Contextual Reference by its type and qualifiers. * You can use this method to get contextual references of a given type. * A 'Contextual Reference' is a proxy which will automatically resolve * the correct contextual instance when you access any method.

* *

Attention: You shall not use this method to manually resolve a * @Dependent bean! The reason is that this contextual instances do usually * live in the well-defined lifecycle of their injection point (the bean they got * injected into). But if we manually resolve a @Dependent bean, then it does not * belong to such a well defined lifecycle (because @Dependent it is not * @NormalScoped) and thus will not automatically be * destroyed at the end of the lifecycle. You need to manually destroy this contextual instance via * {@link javax.enterprise.context.spi.Contextual#destroy(Object, javax.enterprise.context.spi.CreationalContext)}. * Thus you also need to manually store the CreationalContext and the Bean you * used to create the contextual instance which this method will not provide.

* * @param type the type of the bean in question * @param qualifiers additional qualifiers which further distinct the resolved bean * @param target type * @return the resolved Contextual Reference * @throws IllegalStateException if the bean could not be found. * @see #getContextualReference(Class, boolean, Annotation...) */ public static T getContextualReference(Class type, Annotation... qualifiers) { return getContextualReference(type, false, qualifiers); } /** * {@link #getContextualReference(Class, Annotation...)} which returns null if the * 'optional' parameter is set to true. * * @param type the type of the bean in question * @param optional if true it will return null if no bean could be found or created. * Otherwise it will throw an {@code IllegalStateException} * @param qualifiers additional qualifiers which further distinct the resolved bean * @param target type * @return the resolved Contextual Reference * @see #getContextualReference(Class, Annotation...) */ public static T getContextualReference(Class type, boolean optional, Annotation... qualifiers) { BeanManager beanManager = getBeanManager(); return getContextualReference(beanManager, type, optional, qualifiers); } /** * {@link #getContextualReference(Class, Annotation...)} which returns null if the * 'optional' parameter is set to true. * This method is intended for usage where the BeanManger is known, e.g. in Extensions. * * @param beanManager the BeanManager to use * @param type the type of the bean in question * @param optional if true it will return null if no bean could be found or created. * Otherwise it will throw an {@code IllegalStateException} * @param qualifiers additional qualifiers which further distinct the resolved bean * @param target type * @return the resolved Contextual Reference * @see #getContextualReference(Class, Annotation...) */ public static T getContextualReference(BeanManager beanManager, Class type, boolean optional, Annotation... qualifiers) { Set> beans = beanManager.getBeans(type, qualifiers); if (beans == null || beans.isEmpty()) { if (optional) { return null; } throw new IllegalStateException("Could not find beans for Type=" + type + " and qualifiers:" + Arrays.toString(qualifiers)); } return getContextualReference(type, beanManager, beans); } /** *

Get a Contextual Reference by its EL Name. * This only works for beans with the @Named annotation.

* *

Attention: please see the notes on manually resolving @Dependent bean * in {@link #getContextualReference(Class, boolean, java.lang.annotation.Annotation...)}!

* * @param name the EL name of the bean * @return the resolved Contextual Reference * @throws IllegalStateException if the bean could not be found. * @see #getContextualReference(String, boolean) */ public static Object getContextualReference(String name) { return getContextualReference(name, false); } /** *

Get a Contextual Reference by its EL Name. * This only works for beans with the @Named annotation.

* *

Attention: please see the notes on manually resolving @Dependent bean * in {@link #getContextualReference(Class, boolean, java.lang.annotation.Annotation...)}!

* * @param name the EL name of the bean * @param optional if true it will return null if no bean could be found or created. * Otherwise it will throw an {@code IllegalStateException} * @return the resolved Contextual Reference */ public static Object getContextualReference(String name, boolean optional) { return getContextualReference(name, optional, Object.class); } /** *

Get a Contextual Reference by its EL Name. * This only works for beans with the @Named annotation.

* *

Attention: please see the notes on manually resolving @Dependent bean * in {@link #getContextualReference(Class, boolean, java.lang.annotation.Annotation...)}!

* * * @param name the EL name of the bean * @param optional if true it will return null if no bean could be found or created. * Otherwise it will throw an {@code IllegalStateException} * @param type the type of the bean in question - use {@link #getContextualReference(String, boolean)} * if the type is unknown e.g. in dyn. use-cases * @param target type * @return the resolved Contextual Reference */ public static T getContextualReference(String name, boolean optional, Class type) { BeanManager beanManager = getBeanManager(); Set> beans = beanManager.getBeans(name); if (beans == null || beans.isEmpty()) { if (optional) { return null; } throw new IllegalStateException("Could not find beans for Type=" + type + " and name:" + name); } return getContextualReference(type, beanManager, beans); } /** * Get the Contextual Reference for the given bean. * * @param type the type of the bean in question * @param bean bean-definition for the contextual-reference * @param target type * @return the resolved Contextual Reference */ public static T getContextualReference(Class type, Bean bean) { return getContextualReference(type, getBeanManager(), bean); } private static T getContextualReference(Class type, BeanManager beanManager, Bean bean) { //noinspection unchecked return getContextualReference(type, beanManager, new HashSet>((Collection) Arrays.asList(bean))); } /** *

Get a list of Contextual References by type independent of the qualifier * (including dependent scoped beans). * * You can use this method to get all contextual references of a given type. * A 'Contextual Reference' is a proxy which will automatically resolve * the correct contextual instance when you access any method.

* *

Attention: please see the notes on manually resolving @Dependent bean * in {@link #getContextualReference(Class, boolean, java.lang.annotation.Annotation...)}!

*

Attention: This will also return instances of beans for which an Alternative * exists! The @Alternative resolving is only done via {@link BeanManager#resolve(java.util.Set)} * which we cannot use in this case!

* * @param type the type of the bean in question * @param optional if true it will return an empty list if no bean could be found or created. * Otherwise it will throw an {@code IllegalStateException} * @param target type * @return the resolved list of Contextual Reference or an empty-list if optional is true */ public static List getContextualReferences(Class type, boolean optional) { return getContextualReferences(type, optional, true); } /** *

Get a list of Contextual References by type independent of the qualifier. * * Further details are available at {@link #getContextualReferences(Class, boolean)} *

Attention: please see the notes on manually resolving @Dependent bean * in {@link #getContextualReference(Class, boolean, java.lang.annotation.Annotation...)}!

*

Attention: This will also return instances of beans for which an Alternative * exists! The @Alternative resolving is only done via {@link BeanManager#resolve(java.util.Set)} * which we cannot use in this case!

* * @param type the type of the bean in question * @param optional if true it will return an empty list if no bean could be found or created. * Otherwise it will throw an {@code IllegalStateException} * @param includeDefaultScopedBeans specifies if dependent scoped beans should be included in the result * @param target type * @return the resolved list of Contextual Reference or an empty-list if optional is true */ public static List getContextualReferences(Class type, boolean optional, boolean includeDefaultScopedBeans) { BeanManager beanManager = getBeanManager(); Set> beans = getBeanDefinitions(type, optional, includeDefaultScopedBeans, beanManager); List result = new ArrayList(beans.size()); for (Bean bean : beans) { //noinspection unchecked result.add(getContextualReference(type, beanManager, bean)); } return result; } public static DependentProvider getDependent(Class type, Annotation... qualifiers) { BeanManager beanManager = getBeanManager(); Set> beans = beanManager.getBeans(type, qualifiers); Bean bean = beanManager.resolve(beans); return createDependentProvider(beanManager, type, (Bean) bean); } public static DependentProvider getDependent(String name) { BeanManager beanManager = getBeanManager(); Set> beans = beanManager.getBeans(name); Bean bean = beanManager.resolve(beans); Class beanClass = bean.getBeanClass(); return createDependentProvider(beanManager, (Class) beanClass, (Bean) bean); } private static DependentProvider createDependentProvider(BeanManager beanManager, Class type, Bean bean) { CreationalContext cc = beanManager.createCreationalContext(bean); T instance = (T) beanManager.getReference(bean, type, cc); return new DependentProvider(bean, cc, instance); } /** * Get a set of {@link Bean} definitions by type independent of the qualifier. * * @param type the type of the bean in question * @param optional if true it will return an empty set if no bean could be found. * Otherwise it will throw an {@code IllegalStateException} * @param includeDefaultScopedBeans specifies if dependent scoped beans should be included in the result * @param target type * @return the resolved set of {@link Bean} definitions or an empty-set if optional is true */ public static Set> getBeanDefinitions(Class type, boolean optional, boolean includeDefaultScopedBeans) { BeanManager beanManager = getBeanManager(); return getBeanDefinitions(type, optional, includeDefaultScopedBeans, beanManager); } private static Set> getBeanDefinitions(Class type, boolean optional, boolean includeDefaultScopedBeans, BeanManager beanManager) { Set> beans = beanManager.getBeans(type, new AnyLiteral()); if (beans == null || beans.isEmpty()) { if (optional) { return Collections.emptySet(); } throw new IllegalStateException("Could not find beans for Type=" + type); } if (!includeDefaultScopedBeans) { beans = filterDefaultScopedBeans(beans); } Set> result = new HashSet>(); for (Bean bean : beans) { //noinspection unchecked result.add((Bean) bean); } return result; } /** * Allows to perform dependency injection for instances which aren't managed by CDI. *

* Attention:
* The resulting instance isn't managed by CDI; only fields annotated with @Inject get initialized. * * @param instance current instance * @param current type * @return instance with injected fields (if possible - or null if the given instance is null) */ @SuppressWarnings("unchecked") public static T injectFields(T instance) { if (instance == null) { return null; } BeanManager beanManager = getBeanManager(); CreationalContext creationalContext = beanManager.createCreationalContext(null); AnnotatedType annotatedType = beanManager.createAnnotatedType(instance.getClass()); InjectionTarget injectionTarget = beanManager.createInjectionTarget(annotatedType); injectionTarget.inject(instance, creationalContext); return instance; } private static Set> filterDefaultScopedBeans(Set> beans) { Set> result = new HashSet>(beans.size()); Iterator> beanIterator = beans.iterator(); Bean currentBean; while (beanIterator.hasNext()) { currentBean = beanIterator.next(); if (!Dependent.class.isAssignableFrom(currentBean.getScope())) { result.add(currentBean); } } return result; } /** * Internal helper method to resolve the right bean and resolve the contextual reference. * * @param type the type of the bean in question * @param beanManager current bean-manager * @param beans beans in question * @param target type * @return the contextual reference */ private static T getContextualReference(Class type, BeanManager beanManager, Set> beans) { Bean bean = beanManager.resolve(beans); logWarningIfDependent(bean); CreationalContext creationalContext = beanManager.createCreationalContext(bean); @SuppressWarnings({ "unchecked", "UnnecessaryLocalVariable" }) T result = (T) beanManager.getReference(bean, type, creationalContext); return result; } /** * Log a warning if the produced creational instance is of * Scope @Dependent as we cannot properly cleanup * the contextual instance afterwards. */ private static void logWarningIfDependent(Bean bean) { if (LOG_DEPENDENT_WARNINGS && bean.getScope().equals(Dependent.class)) { LOG.log(Level.WARNING, "BeanProvider shall not be used to create @Dependent scoped beans. " + "Bean: " + bean.toString()); } } /** * Internal method to resolve the BeanManager via the {@link BeanManagerProvider} * @return current bean-manager */ private static BeanManager getBeanManager() { return BeanManagerProvider.getInstance().getBeanManager(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy