java.lang.ClassCastException:$Proxy96无法转换为ticket.app.DatesFacade

发布于 2024-10-28 15:15:24 字数 5786 浏览 1 评论 0原文

我正在将一些代码输入到在 Ubuntu 机器上运行的 Hudson 服务器中,以便在代码上运行一些代码指标(Sonar)和 Cobertura。该项目运行于 Glassfish3.1,使用 Maven3,用 Java、JSF 2.0 编写,并使用 OracleXE 数据库(无关)。

当尝试在我的 JUnit 测试中创建 Facade 实例时,会引发该错误。当我从 Netbeans 运行测试时,测试运行良好,但是当 Hudson 在其上进行自动构建时,我收到此错误:

    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 运行的。我添加这个细节是因为当我用 Google 搜索这个错误时,除了解释 WAR 和 EAR 文件中都引用了外观的 JBoss 错误之外什么也没找到。

编辑:这就是我当前创建 Facade 实例的方式(通过 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");

编辑:我的 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);

}

更改: EventsFacade delaration:

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

I am entering some code into a Hudson Server run on a Ubuntu box in order to run some Code Metrics(Sonar) and Cobertura on the code. The project runs off of Glassfish3.1, uses Maven3, written in Java, JSF 2.0 and uses OracleXE Database(irrelevant).

The error is being thrown when trying to create an instance of an Facade inside of my JUnit tests. The tests run fine when I am running them from Netbeans, but when Hudson does the automatic build on it I get this error:

    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)

The Hudson server is not run off of JBoss, it is run off of Tomcat. I add this detail because when I Google this error, I have found nothing but JBoss errors explaining that the facade is referenced in both the WAR and EAR files.

EDIT: This is how I am currently creating instances of the Facade (Which works fine when running the tests through 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");

EDIT: 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);
    }
}

EDIT: And.. my AbstractFacade in full:

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

}

EDIT: Created new Interface:

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

}

CHANGED: EventsFacade delaration:

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

EDIT: After getting the proxy error in my IDE after creating the new interface the output began to show:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一张白纸 2024-11-04 15:15:24

这通常意味着当对象周围存在代理(并且代理基于接口)时,您将通过其类而不是其接口来引用该对象。

解决方案是通过对象的接口来引用该对象。我猜想 EventsFacade 有一个 Local 和/或 Remote 接口。尝试使用它。如果它没有界面 - 制作一个界面,这是一种很好的做法。定义接口中的所有公共方法。

更新:看起来,这可能是您使用的嵌入式 glassfish 的问题。由于您无法使用调试器进行调试,因此您可以执行以下操作来跟踪问题:使用 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);
}

This usually means that you are referencing an object by its class, rather than by its interface when there is a proxy around the object (and the proxy is based on the interface).

The solution is to refer to the object by its interface. I would guess that EventsFacade has a Local and/or Remote interface. Try using that. If it doesn't have an interface - make one, it is a good practice. Define all the public methods in the interface.

Update: as it seems, this might be a problem with the embedded glassfish you are using. As you can't debug that with a debugger, here's what you can do to trace the problem: Use java.lang.reflect.Proxy.getInvocationHandler(object). And then list all the fields of the returned object. (You would have to drop the cast for now and get it from the context simply as Object). Something like:

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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文