2013-05-06 3 views
5

Я получаю следующее исключение, когда хочу передать один тип другому.Невозможно использовать тип типа

java.lang.ClassCastException: org.paston.certification.data.impl.BRL6000 
cannot be cast to org.paston.certification.data.Certification 

BRL6000 расширяет Сертификацию. Поэтому, в моем понимании, я должен был бы подвергнуть объект типа BRL6000 типу сертификации.

Это код, в котором происходит исключение.

Object certification = ch.getCertificationData(process, version); 
Certification c = (Certification)certification; 

Развертывание

Приложение развернуто из Eclipse, на сервере Tomcat 7. Мое приложение использует несколько JAR из среды Tomcat (например, Bonita_Server.jar).

Мое приложение (в Eclipse) - это динамические веб-проекты, которые ссылаются на другой проект (Certificationnl), который содержит классы Certification и BRL6000. Project Certificationnl добавляется в WAR WAR веб-проекта при развертывании приложения в Tomcat.

Классы

BRL6000 класса

package org.paston.certification.data.impl; 

import org.paston.certification.data.Certification; 
import org.paston.certification.data.CertificationStep; 

public class BRL6000 extends Certification{ 

    /** 
    * 
    */ 
    public static final long serialVersionUID = -8215555386637513536L; 
    public static final String processName = "BRL6000"; 

} 

сертификации класса

package org.paston.certification.data; 

import java.util.ArrayList; 
import java.util.List; 

import org.ow2.bonita.facade.runtime.impl.AttachmentInstanceImpl; 

public class Certification implements java.io.Serializable{ 

    public enum Section{ 
     ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN 
    } 
    /** 
    * SerializationVersionUID 
    */ 
    private static final long serialVersionUID = -5158236308772958478L; 


} 

getCertificationData

public Object getCertificationData(String process, String version) { 
    if (loginContext == null) 
     login(); 

    System.out.println("Process: "+ process + " Version: "+ version); 
    ProcessDefinitionUUID pdu = new ProcessDefinitionUUID(process, version); 

    QueryRuntimeAPI queryRuntimeAPI = AccessorUtil 
      .getQueryRuntimeAPI(); 

    try { 
     Set<ProcessInstance> processInstances = queryRuntimeAPI 
       .getProcessInstances(pdu); 

     if (processInstances.size() != 1) 
      System.out.println("Best number of instances is 1. Found: " 
        + processInstances.size()); 

     for (ProcessInstance processInstance : processInstances) { 
      Map<String, Object> variables = processInstance 
        .getLastKnownVariableValues(); 
      if (((Boolean) variables.get("active")) == true) {    
       return variables.get("certification"); 
      } 
     } 
    } catch (ProcessNotFoundException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    return null; 
} 

Обновление с кодом в качестве Servlet

package org.paston.certification.servlet; 

import java.io.IOException; 
import java.io.PrintWriter; 

import javax.servlet.ServletException; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import org.paston.certification.CertificationHandler; 
import org.paston.certification.data.Certification; 
import org.paston.certification.data.CertificationI; 

/** 
* Servlet implementation class SomeServlet 
*/ 
public class SomeServlet extends HttpServlet { 
    private static final long serialVersionUID = 1L; 

    /** 
    * @see HttpServlet#HttpServlet() 
    */ 
    public SomeServlet() { 
     super(); 
     // TODO Auto-generated constructor stub 
    } 

    /** 
    * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) 
    */ 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 

     CertificationHandler ch = new CertificationHandler(); 
     String process = request.getParameter("p"); 
     String version = request.getParameter("v"); 
     Object certification = ch.getCertificationData(process, version); 
     Class<?> clazz = certification.getClass(); 
     while (clazz != null) { 
      System.out.println(clazz.getName()); 
      clazz = clazz.getSuperclass(); 
     } 

     Class c1 = certification.getClass().getSuperclass(); 
     Class c2 = Certification.class; 

     System.out.println("c1 is " + c1 + ", c2 is " + c2); 
     System.out.println("c1 == c2 is " + (c1 == c2)); 
     System.out.println("c1.equals(c2) is " + c1.equals(c2)); 
     System.out.println("c1.getName().equals(c2.getName()) is " 
       + c1.getName().equals(c2.getName())); 
     System.out.println("c1.getClassLoader() == c2.getClassLoader() is " 
       + (c1.getClassLoader() == c2.getClassLoader())); 

     CertificationI c = (CertificationI) certification; 

     PrintWriter out = response.getWriter(); 
     out.println("Hello World"); 
    } 

    /** 
    * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) 
    */ 
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
     // TODO Auto-generated method stub 
    } 

} 

