ClassCastException при использовании встроенного Glassfish для модульных тестов - PullRequest
2 голосов
/ 21 ноября 2011

Я выполняю некоторые модульные тесты на некоторых EJBS через maven и встроенный контейнер GlassfishОдин из моих тестов работает, но все последующие попытки протестировать другой EJB приводят к одной и той же ошибке:

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

С последующим бином, который я пытаюсь протестировать.Я уверен, что мои настройки хороши, так как, как я уже сказал, один из моих bean-компонентов может быть протестирован правильно.

Примеры рабочего кода:

@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);
    }

}

Есть идеи, почему это может не сработать?

Ответы [ 2 ]

1 голос
/ 27 ноября 2011

Ваш одноэлементный EJB имеет локальный бизнес-интерфейс по умолчанию посредством реализации интерфейса PortalContext.Тестовый клиент должен знать его только по своему бизнес-интерфейсу, и фактический класс компонента (OpenChurchPortalContext) не должен ссылаться непосредственно на клиент.Таким образом, решение проблемы заключается в том, чтобы найти его по бизнес-интерфейсу PortalContext.

1 голос
/ 21 ноября 2011

Эта проблема часто возникает, если вы используете прокси-сервер, а не интерфейс. Предполагая, что эта строка не работает:

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 для Spring AOP . Для этого вам необходимо обратиться к документации вашего контейнера.
...