java.lang.ClassCastException: $ Proxy96 не может быть приведен к ticket.app.DatesFacade - PullRequest
1 голос
/ 02 апреля 2011

Я ввожу некоторый код в Hudson Server, запущенный на коробке Ubuntu, чтобы запустить некоторые метрики кода (сонар) и Cobertura в коде. Проект работает на Glassfish3.1, использует Maven3, написанный на Java, JSF 2.0 и использует базу данных OracleXE (не имеет значения).

Ошибка выдается при попытке создать экземпляр Facade внутри моих тестов JUnit. Тесты работают нормально, когда я запускаю их из Netbeans, но когда Хадсон выполняет автоматическую сборку, я получаю эту ошибку:

    java.lang.ClassCastException: $Proxy96 cannot be cast to ticket.app.DatesFacade
    at ticket.app.EventsControllerTest.setUp(EventsControllerTest.java:60)
    at junit.framework.TestCase.runBare(TestCase.java:128)
    at junit.framework.TestResult$1.protect(TestResult.java:106)
    at junit.framework.TestResult.runProtected(TestResult.java:124)
    at junit.framework.TestResult.run(TestResult.java:109)
    at junit.framework.TestCase.run(TestCase.java:120)
    at junit.framework.TestSuite.runTest(TestSuite.java:230)
    at junit.framework.TestSuite.run(TestSuite.java:225)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:616)
    at org.apache.maven.surefire.junit.JUnitTestSet.execute(JUnitTestSet.java:207)
    at org.apache.maven.surefire.junit.JUnit3Provider.executeTestSet(JUnit3Provider.java:107)
    at org.apache.maven.surefire.junit.JUnit3Provider.invoke(JUnit3Provider.java:79)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:616)
    at org.apache.maven.surefire.booter.ProviderFactory$ClassLoaderProxy.invoke(ProviderFactory.java:103)
    at $Proxy0.invoke(Unknown Source)
    at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:145)
    at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcess(SurefireStarter.java:87)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:69)

Сервер Hudson работает не на JBoss, а на Tomcat. Я добавляю эту деталь, потому что, когда я гуглю эту ошибку, я не нашел ничего, кроме ошибок JBoss, объясняющих, что на фасад ссылаются как в файлах WAR, так и в файлах EAR.

РЕДАКТИРОВАТЬ: Вот как я сейчас создаю экземпляры Фасада (который отлично работает при выполнении тестов через Netbeans GF3.1):

        Map properties = new HashMap();
    properties.put(EJBContainer.MODULES, new File("target/classes"));
    properties.put("org.glassfish.ejb.embedded.glassfish.configuration.file", "server/config/domain.xml");
    properties.put("oracle.jdbc.OracleDriver", "server/lib/ojdbc14.jar");
    ejbContainer = EJBContainer.createEJBContainer(properties);
    ctx = ejbContainer.getContext();

    EventsFacade instance = (EventsFacade)ctx.lookup("java:global/classes/EventsFacade");

РЕДАКТИРОВАТЬ: My EventsFacade:

@Stateful
public class EventsFacade extends AbstractFacade<Events> {
    @PersistenceContext(unitName = "tickets_AppTicket_war_1.0-SNAPSHOTPU")
    private EntityManager em;

    protected EntityManager getEntityManager() {
        return em;
    }

    public EventsFacade() {
        super(Events.class);
    }
}

РЕДАКТИРОВАТЬ : И .. мой AbstractFacade полностью:

public abstract class AbstractFacade<T> {
private Class<T> entityClass;

public AbstractFacade(Class<T> entityClass) {
    this.entityClass = entityClass;
}

protected abstract EntityManager getEntityManager();

public void create(T entity) {
    getEntityManager().persist(entity);
}

public void edit(T entity) {
    getEntityManager().merge(entity);
}

public void remove(T entity) {
    getEntityManager().remove(getEntityManager().merge(entity));
}

public T find(Object id) {
    return getEntityManager().find(entityClass, id);
}

public List<T> findAll() {
    javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
    cq.select(cq.from(entityClass));
    return getEntityManager().createQuery(cq).getResultList();
}

public List<T> findRange(int[] range) {
    javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
    cq.select(cq.from(entityClass));
    javax.persistence.Query q = getEntityManager().createQuery(cq);
    q.setMaxResults(range[1] - range[0]);
    q.setFirstResult(range[0]);
    return q.getResultList();
}

public int count() {
    javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
    javax.persistence.criteria.Root<T> rt = cq.from(entityClass);
    cq.select(getEntityManager().getCriteriaBuilder().count(rt));
    javax.persistence.Query q = getEntityManager().createQuery(cq);
    return ((Long) q.getSingleResult()).intValue();
}

}

РЕДАКТИРОВАТЬ: Создан новый интерфейс:

    @Local
public interface EventsInterface<Events> {

    int count();

    void create(Events entity);

    void edit(Events entity);

    Events find(Object id);

    List<Events> findAll();

    List<Events> findRange(int[] range);

    void remove(Events entity);

}

ИЗМЕНЕНО: События DelarationFacade:

public class EventsFacade extends AbstractFacade<Events> implements EventsInterface<Events> {

РЕДАКТИРОВАТЬ: После получения ошибки прокси в моей IDE после создания нового интерфейса вывод начал отображать:

Field Name == intfClass
Field == interface ticket.app.EventsInterface
Field Name == containerId
Field == 85313541807800321
Field Name == delegate
Field == com.sun.ejb.containers.EJBLocalObjectInvocationHandler@72b0f2b2
Field Name == isOptionalLocalBusinessView
Field == false

1 Ответ

5 голосов
/ 02 апреля 2011

Обычно это означает, что вы ссылаетесь на объект по его классу, а не по интерфейсу, когда вокруг объекта есть прокси (а прокси основан на интерфейсе).

Решение - обратиться к объекту по его интерфейсу. Я предполагаю, что EventsFacade имеет интерфейс Local и / или Remote. Попробуйте использовать это. Если у него нет интерфейса - создайте его, это хорошая практика. Определите все открытые методы в интерфейсе.

Обновление: возможно, это проблема встроенной стеклянной рыбы, которую вы используете. Поскольку вы не можете отладить это с помощью отладчика, вот что вы можете сделать, чтобы отследить проблему: Используйте java.lang.reflect.Proxy.getInvocationHandler(object). А затем перечислите все поля возвращаемого объекта. (Вам сейчас придется отказаться от актеров и получить их из контекста просто как Object). Что-то вроде:

Object ic = Proxy.getInvocationHandler(facade);
Field[] fields = ic.getClass().getDeclaredFields();
for (Field field : fields) {
    field.setAccessible(true);
    System.out.println(field.getName() + "=" + field.get(ic);
}
...