Консоль выход Servlet:

Process: BRL6000 Версия: 1.0 org.paston.certification.data.impl.BRL6000 org.paston .certification.data.Certification java.lang.Object c1 - класс org.paston.certification.data.Certification, c2 - класс org.paston.certification.data.Certification c1 == c2 is false c1.equals (c2) is false c1.getName(). equals (c2. GetName()) истинно c1.getClassLoader() == c2.getClassLoader() ложна

Существует также один другой вопрос, который, возможно, намекая на проблемы. Каждые 10 секунд я вижу следующее исключение в консоли:

May 07, 2013 2:09:45 PM org.apache.catalina.loader.WebappClassLoader loadClass 
INFO: Illegal access: this web application instance has been stopped already. Could not load org.ow2.bonita.runtime.tx.StandardTransaction. The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact. 
java.lang.IllegalStateException 
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1566) 
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1526) 
    at org.ow2.bonita.util.ReflectUtil.loadClass(ReflectUtil.java:68) 
    at org.ow2.bonita.env.descriptor.ObjectDescriptor.construct(ObjectDescriptor.java:195) 
    at org.ow2.bonita.env.WireContext.construct(WireContext.java:521) 
    at org.ow2.bonita.env.WireContext.create(WireContext.java:498) 
    at org.ow2.bonita.env.WireContext.create(WireContext.java:484) 
    at org.ow2.bonita.env.WireContext.get(WireContext.java:456) 
    at org.ow2.bonita.env.WireContext.get(WireContext.java:343) 
    at org.ow2.bonita.env.WireContext.get(WireContext.java:746) 
    at org.ow2.bonita.env.BasicEnvironment.get(BasicEnvironment.java:151) 
    at org.ow2.bonita.env.BasicEnvironment.get(BasicEnvironment.java:142) 
    at org.ow2.bonita.util.EnvTool.getEnvClass(EnvTool.java:175) 
    at org.ow2.bonita.util.EnvTool.getTransaction(EnvTool.java:84) 
    at org.ow2.bonita.runtime.tx.StandardTransactionInterceptor.execute(StandardTransactionInterceptor.java:42) 
    at org.ow2.bonita.services.impl.EnvironmentInterceptor.execute(EnvironmentInterceptor.java:40) 
    at org.ow2.bonita.services.impl.RetryInterceptor.execute(RetryInterceptor.java:59) 
    at org.ow2.bonita.runtime.event.EventExecutorThread.run(EventExecutorThread.java:61) 

Update 2

Я пришел, чтобы понять проблему немного лучше. Bonitaserver (AccessorUtil) делает загрузку объекта сертификации. Он где-то загружает классы из Certification.jar1620768823629427276.tmp, которые Bonitaserver создал, когда процесс был загружен на сервер.

Кроме того, я нашел класс ReflectUtil (link), который, вероятно, используется для загрузки этих классов.

Я пытался загрузить классы в начале doGet для этого (сервлета) как ClassLoaderAccessorUtil. Оба с тем же старым результатом.

ArrayList<String> classesNames = new ArrayList<String>(); 
    classesNames.add("org.paston.certification.data.Certification"); 
    classesNames.add("org.paston.certification.data.CertificationI"); 
    classesNames.add("org.paston.certification.data.impl.BRL6000"); 
    ClassLoader cl = this.getClass().getClassLoader(); 
    Class<?>[] classes = ReflectUtil.loadClasses(cl, classesNames); 

Update 3

Результаты следующего кода, предложенного @GaborSch. Код, как я использовал его:

