You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java 1.8+mockejb初始化InitialContext遇ExceptionInInitializerError

解决MockEJB 0.6-beta2与Java 8兼容问题及替代方案

问题概述

使用MockEJB 0.6-beta2搭配Java 8搭建EJB测试项目时,执行ctx = new InitialContext();代码行抛出ExceptionInInitializerError,核心原因是MockEJB依赖的旧版CGLib无法适配Java 8的模块反射访问限制。

完整错误栈

java.lang.ExceptionInInitializerError
    at net.sf.cglib.core.KeyFactory$Generator.generateClass(KeyFactory.java:166)
    at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
    at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
    at net.sf.cglib.core.KeyFactory$Generator.create(KeyFactory.java:144)
    at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:116)
    at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:108)
    at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:104)
    at net.sf.cglib.proxy.Enhancer.<clinit>(Enhancer.java:69)
    at org.mockejb.interceptor.InterceptableProxy.create(InterceptableProxy.java:38)
    at org.mockejb.jndi.MockContextFactory.getInitialContext(MockContextFactory.java:47)
    at java.naming/javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:732)
    at java.naming/javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:305)
    at java.naming/javax.naming.InitialContext.init(InitialContext.java:236)
    at java.naming/javax.naming.InitialContext.<init>(InitialContext.java:184)
    at ar.com.clarin.suscripciones.servicios.impl.GestionarClienteComercialShould.setUp(GestionarClienteComercialShould.java:31)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
    at java.base/java.lang.reflect.Method.invoke(Method.java:577)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:93)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @cd2dae5
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
    at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:200)
    at java.base/java.lang.reflect.Method.setAccessible(Method.java:194)
    at net.sf.cglib.core.ReflectUtils$2.run(ReflectUtils.java:56)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:318)
    at net.sf.cglib.core.ReflectUtils.<clinit>(ReflectUtils.java:46)
    ... 36 more

测试代码

public class GestionarClienteComercialShould {

    private Context ctx;
    @Before
    public void setUp() throws Exception {
        // Setup the JNDI environment to use the MockEJB 
        // context factory
        MockContextFactory.setAsInitial();;
        // Create the initial context that will be used for binding EJBs
        ctx = new InitialContext(); 
    }
    @Test
    public void test() throws NamingException  {
                
                
        // Create an instance of the MockContainer
        MockContainer mc = new MockContainer(ctx);
        GestionarBPLocal gestionarBp = mock(GestionarBP.class);
        SessionBeanDescriptor dd = new SessionBeanDescriptor(
                   "java:comp/env/ejb/GestionarBP", 
                   GestionarBPLocal.class, GestionarBP.class,
                   gestionarBp) ;
        // Deploy our bean to the container allowing it to
        // be found via JNDI and tested
        mc.deploy(dd);
    }
}

POM依赖配置

<dependencies>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.26</version>
    </dependency>
    <!-- Test -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-inline</artifactId>
        <version>3.4.0</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.26</version>
        <scope>test</scope>
    </dependency>
    
    <dependency>
        <groupId>org.mockejb</groupId>
        <artifactId>mockejb</artifactId>
        <version>0.6-beta2</version>
        <scope>test</scope>
    </dependency>

</dependencies>

解决方案

临时修复MockEJB兼容问题

MockEJB 0.6-beta2依赖的CGLib版本过旧,可通过以下步骤修复:

  1. 在POM中添加兼容Java 8的CGLib依赖,覆盖旧版本:
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
    <scope>test</scope>
</dependency>
  1. 运行测试时添加JVM参数,开放模块访问权限:
--add-opens java.base/java.lang=ALL-UNNAMED

推荐替代EJB Mock库

MockEJB已多年未维护,推荐使用以下现代兼容方案:

1. EJB3Mock

专注EJB 3.x的轻量Mock库,支持JNDI与EJB容器模拟,API简洁,兼容Java 8+。
POM依赖:

<dependency>
    <groupId>org.ejb3unit</groupId>
    <artifactId>ejb3unit-core</artifactId>
    <version>0.9.8</version>
    <scope>test</scope>
</dependency>

2. Arquillian + Mockito

容器化测试框架,可配合Mockito模拟EJB依赖,支持真实/嵌入式容器,适配复杂EJB场景。
核心依赖:

<dependency>
    <groupId>org.jboss.arquillian.junit</groupId>
    <artifactId>arquillian-junit-container</artifactId>
    <version>1.7.0.Final</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>4.11.0</version>
    <scope>test</scope>
</dependency>

3. OpenEJB Embedded

使用嵌入式OpenEJB容器运行测试,无需Mock,适合需要真实EJB环境的场景,兼容Java 8+。
POM依赖:

<dependency>
    <groupId>org.apache.openejb</groupId>
    <artifactId>openejb-core</artifactId>
    <version>4.7.5</version>
    <scope>test</scope>
</dependency>

内容的提问来源于stack exchange,提问作者gerumato

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 19:50:46