RMI ClassCastException no cliente OSGi acessando EJB do servidor JavaEE

Eu tenho um aplicativo OSGi. Trabalhando com o EJB context.lookup Eu tive que configurar o carregador de classs de contexto do Thread como o carregador de classs do bundle para poder converter. Como isso:

Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); Entity entity=bean.getOne(); System.out.println(entity.getClass().getClassLoader()); 

saída é

org.apache.felix.framework.BundleWiringImpl@7468776f

Este código funciona. O problema que não posso transmitir se tiver ArrayList

 Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); ArrayList entities=bean.getMany(); 

Este código retorna ClassCastException.

Verificação

 ArrayList temp=new ArrayList(); System.out.println(temp.getClass().getClassLoader()); 

retorna NULL – significa class bootstrap. Como isso pode ser consertado?

EDITAR:

O mais interessante, que ArrayList com String funciona, array clássico funciona, mas ArrayList e ArrayList com Entiry não funcionam.

 Class Bean { .... @Override //THIS DOESN'T WORK public ArrayList readMany() { Entity dir1=new Entity(); dir1.setContent("1 test"); Entity dir2=new Entity(); dir2.setContent("2 test"); ArrayList result=new ArrayList(); result.add(dir1);result.add(dir2); return result; } @Override //THIS WORKS public ArrayList readMany2() { String str1=new String("1 test"); String str2=new String("2 test"); ArrayList result=new ArrayList(); result.add(str1); result.add(str2); return result; } @Override //THIS WORKS public Entity[] readArray() { ArrayList al=readMany(); Entity[] ar=new Entity[al.size()]; for (int i = 0; i < al.size(); i++) { ar[i]=al.get(i); } return ar; } @Override //THIS DOESN'T WORK public ArrayList readSimpleArrayList() { ArrayList gal=readMany(); ArrayList al= new ArrayList(); for (Entity obj : gal) { al.add(obj); } return al; } ... } 

Aqui está o log

java.lang.ClassCastException: com.test.cmn.shd.base.dir.language.LanguageDirEntity não pode ser convertido para com.test.cmn.shd.base.dir.language.LanguageDirEntity em com.test.cmn.dt.base .Activator.start (Activator.java:83) em org.apache.felix.framework.util.SecureAction.startActivator (SecureAction.java:645) em org.apache.felix.framework.Felix.activateBundle (Felix.java:1977 ) em org.apache.felix.framework.Felix.startBundle (Felix.java:1895) em org.apache.felix.framework.BundleImpl.start (BundleImpl.java:944) em org.apache.felix.framework.BundleImpl. start (BundleImpl.java:931) em com.test.cmn.dt.loader.LoaderModel.startCoreModule (LoaderModel.java:149) em com.test.cmn.dt.loader.LoaderModel.access $ 100 (LoaderModel.java:39 ) em com.test.cmn.dt.loader.LoaderModel $ InstallAndStartModuleWorker.doInBackground (LoaderModel.java:79) em com.test.cmn.dt.loader.LoaderModel $ InstallAndStartModuleWorker.doInBackground (LoaderModel.java:73) em javax. swing.SwingWorker $ 1.call (SwingWorker.java:296) em java.util.concurrent.Fu tureTask.run (FutureTask.java:262) em javax.swing.SwingWorker.run (SwingWorker.java:335) em java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1145) em java.util.concurrent.ThreadPoolExecutor $ Worker.run (ThreadPoolExecutor.java:615) em java.lang.Thread.run (Thread.java:744)