System.out.println("--- Test ClassLoader certification object---"); 
    ClassLoader cl1 = certification.getClass().getSuperclass().getClassLoader(); 
    while (cl1 != null) { 
     System.out.println(cl1.getClass().getCanonicalName() + " " + cl1.hashCode() + " " + cl1); 
     cl1 = cl1.getParent(); 
    } 
    System.out.println("--- Test ClassLoader Certification class---"); 
    ClassLoader cl2 = Certification.class.getClassLoader(); 
    while (cl2 != null) { 
     System.out.println(cl2.getClass().getCanonicalName() + " " + cl2.hashCode() + " " + cl2); 
     cl2 = cl2.getParent(); 
    } 

Результат кода:

--- Test ClassLoader certification object--- 

org.ow2.bonita.runtime.ProcessClassLoader 451656 
[email protected] 
org.ow2.bonita.runtime.VirtualCommonClassloader 1182018350 
[email protected] 
org.apache.catalina.loader.StandardClassLoader 318536939 
[email protected] 
sun.misc.Launcher.AppClassLoader 1667514408 
[email protected] 
sun.misc.Launcher.ExtClassLoader 1253061906 
[email protected] 

--- Test ClassLoader Certification class--- 

org.apache.catalina.loader.WebappClassLoader 2136824254 
WebappClassLoader context: /Certification delegate: false 
repositories: 
    /WEB-INF/classes/ 
----------> Parent Classloader: [email protected] 

org.apache.catalina.loader.StandardClassLoader 318536939 
[email protected] 
sun.misc.Launcher.AppClassLoader 1667514408 
[email protected] 
sun.misc.Launcher.ExtClassLoader 1253061906 
[email protected] 
+5

Просьба показать определения ваших классов 'BRL6000' и' Certification' и код, который вызывает исключение. – AlexR

+0

Вы уверены, что наследуете/литье на правильный тип сертификации? Возможно, вы случайно импортировали другой тип сертификации. –

+0

Это меня озадачивает, как люди ожидают помощи, не публикуя сломанный код. – jn1kk

ответ

7

Я подозреваю, что корень проблемы лежит в среде выполнения.

Данные вашего Certification в конечном итоге исходят от AccessorUtil.getQueryRuntimeAPI(), который является статическим методом, выполняемым Tomcat, поэтому все экземпляры объектов, исходящие от него, скорее всего, будут загружаться загрузчиком классов Tomcat.

Если вы скопируете файл jar под Tomcat, он загрузит его своим собственным загрузчиком классов. Ваш eclipse-run-код, хотя и использует другой загрузчик классов, и если у них нет общего загрузчика классов предков, где загружается этот класс Certification, они будут считаться другим классом.

Предлагаю просмотреть ваши пути к классам времени выполнения, удалить из вас файлы Tomcat или (в худшем случае) запустить ваш код в Tomcat (например, в качестве сервлета в том же приложении).

Update:

На основе описания развертывания проекта я считаю, что

  • AccessorUtil класса загружается общий загрузчиком класса
  • Списки внутри населенны Certification экземпляров из ваших Certificationnl классы с вашего развертывания Tomcat
  • Вы можете получить доступ к этим объектам через класс AccessorUtil, но определения классов недоступны из вашего кода Eclipse.

Плохая идея получить доступ к объектам, определенным Tomcat, снаружи на уровне JVM. Либо введите код в один и тот же контейнер, либо используйте правильно определенный интерфейс (например, веб-службы).

Если вы хотите остаться с текущей настройкой проекта, вы также можете использовать интерфейсы, которые помещаются в общий загрузчик классов (рядом с AccessorUtil) и отбрасываются в интерфейс.

Update 2:

Чтобы проверить иерархию загрузчика классов, выполнить такой код:

Class c1 = certification.getClass().getSuperclass().getClassLoader(); 
while (c1 != null) { 
    System.out.println(c1.getClass().getCanonicalName() + " " + c1.hashCode() + " " + c1); 
    c1 = c1.getParent(); 
} 

Class c2 = Certification.class.getClassLoader(); 
while (c2 != null) { 
    System.out.println(c2.getClass().getCanonicalName() + " " + c2.hashCode() + " " + c2); 
    c2 = c2.getParent(); 
} 

Вы можете найти общий предок путем сравнения стека. Лучший способ продолжить - отладка.

Update 3:

