2011-11-21 58 views
2

我正在通过maven和嵌入式glassfish容器在EJBS上运行一些单元测试。我的一个测试工作,但所有的后续尝试在同一错误测试不同的EJB结果:ClassCastException当使用嵌入式glassfish进行单元测试

java.lang.ClassCastException: $Proxy81 cannot be cast to 

其次是什么豆,我尝试测试。我相信我的设置很好,因为正如我所说,我的一个豆子可以正确测试。的workiing代码

实例:

@Stateful 
public class LayoutManagerBean implements LayoutManager { 

    private final Log LOG = LogFactory.getLog(LayoutManagerBean.class); 



    public List<Menu> getMenus(User currentUser) { 
     ... 
    } 

} 

@Local 
public interface LayoutManager { 

    public List<Menu> getMenus(User user); 

} 

并且测试:

public class LayoutManagerTest { 

    private static EJBContainer ejbContainer; 
    private static Context ctx; 

    @BeforeClass 
    public static void setUp() { 
     ejbContainer = EJBContainer.createEJBContainer(); 
     ctx = ejbContainer.getContext(); 
    } 

    @AfterClass 
    public static void tearDown() { 
     ejbContainer.close(); 
    } 

    @Test 
    public void getMenus() { 
     LayoutManager manager = null; 
     try { 
      manager = (LayoutManager) ctx.lookup("java:global/classes/LayoutManagerBean!uk.co.monkeypower.openchurch.core.layout.beans.LayoutManager"); 
     } catch (NamingException e) { 
      System.out.println("Failed to lookup the gosh darned bean!"); 
     } 
     assertNotNull(manager); 
     //Menu[] menus = manager.getMenus(); 
     //assertTrue(menus.length > 1); 
    } 

} 

以及故障的一个示例:

@Singleton 
public class OpenChurchPortalContext implements PortalContext { 

    private Set<PortletMode> portletModes = Collections.emptySet(); 
    private Set<WindowState> windowStates = Collections.emptySet(); 

    private Properties portalProperties = new Properties(); 

    public OpenChurchPortalContext() { 
     portletModes.add(PortletMode.VIEW); 
     portletModes.add(PortletMode.HELP); 
     portletModes.add(PortletMode.EDIT); 
     portletModes.add(new PortletMode("ABOUT")); 

     windowStates.add(WindowState.MAXIMIZED); 
     windowStates.add(WindowState.MINIMIZED); 
     windowStates.add(WindowState.NORMAL); 
    } 
... 
} 

并且测试:

public class OpenChurchPortalContextTest { 

    private static EJBContainer ejbContainer; 
    private static Context ctx; 

    @BeforeClass 
    public static void setUp() { 
     ejbContainer = EJBContainer.createEJBContainer(); 
     ctx = ejbContainer.getContext(); 
    } 

    @AfterClass 
    public static void tearDown() { 
     ejbContainer.close(); 
    } 

    @Test 
    public void test() { 
     OpenChurchPortalContext context = null; 
     try { 
      context = (OpenChurchPortalContext) ctx.lookup("java:global/classes/OpenChurchPortalContext"); 
     } catch (NamingException e) { 
      System.out.println("Failed to find the bean in the emebedded jobber"); 
     } 
     assertNotNull(context); 
     Set<PortletMode> modes = (Set<PortletMode>) context.getSupportedPortletModes(); 
     assertTrue(modes.size() > 1); 
     Set<WindowState> states = (Set<WindowState>) context.getSupportedWindowStates(); 
     assertTrue(states.size() > 1); 
    } 

} 

任何想法为什么这可能不工作?

+0

我不能在不了解代码的情况下提出解决方案,但也许可以尝试创建两个as-compact-as-possible项目,一个包含成功的测试,另一个包含失败的测试。然后,您将找到解决方案,或者至少您可以分享您的代码供其他人进行调查。 – melihcelik

+0

好的 - 我试图发布一些示例代码,但它在Firefox中存在问题。将继续尝试。 –

+0

我可以看到的一个区别是失败的bean是@Singleton,而工作的bean是通过本地接口查找的有状态会话bean。 –

回答

1

如果您代理的是类而不是接口,那么您经常会遇到此问题。假设这是这行失败:

context = (OpenChurchPortalContext) ctx.lookup("java:global/classes/OpenChurchPortalContext"); 

OpenChurchPortalContext是一类,但它是由一个代理类包装来实现EJB特定功能。这个代理类不是OpenChurchPortalContext的子类,所以你得到一个ClassCastException。

你没有得到第一个例子,因为LayoutManager是一个接口

LayoutManager manager = null; // INTERFACE, so it works 
try { 
    manager = (LayoutManager) ctx.lookup("java:global/classes/LayoutManagerBean!uk.co.monkeypower.openchurch.core.layout.beans.LayoutManager"); 
} catch (NamingException e) { 
    System.out.println("Failed to lookup the gosh darned bean!"); 
} 

首先,你可以测试一下,看看如果真的是你的问题,改变背景是一个PortalContext不OpenChurchPortalContext:

PortalContext context = null; 
try { 
    context = (PortalContext) ctx.lookup("java:global/classes/OpenChurchPortalContext"); 
} catch (NamingException e) { 
    System.out.println("Failed to find the bean in the emebedded jobber"); 
} 

如果您的问题真的是代理服务器,那么上面的代码应该工作。如果是这种情况,您有两种可能的解决方案:

  1. 当您执行ctx.lookup时,请始终使用接口。这可能有点痛苦,因为您需要为每个EJB专门定义一个接口。
  2. 您可能可以将EJB容器配置为代理类而不仅仅是接口,类似于proxyTargetClass for Spring AOP。你需要检查你的容器的文档。
1

通过实现PortalContext接口,您的单例EJB具有默认的本地业务接口。测试客户端只能通过它的业务接口了解它,而实际的bean类(OpenChurchPortalContext)不应该被客户端直接引用。所以解决方法是通过业务接口PortalContext查找它。