首次测试后嵌入 Arquillian TomEE javax.naming.ConfigurationException

Arquillian TomEE embedded javax.naming.ConfigurationException after first test

我正在使用嵌入了 TomEE 的 Arquillian 来测试 SpringLoggerBeanProducer,它使用 CDI 构造一个记录器对象,然后可以使用 bean producing 将其注入到 Spring 容器中方法。我 运行 关注的问题是可以生产 5 种类型的记录器。当我 运行 测试(每个测试产生一种类型的记录器)时,只有首先执行的测试成功,而所有后续测试都因 javax.naming.ConfigurationException 而失败。 看起来好像只有第一个测试是在 JEE 服务器环境中执行的,而其他的则不是。

生产者代码如下:

package mypackage.monitoring.spring.logger.producer;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.Set;

import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Annotated;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

import mypackage.monitoring.shared.logger.Logger;
import mypackage.monitoring.shared.qualifier.Application;
import mypackage.monitoring.shared.qualifier.Business;
import mypackage.monitoring.shared.qualifier.Security;
import mypackage.monitoring.shared.qualifier.Technical;

@Configuration
public class SpringLoggerBeanProducer {

private BeanManager beanManager;

@org.springframework.context.annotation.Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Application
public Logger applicationLogger(org.springframework.beans.factory.InjectionPoint springIp) {
    return logger(springIp);
}

@org.springframework.context.annotation.Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Business
public Logger businessLogger(org.springframework.beans.factory.InjectionPoint springIp) {
    return logger(springIp);
}

@org.springframework.context.annotation.Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Security
public Logger securityLogger(org.springframework.beans.factory.InjectionPoint springIp) {
    return logger(springIp);
}

@org.springframework.context.annotation.Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Technical
public Logger technicalLogger(org.springframework.beans.factory.InjectionPoint springIp) {
    return logger(springIp);
}

private Logger logger(org.springframework.beans.factory.InjectionPoint springIp) {
    setBeanManager();
    Field field = springIp.getField();
    Annotation[] qualifiers = getFieldQualifiers(field);
    Bean<? extends Object> bean = getLoggerBean(qualifiers);
    return getInjectableLoggerReference(field, bean);
}

private Logger getInjectableLoggerReference(Field field, Bean<?> bean) {
    CreationalContext<?> creationalContext = beanManager.createCreationalContext(bean);
    return (Logger) beanManager.getInjectableReference(getInjectionPoint(field), creationalContext);
}

private Bean<? extends Object> getLoggerBean(Annotation[] qualifiers) {
    Set<Bean<?>> beans = beanManager.getBeans(Logger.class, qualifiers);
    return beanManager.resolve(beans);
}

private Annotation[] getFieldQualifiers(Field field) {
    Annotation[] annotations = field.getAnnotations();

    Set<Annotation> qualifierSet = getQualifierSet(annotations);
    annotations = qualifierSet.toArray(new Annotation[0]);
    return annotations;
}

private void setBeanManager() {
    try {
        if (beanManager == null) {
            beanManager = InitialContext.doLookup("java:comp/BeanManager");
        }
    } catch (NamingException e) {
        throw new LoggerProducerException("BeanManager not found.", e);
    }
}

private Set<Annotation> getQualifierSet(Annotation[] annotations) {
    Set<Annotation> qualifierSet = new HashSet<Annotation>();
    for (Annotation annotation : annotations) {
        if (annotation.annotationType().isAnnotationPresent(javax.inject.Qualifier.class)) {
            qualifierSet.add(annotation);
        }
    }
    return qualifierSet;
}

private InjectionPoint getInjectionPoint(final Field member) {
    class GeneratedInjectionPoint implements InjectionPoint {

        @Override
        public boolean isTransient() {
            return Modifier.isTransient(member.getModifiers());
        }

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

        @Override
        public Type getType() {
            return member.getType();
        }

        @Override
        public Set<Annotation> getQualifiers() {
            Annotation[] annotations = member.getAnnotations();
            return getQualifierSet(annotations);
        }

        @Override
        public Member getMember() {
            return member;
        }

        @Override
        public Bean<?> getBean() {
            return null;
        }

        @Override
        public Annotated getAnnotated() {
            throw new UnsupportedOperationException("Method not implemented for " + this.getClass().getSimpleName() + ".class");
        }
    }

    return new GeneratedInjectionPoint();
}
}

异常发生在beanManager = InitialContext.doLookup("java:comp/BeanManager");

测试代码:

package mypackage.monitoring.spring.logger.producer;

import static org.junit.Assert.assertThat;

import java.lang.reflect.Field;

import javax.inject.Inject;

import org.hamcrest.Matchers;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.InjectionPoint;

