/* * JBoss, Home of Professional Open Source * Copyright 2011, Red Hat, Inc. and/or its affiliates, 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.solder.bean.defaultbean; import static org.jboss.solder.util.collections.Multimaps.newSetMultimap; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.enterprise.event.Observes; import javax.enterprise.inject.Disposes; import javax.enterprise.inject.Produces; import javax.enterprise.inject.spi.AfterBeanDiscovery; import javax.enterprise.inject.spi.AfterDeploymentValidation; 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 javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import javax.enterprise.inject.spi.Extension; import javax.enterprise.inject.spi.ObserverMethod; import javax.enterprise.inject.spi.ProcessAnnotatedType; import javax.enterprise.inject.spi.ProcessBean; import javax.enterprise.inject.spi.ProcessObserverMethod; import javax.enterprise.inject.spi.ProcessProducerField; import javax.enterprise.inject.spi.ProcessProducerMethod; import org.apache.deltaspike.core.util.metadata.builder.AnnotatedTypeBuilder; import org.jboss.solder.logging.Logger; import org.jboss.solder.bean.Beans; import org.jboss.solder.bean.defaultbean.DefaultBean; import org.jboss.solder.literal.AnyLiteral; import org.jboss.solder.literal.DefaultLiteral; import org.jboss.solder.reflection.HierarchyDiscovery; import org.jboss.solder.reflection.Reflections; import org.jboss.solder.reflection.Synthetic; //import org.jboss.solder.reflection.annotated.AnnotatedTypeBuilder; import org.jboss.solder.util.collections.SetMultimap; import org.jboss.solder.util.collections.Supplier; /** * Registers beans annotated @DefaultBean * <p/> * During the ProcessAnnotatedTypePhase beans and producers annotated with @Default * have a synthetic qualifier added to them and existing qualifiers removed. * <p/> * During the ProcessBean phases these default beans are stored for later use * <p/> * If no alternative bean was observed for each of the default beans then the * stored bean is added as a forwarding bean with it's original set of * qualifiers * * @author Stuart Douglas */ public class DefaultBeanExtension implements Extension { private static final String QUALIFIER_NAMEPSACE = "org.jboss.solder.defaultbean"; private static final String PRODUCER_QUALIFIER_NAMEPSACE = "org.jboss.solder.defaultbean.producer"; private static final Logger log = Logger.getLogger(DefaultBeanExtension.class); private boolean beanDiscoveryOver = false; /** * list of all beans in the system */ private final List<Bean<?>> processedBeans = new LinkedList<Bean<?>>(); ; /** * stores type and qualifier information for default beans */ private final Map<Synthetic, DefaultBeanType> beanTypeInformation = new HashMap<Synthetic, DefaultBeanType>(); /** * all default managed beans */ private final Map<Synthetic, Bean<?>> defaultManagedBeans = new HashMap<Synthetic, Bean<?>>(); /** * all default producer beans */ private final Map<Synthetic, Bean<?>> defaultProducerMethods = new HashMap<Synthetic, Bean<?>>(); /** * all default producer fields */ private final Map<Synthetic, Bean<?>> defaultProducerFields = new HashMap<Synthetic, Bean<?>>(); /** * qualifiers for observer methods on default managed beans */ private final SetMultimap<Synthetic, ObserverMethodInfo<?>> defaultObserverMethodsByBean = newSetMultimap(new HashMap<Synthetic, Collection<ObserverMethodInfo<?>>>(), DefaultBeanExtension.<ObserverMethodInfo<?>>createHashSetSupplier()); private final Map<Method, ObserverMethodInfo<?>> defaultObserverMethods = new HashMap<Method, ObserverMethodInfo<?>>(); /** * map of producer method/field qualifiers to default bean synthetic * qualifiers */ private final Map<Synthetic, DefaultBeanQualifiers> producerToDeclaringDefaultBean = new HashMap<Synthetic, DefaultBeanQualifiers>(); /** * map of producer method info to the annotated method */ private final Map<Synthetic, DefaultProducerMethodInfo<?>> producerAnnotatedMethods = new HashMap<Synthetic, DefaultProducerMethodInfo<?>>(); /** * map of producer methods to the annotated field */ private final Map<Synthetic, AnnotatedField<?>> producerAnnotatedFields = new HashMap<Synthetic, AnnotatedField<?>>(); private final Synthetic.Provider syntheticProvider = new Synthetic.Provider(QUALIFIER_NAMEPSACE); private final Synthetic.Provider producerSyntheticProvider = new Synthetic.Provider(PRODUCER_QUALIFIER_NAMEPSACE); private final Set<Throwable> deploymentProblems = new HashSet<Throwable>(); <X> void processAnnotatedType(@Observes ProcessAnnotatedType<X> event, BeanManager beanManager) { boolean defaultBean = false; AnnotatedType<X> tp = event.getAnnotatedType(); AnnotatedTypeBuilder<X> builder = null; Synthetic declaringBeanSyntheticQualifier = null; Set<Annotation> declaringBeanQualifiers = null; if (event.getAnnotatedType().isAnnotationPresent(DefaultBean.class)) { Set<Annotation> qualifiers = new HashSet<Annotation>(); defaultBean = true; builder = new AnnotatedTypeBuilder<X>().readFromType(tp); for (Annotation a : tp.getAnnotations()) { // remove the qualifiers if (beanManager.isQualifier(a.annotationType())) { qualifiers.add(a); builder.removeFromClass(a.annotationType()); } } postProcessQualifierSet(qualifiers); builder.addToClass(new DefaultBeanInformation.Literal(qualifiers)); declaringBeanQualifiers = new HashSet<Annotation>(qualifiers); declaringBeanSyntheticQualifier = syntheticProvider.get(); // store the qualifiers for later beanTypeInformation.put(declaringBeanSyntheticQualifier, new DefaultBeanType(qualifiers, tp.getAnnotation(DefaultBean.class).value())); builder.addToClass(declaringBeanSyntheticQualifier); // now loop though observer methods and replace qualifiers for (AnnotatedMethod<? super X> m : tp.getMethods()) { AnnotatedParameter<? super X> observerParameter = null; for (AnnotatedParameter<? super X> p : m.getParameters()) { if (p.isAnnotationPresent(Observes.class)) { observerParameter = p; break; } } if (observerParameter != null) { // we have an observer method Set<Annotation> observerQualifiers = new HashSet<Annotation>(); for (Annotation a : observerParameter.getAnnotations()) { // remove all qualifiers if (beanManager.isQualifier(a.annotationType())) { observerQualifiers.add(a); builder.removeFromMethodParameter(m.getJavaMember(), observerParameter.getPosition(), a.annotationType()); } } postProcessQualifierSet(observerQualifiers); builder.addToMethodParameter(m.getJavaMember(), observerParameter.getPosition(), declaringBeanSyntheticQualifier); ObserverMethodInfo<?> info = ObserverMethodInfo.of(observerQualifiers, declaringBeanQualifiers, m, declaringBeanSyntheticQualifier); defaultObserverMethodsByBean.put(declaringBeanSyntheticQualifier, info); defaultObserverMethods.put(m.getJavaMember(), info); } } } final Set<Synthetic> producers = new HashSet<Synthetic>(); // now look for producer methods // if this bean is a default bean then all producers are default beans // otherwise the annotation needs to be present for (AnnotatedMethod<? super X> m : tp.getMethods()) { if (m.isAnnotationPresent(Produces.class) && (defaultBean || m.isAnnotationPresent(DefaultBean.class))) { if (declaringBeanQualifiers == null) { declaringBeanQualifiers = new HashSet<Annotation>(Beans.getQualifiers(beanManager, tp.getAnnotations())); if (declaringBeanQualifiers.isEmpty()) { declaringBeanQualifiers.add(DefaultLiteral.INSTANCE); } } if (builder == null) { builder = new AnnotatedTypeBuilder<X>().readFromType(tp); } Set<Annotation> qualifiers = new HashSet<Annotation>(); for (Annotation a : m.getAnnotations()) { // remove the qualifiers if (beanManager.isQualifier(a.annotationType())) { qualifiers.add(a); builder.removeFromMethod(m, a.annotationType()); } } postProcessQualifierSet(qualifiers); builder.addToMethod(m, new DefaultBeanInformation.Literal(qualifiers)); Synthetic syntheticQualifier = producerSyntheticProvider.get(); // store the qualifiers for later Type type = null; // if the type is not explicity set then we infer it if (m.isAnnotationPresent(DefaultBean.class)) { type = m.getAnnotation(DefaultBean.class).value(); } else { type = m.getJavaMember().getGenericReturnType(); } beanTypeInformation.put(syntheticQualifier, new DefaultBeanType(qualifiers, type)); builder.addToMethod(m, syntheticQualifier); producerToDeclaringDefaultBean.put(syntheticQualifier, new DefaultBeanQualifiers(declaringBeanSyntheticQualifier, declaringBeanQualifiers)); producers.add(syntheticQualifier); } } //now look for disposer methods if (!producers.isEmpty()) { for (AnnotatedMethod<? super X> m : tp.getMethods()) { for (AnnotatedParameter<? super X> p : m.getParameters()) { if (p.isAnnotationPresent(Disposes.class)) { Set<Type> type = p.getTypeClosure(); Set<Annotation> qualifiers = new HashSet<Annotation>(); for (final Annotation annotation : p.getAnnotations()) { if (beanManager.isQualifier(annotation.annotationType())) { qualifiers.add(annotation); } } postProcessQualifierSet(qualifiers); for (final Synthetic producer : producers) { final DefaultBeanType beanType = beanTypeInformation.get(producer); Set<Type> types = new HierarchyDiscovery(beanType.getType()).getTypeClosure(); if (Reflections.matches(type, types)) { if (beanType.getQualifiers().equals(qualifiers)) { for (final Annotation annotation : p.getAnnotations()) { if (beanManager.isQualifier(annotation.annotationType())) { builder.removeFromMethodParameter(m.getJavaMember(), p.getPosition(), annotation.annotationType()); } } builder.addToMethodParameter(m.getJavaMember(), p.getPosition(), producer); } } } } } } } for (AnnotatedField<? super X> f : tp.getFields()) { if (f.isAnnotationPresent(Produces.class) && (defaultBean || f.isAnnotationPresent(DefaultBean.class))) { if (declaringBeanQualifiers == null) { declaringBeanQualifiers = new HashSet<Annotation>(Beans.getQualifiers(beanManager, tp.getAnnotations())); if (declaringBeanQualifiers.isEmpty()) { declaringBeanQualifiers.add(DefaultLiteral.INSTANCE); } } // we do not support producer fields on normal scoped beans // as proxies prevent us from reading the fields for (Annotation i : tp.getAnnotations()) { if (beanManager.isNormalScope(i.annotationType())) { deploymentProblems.add(new RuntimeException("Default producer fields are not supported on normal scoped beans. Field: " + f + " Declaring Bean: " + tp)); } } if (builder == null) { builder = new AnnotatedTypeBuilder<X>().readFromType(tp); } Set<Annotation> qualifiers = new HashSet<Annotation>(); for (Annotation a : f.getAnnotations()) { // remove the qualifiers if (beanManager.isQualifier(a.annotationType())) { qualifiers.add(a); builder.removeFromField(f, a.annotationType()); } } postProcessQualifierSet(qualifiers); builder.addToField(f, new DefaultBeanInformation.Literal(qualifiers)); Synthetic syntheticQualifier = producerSyntheticProvider.get(); // store the qualifiers for later Type type = null; if (f.isAnnotationPresent(DefaultBean.class)) { type = f.getAnnotation(DefaultBean.class).value(); } else { type = f.getJavaMember().getGenericType(); } beanTypeInformation.put(syntheticQualifier, new DefaultBeanType(qualifiers, type)); builder.addToField(f, syntheticQualifier); producerToDeclaringDefaultBean.put(syntheticQualifier, new DefaultBeanQualifiers(declaringBeanSyntheticQualifier, declaringBeanQualifiers)); } } if (builder != null) { event.setAnnotatedType(builder.create()); } } <X> void processBean(@Observes ProcessBean<X> event) { // after the bean discovery is over we don't need to do any more // processing if (beanDiscoveryOver) { return; } Bean<X> b = event.getBean(); processedBeans.add(b); Synthetic qualifier = null; for (Annotation a : b.getQualifiers()) { if (a instanceof Synthetic) { Synthetic sa = (Synthetic) a; if (sa.namespace().equals(QUALIFIER_NAMEPSACE)) { qualifier = sa; break; } } } if (qualifier != null) { defaultManagedBeans.put(qualifier, b); } } <T, X> void processProducer(@Observes ProcessProducerMethod<T, X> event) { if (beanDiscoveryOver) { return; } Bean<X> b = event.getBean(); Synthetic qualifier = handleProducerBean(b); if (qualifier != null) { // store producer method information defaultProducerMethods.put(qualifier, event.getBean()); AnnotatedMethod<T> method = event.getAnnotatedProducerMethod(); AnnotatedMethod<T> disposerMethod = null; if (event.getAnnotatedDisposedParameter() != null) { disposerMethod = (AnnotatedMethod<T>) event.getAnnotatedDisposedParameter().getDeclaringCallable(); } producerAnnotatedMethods.put(qualifier, new DefaultProducerMethodInfo<T>(method, disposerMethod)); } } <T, X> void processProducer(@Observes ProcessProducerField<T, X> event) { if (beanDiscoveryOver) { return; } Bean<X> b = event.getBean(); Synthetic qualifier = handleProducerBean(b); if (qualifier != null) { defaultProducerFields.put(qualifier, event.getBean()); producerAnnotatedFields.put(qualifier, event.getAnnotatedProducerField()); } } <X> Synthetic handleProducerBean(Bean<X> b) { Synthetic qualifier = null; for (Annotation a : b.getQualifiers()) { if (a instanceof Synthetic) { Synthetic sa = (Synthetic) a; if (sa.namespace().equals(PRODUCER_QUALIFIER_NAMEPSACE)) { qualifier = sa; break; } } } return qualifier; } <T, X> void processObserverMethod(@Observes ProcessObserverMethod<T, X> event) { Synthetic qualifier = null; for (Annotation a : event.getObserverMethod().getObservedQualifiers()) { if (a instanceof Synthetic) { Synthetic sa = (Synthetic) a; if (sa.namespace().equals(QUALIFIER_NAMEPSACE)) { qualifier = sa; break; } } } if (qualifier != null) { ObserverMethodInfo<?> info = defaultObserverMethods.get(event.getAnnotatedMethod().getJavaMember()); info.setDelegate(event.getObserverMethod()); } } void afterBeanDiscovery(@Observes AfterBeanDiscovery event, BeanManager manager) { beanDiscoveryOver = true; // first check for duplicate default bean definitions Map<DefaultBeanType, Bean<?>> duplicateDetectionMap = new HashMap<DefaultBeanType, Bean<?>>(); for (Entry<Synthetic, DefaultBeanType> e : beanTypeInformation.entrySet()) { Bean<?> bean = defaultManagedBeans.get(e.getKey()); if (bean == null) { bean = defaultProducerMethods.get(e.getKey()); } if (bean == null) { bean = defaultProducerFields.get(e.getKey()); } if (duplicateDetectionMap.containsKey(e.getValue())) { Bean<?> other = duplicateDetectionMap.get(e.getValue()); deploymentProblems.add(new RuntimeException("Two default beans with the same type and qualifiers: Type: " + e.getValue().getType() + " Qualifiers: " + e.getValue().getQualifiers() + " Beans are " + other.toString() + " and " + bean.toString())); } duplicateDetectionMap.put(e.getValue(), bean); } // loop over all installed beans and see if they match any default beans if (beanTypeInformation.size() > 0) { for (Bean<?> processedBean : processedBeans) { Iterator<Entry<Synthetic, DefaultBeanType>> it = beanTypeInformation.entrySet().iterator(); while (it.hasNext()) { Entry<Synthetic, DefaultBeanType> definition = it.next(); if (definition.getValue().matches(processedBean)) { Synthetic qual = definition.getKey(); Bean<?> bean = null; // remove the default bean from the beans to be installed bean = defaultManagedBeans.remove(qual); if (bean == null) { bean = defaultProducerMethods.remove(qual); } if (bean == null) { bean = defaultProducerFields.remove(qual); } log.info("Preventing install of default bean " + bean); it.remove(); } } } } Set<Synthetic> allDefaultBeanQualifiers = new HashSet<Synthetic>(defaultManagedBeans.keySet()); allDefaultBeanQualifiers.addAll(defaultProducerFields.keySet()); allDefaultBeanQualifiers.addAll(defaultProducerMethods.keySet()); for (Synthetic qual : allDefaultBeanQualifiers) { final DefaultBeanType beanInfo = beanTypeInformation.get(qual); final HashSet<Type> types = new HashSet<Type>(); types.add(Object.class); types.add(beanInfo.getType()); final Set<Annotation> qualifiers = new HashSet<Annotation>(beanInfo.getQualifiers()); if (defaultManagedBeans.containsKey(qual)) { Bean<?> db = DefaultManagedBean.of(defaultManagedBeans.get(qual), beanInfo.getType(), types, qualifiers, manager); log.debug("Installing default managed bean " + db); event.addBean(db); Set<ObserverMethodInfo<?>> observers = defaultObserverMethodsByBean.get(qual); for (ObserverMethodInfo<?> i : observers) { DefaultObserverMethod<?, ?> obs = DefaultObserverMethod.of(i.getDelegate(), i.getAnnotatedMethod(), qualifiers, i.getObserverParameterQualifier(), db, manager); event.addObserverMethod(obs); } } else if (defaultProducerMethods.containsKey(qual)) { Synthetic declaringDefaultBean = this.producerToDeclaringDefaultBean.get(qual).getSyntheticQualifier(); Set<Annotation> declaringBeanQualifiers; if (declaringDefaultBean != null && !beanTypeInformation.containsKey(declaringDefaultBean)) { // this is a default producer method that was declared on a // default bean that has been replaced declaringBeanQualifiers = Collections.singleton((Annotation) declaringDefaultBean); } else { declaringBeanQualifiers = this.producerToDeclaringDefaultBean.get(qual).getQualifiers(); } DefaultProducerMethodInfo<?> info = producerAnnotatedMethods.get(qual); Bean<?> db = createDefaultProducerMethod(defaultProducerMethods.get(qual), qual, beanInfo, types, qualifiers, declaringBeanQualifiers, info, manager); log.debug("Installing default producer bean " + db); event.addBean(db); } else if (defaultProducerFields.containsKey(qual)) { Synthetic declaringDefaultBean = this.producerToDeclaringDefaultBean.get(qual).getSyntheticQualifier(); Set<Annotation> declaringBeanQualifiers; if (declaringDefaultBean != null && !beanTypeInformation.containsKey(declaringDefaultBean)) { // this is a default producer method that was declared on a // default bean that has been replaced declaringBeanQualifiers = Collections.singleton((Annotation) declaringDefaultBean); } else { declaringBeanQualifiers = this.producerToDeclaringDefaultBean.get(qual).getQualifiers(); } Bean<?> db = DefaultProducerField.of(defaultProducerFields.get(qual), beanInfo.getType(), types, qualifiers, declaringBeanQualifiers, producerAnnotatedFields.get(qual), manager); log.debug("Installing default producer bean " + db); event.addBean(db); } } for (Throwable e : deploymentProblems) { event.addDefinitionError(e); } } void afterDeploymentValidation(@Observes AfterDeploymentValidation event) { this.processedBeans.clear(); this.beanTypeInformation.clear(); this.producerToDeclaringDefaultBean.clear(); this.producerSyntheticProvider.clear(); this.producerAnnotatedFields.clear(); this.producerAnnotatedMethods.clear(); } private static class DefaultBeanType { private final Set<Annotation> qualifiers; private final Type type; public DefaultBeanType(Set<Annotation> qualifiers, Type type) { this.qualifiers = new HashSet<Annotation>(qualifiers); this.type = type; } public Set<Annotation> getQualifiers() { return qualifiers; } public Type getType() { return type; } private boolean matches(Bean<?> bean) { if (bean.getTypes().contains(type)) { for (Annotation a : qualifiers) { if (!bean.getQualifiers().contains(a)) { return false; } } return true; } return false; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((qualifiers == null) ? 0 : qualifiers.hashCode()); result = prime * result + ((type == null) ? 0 : type.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; DefaultBeanType other = (DefaultBeanType) obj; if (qualifiers == null) { if (other.qualifiers != null) return false; } else if (!qualifiers.equals(other.qualifiers)) return false; if (type == null) { if (other.type != null) return false; } else if (!type.equals(other.type)) return false; return true; } } private static class ObserverMethodInfo<T> { private final Set<Annotation> observerParameterQualifier; private final Set<Annotation> declaringBeanQualfiers; private final AnnotatedMethod<T> annotatedMethod; private final Synthetic defaultBeanSynthetic; private ObserverMethod<?> delegate; public static <T> ObserverMethodInfo<T> of(Set<Annotation> observerParameterQualifier, Set<Annotation> declaringBeanQualfiers, AnnotatedMethod<T> annotatedMethod, Synthetic defaultBeanSynthetic) { return new ObserverMethodInfo<T>(observerParameterQualifier, declaringBeanQualfiers, annotatedMethod, defaultBeanSynthetic); } public ObserverMethodInfo(Set<Annotation> observerParameterQualifier, Set<Annotation> declaringBeanQualfiers, AnnotatedMethod<T> annotatedMethod, Synthetic defaultBeanSynthetic) { this.observerParameterQualifier = observerParameterQualifier; this.declaringBeanQualfiers = declaringBeanQualfiers; this.annotatedMethod = annotatedMethod; this.defaultBeanSynthetic = defaultBeanSynthetic; } public Set<Annotation> getObserverParameterQualifier() { return observerParameterQualifier; } public AnnotatedMethod<T> getAnnotatedMethod() { return annotatedMethod; } public ObserverMethod<?> getDelegate() { return delegate; } public void setDelegate(ObserverMethod<?> delegate) { this.delegate = delegate; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((declaringBeanQualfiers == null) ? 0 : declaringBeanQualfiers.hashCode()); result = prime * result + ((observerParameterQualifier == null) ? 0 : observerParameterQualifier.hashCode()); result = prime * result + ((defaultBeanSynthetic == null) ? 0 : defaultBeanSynthetic.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ObserverMethodInfo<?> other = (ObserverMethodInfo<?>) obj; if (annotatedMethod == null) { if (other.annotatedMethod != null) return false; } else if (!annotatedMethod.equals(other.annotatedMethod)) return false; if (declaringBeanQualfiers == null) { if (other.declaringBeanQualfiers != null) return false; } else if (!declaringBeanQualfiers.equals(other.declaringBeanQualfiers)) return false; if (observerParameterQualifier == null) { if (other.observerParameterQualifier != null) return false; } else if (!observerParameterQualifier.equals(other.observerParameterQualifier)) return false; if (defaultBeanSynthetic == null) { if (other.defaultBeanSynthetic != null) return false; } else if (!defaultBeanSynthetic.equals(other.defaultBeanSynthetic)) return false; return true; } } private final class DefaultProducerMethodInfo<X> { private final AnnotatedMethod<X> producerMethod; private final AnnotatedMethod<X> disposerMethod; public DefaultProducerMethodInfo(AnnotatedMethod<X> producerMethod, AnnotatedMethod<X> disposerMethod) { this.producerMethod = producerMethod; this.disposerMethod = disposerMethod; } public AnnotatedMethod<X> getProducerMethod() { return producerMethod; } public AnnotatedMethod<X> getDisposerMethod() { return disposerMethod; } } private static <T> Supplier<Set<T>> createHashSetSupplier() { return new Supplier<Set<T>>() { public Set<T> get() { return new HashSet<T>(); } }; } private <T, X> DefaultProducerMethod<T, X> createDefaultProducerMethod(Bean<T> originalBean, Annotation qualifier, DefaultBeanType beanInfo, Set<Type> types, Set<Annotation> qualifiers, Set<Annotation> declaringBeanQualifiers, DefaultProducerMethodInfo<X> info, BeanManager beanManager) { return DefaultProducerMethod.of(originalBean, beanInfo.getType(), types, qualifiers, declaringBeanQualifiers, info.getProducerMethod(), info.getDisposerMethod(), beanManager); } private static class DefaultBeanQualifiers { private Synthetic syntheticQualifier; private Set<Annotation> qualifiers; public DefaultBeanQualifiers(Synthetic syntheticQualifier, Set<Annotation> qualifiers) { this.syntheticQualifier = syntheticQualifier; this.qualifiers = qualifiers; } public Synthetic getSyntheticQualifier() { return syntheticQualifier; } public Set<Annotation> getQualifiers() { return qualifiers; } } private Set<Annotation> postProcessQualifierSet(Set<Annotation> qualifiers) { if (qualifiers.isEmpty()) { qualifiers.add(DefaultLiteral.INSTANCE); } qualifiers.add(AnyLiteral.INSTANCE); return qualifiers; } }