Видно, что ваш общий загрузчик классов является org.apache.catalina.loader.StandardClassLoader. Кроме того

  • org.apache.catalina.loader.WebappClassLoader присутствует для вашего веб-приложение (это, где вы хотите преобразованный в)
  • org.ow2.bonita.runtime.VirtualCommonClassloader и org.ow2.bonita.runtime.ProcessClassLoader присутствуют где объекты происходят из (это где они инстанцированный)

Похоже, что Bonita использует какой-то механизм загрузки классов.

Решение состоит в том, что вы делаете StandardClassloader (или любой другой загрузчик классов) для загрузки ваших классов. Так как Certification (и, следовательно, BRL6000) зависят от классов Bonita, вы должны поставить Bonita_Server.jar в одобренный. См. Tomcat Classloader HOWTO, это может дать вам больше понимания.

Update 4:

Для Сериализация/десериализации рекомендуется в моих комментариях, вы можете использовать этот кусок кода:

Certification certification = null; 
try { 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    ObjectOutputStream oos = new ObjectOutputStream(baos); 
    oos.writeObject(ch.getCertificationData(process, version)); 
    oos.flush(); 
    certification = (Certification) new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())).readObject(); 
} catch (IOException | ClassNotFoundException ex) { 
} 

Обратите внимание, что (Certification) бросок делается в настоящее время загружены класс.

Update 5:

Окончательное решение было не с помощью прямого доступа Java на уровне класса, а с помощью надлежащего API, чтобы сделать тот же трюк.

+0

Arg! Я удалил банку из Tomcat и добавил ее в сборку развертывания моего веб-проекта. Угадайте, что? Такое же исключение сохраняется. –

+0

Итак, какова ваша среда выполнения * точно *? Вы можете добавить его к своему вопросу, потому что я думаю, что это актуально. – gaborsch

+0

добавил описание к моему вопросу orignal. –

3

Я думаю, что есть два возможных объяснения:

  • Вам удалось загрузить Certification класс в двух различных загрузчиков классов.
  • У вас есть два класса Certification, у которых есть имена, которые только посмотреть то же самое.

Вот что я предлагаю вам сделать, чтобы выяснить, что происходит.

  • Перед утверждением, что делает (Certification) certification вставить следующее:

    // Get the classes that are being compared in the typecast. 
    Class c1 = certification.getClass().getSuperclass(); 
    Class c2 = Certification.class; 
    
    System.out.println("c1 is " + c1 + ", c2 is " + c2); 
    System.out.println("c1 == c2 is " + c1 == c2); 
    System.out.println("c1.equals(c2) is " + c1 == c1.equals(c2)); 
    System.out.println("c1.getName().equals(c2.getName()) is " + 
            c1.getName().equals(c2.getName())); 
    System.out.println("c1.getClassLoader() == c2.getClassLoader() is " + 
            c1.getClassLoader() == c2.getClassLoader()); 
    
  • Убедитесь, что первая строка дает (что выглядит) одни и те же имена для c1 и c2. (Если нет, то мы выбрали неправильные классы для сравнения. Tweak моего кода, чтобы получить правильные.)

  • В c1 == c2 и c2.equals(c2) тестах должны дать тот же ответ, и я предсказываю, это будет false.

  • Сравнивая имена есть тесты, которые отличает два альтернативных объяснения:

    • Если имена совпадают, это указывает на проблемы загрузчика классов.
    • Если имена не равны, то у вас есть два разных класса, имена которых выглядят одинаково, но на самом деле их нет. (Как это может быть? Ну, Java использует Unicode, а некоторые из европейских символов используют один и тот же «глиф» для разных символов. В зависимости от используемых вами шрифтов вы получаете пары символов, которые выглядят то же самое, когда вы их просматриваете в редакторе/IDE, но на самом деле таковыми не являются.
  • заключительный тест подтвердит, что c1 и c2 или не имеют один и тот же загрузчик классов.


Это вона 't объяснить почему ваше веб-приложение находится в этом состоянии, но оно ясно скажет вам, является ли проблема загрузчиком классов, фанковыми именами классов ... или чем-то еще.

+0

+1 Я уверен, что есть несколько нечетных сценариев, которые не покрывают, но это хороший шаг в правильном направлении. –

+0

Спасибо. это, по крайней мере, дает мне дополнительную информацию. Погрузчики классов не совпадают. c1 == c2 также возвращает false. –

Смежные вопросы