EDITAR 2 – CÓDIGO COMPLETO. Este código é executado no computador do cliente. JavaEE (GF4) está sendo executado no servidor. Existem três pacotes configuráveis ​​osgi: para servidor, para cliente e compartilhado. A cópia de shared está no servidor e nos clientes e contém LanguageDirBeanRemote e LanguageDirEntity.

 ClassLoader thatLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); try { Properties jndiProps = new Properties(); jndiProps.put("java.naming.factory.initial", "com.sun.enterprise.naming.impl.SerialInitContextFactory"); jndiProps.put("java.naming.factory.url.pkgs", "com.sun.enterprise.naming"); jndiProps.put("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl"); jndiProps.setProperty("org.omg.CORBA.ORBInitialHost", "xxxx"); jndiProps.setProperty("org.omg.CORBA.ORBInitialPort", "3700"); InitialContext ctx = new InitialContext(jndiProps); LanguageDirBeanRemote bean=(LanguageDirBeanRemote)ctx.lookup("java:global/..."); ArrayList elements=bean.readDirectory(); System.out.println("HERE I GET THE ERROR:"+elements.get(0).getContent()); } finally { Thread.currentThread().setContextClassLoader(thatLoader); } 

EDIT 3 eu abri um bug

X não pode ser convertido em X “, em um contexto de carregador de classs / OSGi, geralmente significa que você tem dois carregadores de class presentes em seu sistema, ambos carregaram a class X e que você está tentando passar uma instância criada usando um cópia do classloader da class para codificar esperando a cópia do outro carregador de class.

As correções são para garantir que apenas uma instância dessa class exista em qualquer carregador de class e seja compartilhada por todos os códigos (mais simples) ou para garantir que as instâncias nunca ultrapassem os limites de contexto do carregador de class ou mais frágeis para garantir que todos está encontrando EXATAMENTE a mesma implementação dessa class (mesmos bytecodes exatos para a class e tudo o que ela herda).

Como a outra resposta disse, a raiz do seu problema é quase certamente que você tem várias cópias do LanguageDirEntity carregadas por carregadores de classs diferentes. A causa mais provável disso é que você empacotou inadvertidamente a class física em pacotes diferentes. Portanto, a primeira solução é inspecionar seus pacotes para a turma. Se estiverem todos no mesmo local, correndo

grep -r LanguageDirEntity *

é uma maneira rápida e suja de encontrá-los. (Você está usando o plug-in do pacote Maven para sua compilation? É fácil embutir dependencies em pacotes, a menos que você tenha um direito ao seu pomo).

A razão pela qual as coisas funcionam quando você usa um String em um ArrayList é que o String será fornecido pelo sistema e nunca haverá várias cópias dele carregadas por diferentes carregadores de classs. O motivo pelo qual você tem problemas ao usar o ArrayList, mas não tem problemas ao usar as classs Entity, é que a interação de genéricos e collections introduz alguns lançamentos extras que não são necessários no caso de uso direto.

Desempacotar exatamente o que está acontecendo é complicado sem saber que classs são empacotadas onde. Eu acho que, pelos problemas que você está vendo, o Bean não está no mesmo pacote que o Ativador. No entanto, a ideia básica é que toda vez que o ArrayList for usado pelo código (para adicionar elementos ou ler elementos), será feita uma conversão para converter o conteúdo para ‘Entity’. Quanto mais conversões você fizer, nos pacotes mais diferentes, maior a chance de atingir classs que foram carregadas de forma incompatível a partir de pacotes diferentes. Neste caso, parece que seu Activator viu uma cópia diferente da class do seu Bean , então quando o ativador tenta o casting (implícito, adicionado pelo compilador), ele é incompatível com o conteúdo do ArrayList .

Obrigado a todos. Eu finalmente resolvi isso. Estou escrevendo como entendo. Existem duas maneiras de usar o gf-client com o osgi client:

  1. Não oficial – pegue pacotes de peixe-vidro e instale-os manualmente via osgi api.
  2. Forma oficial – copie o glassfish / lib / gf-client.jar e o glassfish / modules para o cliente e, no classpath, adicione gf-clinet.jar.

Eu não sei como, eu fiz pela primeira vez. Eu não posso errar, porque glassfish é o próprio osgi. Quando fiz isso pela segunda vez, esse problema desapareceu. Portanto, o problema estava em carregadores de classs diferentes quando você carrega a partir do caminho de class java e do pacote osgi.