package org.jglue.cdiunit.internal; import com.google.common.collect.Maps; import org.jglue.cdiunit.ProducerConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.enterprise.context.Dependent; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.event.Observes; import javax.enterprise.inject.Any; import javax.enterprise.inject.Default; import javax.enterprise.inject.spi.*; import javax.enterprise.util.AnnotationLiteral; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; public class ProducerConfigExtension implements Extension { private static final Logger log = LoggerFactory.getLogger(ProducerConfigExtension.class); private final Method testMethod; @SuppressWarnings("unused") public ProducerConfigExtension() { this(null); } public ProducerConfigExtension(Method testMethod) { this.testMethod = testMethod; } @SuppressWarnings("unused") void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) throws Exception { Map<Class<? extends Annotation>, Annotation> values = Maps.newHashMap(); // get class annotations first: addConfigValues(values, testMethod.getDeclaringClass().getAnnotations()); // method annotations will override class annotations: addConfigValues(values, testMethod.getAnnotations()); for (final Annotation annotation : values.values()) { log.debug("Defining bean: value={} class={} ", annotation, annotation.getClass().getName()); AnnotatedType<? extends Annotation> at = bm.createAnnotatedType(annotation.getClass()); final InjectionTarget<? extends Annotation> it = bm.createInjectionTarget(at); abd.addBean(new Bean<Annotation>() { @Override public Class<?> getBeanClass() { return annotation.annotationType(); } @Override public Set<InjectionPoint> getInjectionPoints() { return it.getInjectionPoints(); } @Override public String getName() { return null; } @Override public Set<Annotation> getQualifiers() { Set<Annotation> qualifiers = new HashSet<Annotation>(); qualifiers.add(new AnnotationLiteral<Default>() {}); qualifiers.add(new AnnotationLiteral<Any>() {}); return qualifiers; } @Override public Class<? extends Annotation> getScope() { return Dependent.class; } @Override public Set<Class<? extends Annotation>> getStereotypes() { return Collections.emptySet(); } @Override public Set<Type> getTypes() { Set<Type> types = new HashSet<Type>(); types.add(annotation.annotationType()); types.add(Annotation.class); types.add(Object.class); return types; } @Override public boolean isAlternative() { return false; } @Override public boolean isNullable() { return false; } @Override public Annotation create(CreationalContext<Annotation> ctx) { // We return the same instance every time (despite @Dependent) // but Annotations are immutable and thus safe to share. return annotation; } @Override public void destroy(Annotation instance, CreationalContext<Annotation> ctx) { ctx.release(); } }); } } private static void addConfigValues(Map<Class<? extends Annotation>, Annotation> values, Annotation[] annotations) { for (final Annotation annotation : annotations) { if (!annotation.annotationType().isAnnotationPresent(ProducerConfig.class)) { continue; } if (!Modifier.isPublic(annotation.annotationType().getModifiers())) { throw new RuntimeException("ProducerConfig annotation classes must be public"); } values.put(annotation.annotationType(), annotation); } } }