import mypackage.monitoring.shared.event.MonitorEventType;
import mypackage.monitoring.shared.logger.Logger;
import mypackage.monitoring.shared.qualifier.Application;
import mypackage.monitoring.shared.qualifier.Business;
import mypackage.monitoring.shared.qualifier.Security;
import mypackage.monitoring.shared.qualifier.Technical;

@RunWith(Arquillian.class)
public class SpringLoggerBeanProducerIT<X> {

@Inject
private SpringLoggerBeanProducer producer;

private Logger defaultLogger;
@Application
private Logger applicationLogger;
@Business
private Logger businessLogger;
@Security
private Logger securityLogger;
@Technical
private Logger technicalLogger;

@Deployment
public static JavaArchive createDeployment() {
    return ShrinkWrap.create(JavaArchive.class).addPackages(true, "mypackage")
            .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
}

@Test
public void alsDefaultLoggerDanMonitorEventTypeTechnical() throws Exception {
    System.out.println("Default Logger");
    Logger logger = producer.applicationLogger(new InjectionPoint(this.getClass().getDeclaredField("defaultLogger")));

    assertThat(logger, Matchers.notNullValue());

    Field typeField = logger.getClass().getSuperclass().getDeclaredField("type");
    typeField.setAccessible(true);
    MonitorEventType type = (MonitorEventType) typeField.get(logger);

    assertThat(type, Matchers.is(MonitorEventType.TECHNICAL));
}

@Test
public void alsApplicationLoggerDanMonitorEventTypeApplication() throws Exception {
    System.out.println("Application Logger");
    Logger logger = producer.applicationLogger(new InjectionPoint(this.getClass().getDeclaredField("applicationLogger")));

    assertThat(logger, Matchers.notNullValue());

    Field typeField = logger.getClass().getSuperclass().getDeclaredField("type");
    typeField.setAccessible(true);
    MonitorEventType type = (MonitorEventType) typeField.get(logger);

    assertThat(type, Matchers.is(MonitorEventType.APPLICATION));
}

@Test
public void alsBusinessLoggerDanMonitorEventTypeBusiness() throws Exception {
    System.out.println("Business Logger");
    Logger logger = producer.applicationLogger(new InjectionPoint(this.getClass().getDeclaredField("businessLogger")));

    assertThat(logger, Matchers.notNullValue());

    Field typeField = logger.getClass().getSuperclass().getDeclaredField("type");
    typeField.setAccessible(true);
    MonitorEventType type = (MonitorEventType) typeField.get(logger);

    assertThat(type, Matchers.is(MonitorEventType.BUSINESS));
}

@Test
public void alsSecurityLoggerDanMonitorEventTypeSecurity() throws Exception {
    System.out.println("Security Logger");
    Logger logger = producer.applicationLogger(new InjectionPoint(this.getClass().getDeclaredField("securityLogger")));

    assertThat(logger, Matchers.notNullValue());

    Field typeField = logger.getClass().getSuperclass().getDeclaredField("type");
    typeField.setAccessible(true);
    MonitorEventType type = (MonitorEventType) typeField.get(logger);

    assertThat(type, Matchers.is(MonitorEventType.SECURITY));
}

@Test
public void alsTechnicalLoggerDanMonitorEventTypeTechnical() throws Exception {
    System.out.println("Technical Logger");
    Logger logger = producer.applicationLogger(new InjectionPoint(this.getClass().getDeclaredField("technicalLogger")));

    assertThat(logger, Matchers.notNullValue());

    Field typeField = logger.getClass().getSuperclass().getDeclaredField("type");
    typeField.setAccessible(true);
    MonitorEventType type = (MonitorEventType) typeField.get(logger);

    assertThat(type, Matchers.is(MonitorEventType.TECHNICAL));
}

}

我已将以下 Maven 依赖项添加到我的项目中:

    <!-- Arquillian junit testen -->
    <dependency>
        <groupId>org.jboss.arquillian.junit</groupId>
        <artifactId>arquillian-junit-container</artifactId>
        <version>1.1.9.FINAL</version>
        <scope>test</scope>
    </dependency>

    <!-- Arquillian adapter voor TomEE -->
    <dependency>
        <groupId>org.apache.openejb</groupId>
        <artifactId>arquillian-tomee-embedded</artifactId>
        <version>1.7.4</version>
        <scope>test</scope>
    </dependency>

    <!-- Embedded container TomEE -->
    <dependency>
        <groupId>org.apache.openejb</groupId>
        <artifactId>tomee-embedded</artifactId>
        <version>1.7.4</version>
        <scope>test</scope>
    </dependency>

Test results

Stacktrace

似乎应用程序的某些部分弄乱了 tomee JNDI space(一个 ibm 客户端 jar?)。您可以尝试强制上下文工厂:org.apache.openejb.core.OpenEJBInitialContextFactory

旁注:也许还升级到 tomee 7.0.3?