Erro ao retornar ResultSet de uma classe RMI

20 respostas
R

Ola !

Estou tentando retornar um ResultSet de uma classe remota utilizando RMI, conforme o exemplo abaixo:

// Trecho da Classe cliente:

private class ClickButton implements ActionListener

{

java.sql.ResultSet result;
public void actionPerformed( ActionEvent e )

{

if (e.getSource() == bt1) {

try {

CLocadora obj = (CLocadora) Naming.lookup("<a href="//localhost/CLocadoraServer">//localhost/CLocadoraServer</a>");

result = obj.pesquisarCliente(); // DA ERRO AQUI //

}

catch (Exception xe){

xe.printStackTrace();

}

}

}

}

// Trecho da classe Server:

public ResultSet pesquisarCliente() throws RemoteException {
conectaBanco();

Statement statement;

ResultSet resultSet;

resultSet = null;

try {
String query = “SELECT * FROM cliente”;

statement = connection.createStatement();
resultSet = statement.executeQuery( query );

statement.close();

}

catch ( SQLException sqlex ) {

sqlex.printStackTrace();

}

return resultSet;
}

private void conectaBanco() throws RemoteException {

String url = jdbc:odbc:DSN_LOCADORA;

String username = “renatop”;

String password = “prenato”;
// Carrega o driver para permitir conexão ao banco de dados

try {

Class.forName( sun.jdbc.odbc.JdbcOdbcDriver );
connection = DriverManager.getConnection(

url, username, password );

}

catch ( ClassNotFoundException cnfex ) {

System.err.println(

Failed to load JDBC/ODBC driver. );

cnfex.printStackTrace();

System.exit( 1 ); // termina o programa

}

catch ( SQLException sqlex ) {

System.err.println( Unable to connect );

sqlex.printStackTrace();

}

}

No momento de chamar o método na classe cliente, esta apresentando os seguintes erros:

java.rmi.UnmarshalException: error unmarshalling return; nested exception is:

java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: sun.jdbc.odbc.JdbcOdbcResultSet

at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:164)

at CLocadoraImpl_Stub.pesquisarCliente(Unknown Source)

at ClPesquisaGeral$ClickButton.actionPerformed(ClPesquisaGeral.java:133)

at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1764)

at javax.swing.AbstractButton$ForwardActionEvents.actionPerformed(AbstractButton.java:1817)

at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:419)

at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:257)

at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:245)

at java.awt.Component.processMouseEvent(Component.java:5134)

at java.awt.Component.processEvent(Component.java:4931)

at java.awt.Container.processEvent(Container.java:1566)

at java.awt.Component.dispatchEventImpl(Component.java:3639)

at java.awt.Container.dispatchEventImpl(Container.java:1623)

at java.awt.Component.dispatchEvent(Component.java:3480)

at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:3450)

at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3165)

at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3095)

at java.awt.Container.dispatchEventImpl(Container.java:1609)

at java.awt.Window.dispatchEventImpl(Window.java:1590)

at java.awt.Component.dispatchEvent(Component.java:3480)

at java.awt.EventQueue.dispatchEvent(EventQueue.java:450)

at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:197)

at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)

at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:140)

at java.awt.Dialog.show(Dialog.java:538)

at ClPesquisaGeral.(ClPesquisaGeral.java:119)

at ClCliente$ClickButton.actionPerformed(ClCliente.java:158)

at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1764)

at javax.swing.AbstractButton$ForwardActionEvents.actionPerformed(AbstractButton.java:1817)

at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:419)

at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:257)

at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:245)

at java.awt.Component.processMouseEvent(Component.java:5134)

at java.awt.Component.processEvent(Component.java:4931)

at java.awt.Container.processEvent(Container.java:1566)

at java.awt.Component.dispatchEventImpl(Component.java:3639)

at java.awt.Container.dispatchEventImpl(Container.java:1623)

at java.awt.Component.dispatchEvent(Component.java:3480)

at javax.swing.plaf.basic.BasicInternalFrameUI$GlassPaneDispatcher.retargetMouseEvent(BasicInternalFrameUI.java:1407)

at javax.swing.plaf.basic.BasicInternalFrameUI$GlassPaneDispatcher.forwardMouseEvent(BasicInternalFrameUI.java:1343)

at javax.swing.plaf.basic.BasicInternalFrameUI$GlassPaneDispatcher.mouseReleased(BasicInternalFrameUI.java:1273)

at java.awt.Component.processMouseEvent(Component.java:5134)

at java.awt.Component.processEvent(Component.java:4931)

at java.awt.Container.processEvent(Container.java:1566)

at java.awt.Component.dispatchEventImpl(Component.java:3639)

at java.awt.Container.dispatchEventImpl(Container.java:1623)

at java.awt.Component.dispatchEvent(Component.java:3480)

at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:3450)

at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3165)

at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3095)

at java.awt.Container.dispatchEventImpl(Container.java:1609)

at java.awt.Window.dispatchEventImpl(Window.java:1590)

at java.awt.Component.dispatchEvent(Component.java:3480)

at java.awt.EventQueue.dispatchEvent(EventQueue.java:450)

at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:197)

at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)

at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:144)

at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:136)

at java.awt.EventDispatchThread.run(EventDispatchThread.java:99)

Caused by: java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: sun.jdbc.odbc.JdbcOdbcResultSet

at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1278)

at java.io.ObjectInputStream.readObject(ObjectInputStream.java:324)

at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:297)

at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:146)

 58 more

Caused by: java.io.NotSerializableException: sun.jdbc.odbc.JdbcOdbcResultSet

at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1054)

at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:278)

at sun.rmi.server.UnicastRef.marshalValue(UnicastRef.java:265)

at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:271)

at sun.rmi.transport.Transport$1.run(Transport.java:148)

at java.security.AccessController.doPrivileged(Native Method)

at sun.rmi.transport.Transport.serviceCall(Transport.java:144)

at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:460)

at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:701)

at java.lang.Thread.run(Thread.java:536)

Grato
Renato

20 Respostas

danieldestro

Putz!
ResultSet com RMI não vai funcionar não heim!
Porque você não manda um List com os dados?

R

Daniel,

No VB, eu consigo retornar um recordset remotamente … mas se com o
RMI do Java não rola, sem problemas.

Já pensei em array, mas imagina uma tabela com 30 campos e 200 registros… heheh… o negócio fica meio portuga…

Esse list que vc sugeriu, seja um pouco mais especifico… que tipo vc sugere ?

Obrigado pela atenção…
Renato

danieldestro

Ao invés de passar como array, eu sugeri usar uma coleção do tipo java.util.List.

Bom, vou tentar me informar melhor sobre ResultSet passado via RMI, ma sinceramente acho que não rola.

A

A própria exceção já diz tudo… a classe de implementação do ResultSet não eh serializável… ponha suas informações num List, em objetos serializáveis, naturalmente…

R

Blz Alexandre … entendi a sua observação…

Estou tentando utilizar o List que vc’s sugeriram, mas não estou tendo
sucesso. De que maneira posso gravar as informações neste list ?
Imagino que deve ser um array bidimensional onde uma dimensão
é o campo e a outra o valor do campo …

Vc’s tem algum exemplo prático de utilização ?

Grato
Renato.

danieldestro

List lista = new ArrayList&#40;&#41;; Pessoas p = null; while&#40; rs.next&#40;&#41; &#41; &#123; p = new Pessoa&#40;&#41;; p.setNome&#40; rs.getString&#40;1&#41; &#41;; lista.add&#40; p &#41;; &#125; return lista;

R

Daniel / Alexandre…

O mesmo erro ocorre com o List !
Será que a classe de implementação do List tb não é serializável ?

Abaixo o código fonte …

//  Interface (RMI)

public interface CLocadora extends java.rmi.Remote {

String sayHello() throws java.rmi.RemoteException;
String sayHello2() throws java.rmi.RemoteException;

java.util.List pesquisarCliente() throws java.rmi.RemoteException;

}

// Classe Servidora

import java.util.<em>;

import java.sql.</em>;

import java.rmi.*;

import java.rmi.server.UnicastRemoteObject;
public class CLocadoraImpl extends UnicastRemoteObject implements CLocadora {

private Connection connection;

private String nome;
public CLocadoraImpl() throws java.rmi.RemoteException {
	super();
	nome = sayHello();
}
public String sayHello() throws RemoteException {
	return "Hello World !!!";
}

public String sayHello2() throws RemoteException {
	return "Hello World 2 !!!";
}

private void conectaBanco() throws RemoteException {		 
	 String url = "jdbc:odbc:DSN_LOCADORA";
	 String username = "renatop";
	 String password = "prenato";
	
	 // Carrega o driver para permitir conexão ao banco de dados
	 try {
	 Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver" );
	
	 connection = DriverManager.getConnection(
	 url, username, password );
	 }
	 catch ( ClassNotFoundException cnfex ) {
	 System.err.println(
	 "Failed to load JDBC/ODBC driver." );
	 cnfex.printStackTrace();
	 System.exit( 1 ); // termina o programa
	 }
	catch ( SQLException sqlex ) {
	 System.err.println( "Unable to connect" );
	 sqlex.printStackTrace();
	 }
}


class Cliente {
	int cod_cliente;
	String nom_cliente;
	
}

public List pesquisarCliente() throws RemoteException {
	//String [] [] cliente = {null,null};

	conectaBanco();		
	
    List listResultado = new ArrayList();
    
    //    java.util.ArrayList list2;
    
    Statement statement;
	ResultSet resultSet;
	resultSet = null;
	
	try {
	 String query = "SELECT * FROM cliente";
	
	 statement = connection.createStatement();
	 resultSet = statement.executeQuery( query );		 

	 Cliente cl = null;
	 while(resultSet.next()){
	   cl = new Cliente();
	   cl.cod_cliente = (resultSet.getInt(1));
	   cl.nom_cliente = (resultSet.getString(2));
	   listResultado.add(cl);
	  }	

	 statement.close();
	 return listResultado; 
	 
	 }
	 catch ( SQLException sqlex ) {		 	
	 sqlex.printStackTrace();
	 return listResultado;
	 }		 
	 
//  return null;  
}

public static void main(String[] args) {
	
	//System.setSecurityManager(new RMISecurityManager());
	try {
		CLocadoraImpl obj = new CLocadoraImpl();
		Naming.rebind("//localhost/CLocadoraServer", obj);
		System.out.println("LocadoraImpl foi criado e registrado");
	}
	catch(Exception e) {
		System.out.println("Ocorreu uma exceção no servidor");            
		e.printStackTrace();
}

}

}

// Classe Cliente

private class ClickButton implements ActionListener

{

java.sql.ResultSet result;

List lista = new ArrayList();
public void actionPerformed( ActionEvent e )

{

if (e.getSource() == bt1) {

try   {

CLocadora obj = (CLocadora) Naming.lookup("<a href="//localhost/CLocadoraServer">//localhost/CLocadoraServer</a>");

lista = obj.pesquisarCliente();

}

catch (Exception xe){   		

xe.printStackTrace();

}

}

}

}
C

Ola,

Verifique se sua classe Cliente implementa a interface java.io.Serializable.

A classe mais parecida com RecordSet da Microsoft são os
RowSets.

Eu estou usando a implementacao da Sun. Os rowsets serializaveis sao
os CachedRowSetImpl e o WebRowSetImpl. O ultimo extende o primeiro, com os metodos readlXml, writeXml.

Os dois ultimos metodos sao interessantes. Vamos supor que vc nao queira serializar um objeto WebRowSet. Vc pode gravar o conteudo XML em uma String e enviar a string…na outra ponta vc. le a string com o readXML, gerando o objeto igual ao da outra ponta !!!

Outro detalhe no seu codigo: procure criar uma classe utilitaria para
JDBC. Seria algo do:

public class DB &#123;

   private static DataSource ds;

   public static DataSource getDataSource&#40;&#41; &#123;
      if &#40;ds == null&#41; &#123;
         // obtem o darasource e seta a properidade ds.
         // talvez vc queira sincrhonizar aqui.
      &#125; 
      return ds;
   &#125;


   public static Connection getConnection&#40;&#41; &#123;
      return getDataSource&#40;&#41;.getConnection&#40;&#41;;
   &#125;

   public static void closeConnection&#40;Connection conn&#41; &#123; // fechar obs. JDBC eh um saco !
      if &#40;conn != null&#41; &#123;
        try &#123;
               conn.close
        &#125; catch &#40;SQLException e&#41; &#123;
             // grava um log 
        &#125;
     &#125;

     // e por ai vai....

&#125;
R

Comazzi…

Obrigado pela aula…

Cara, não querendo abusar … mas vc teria algum exemplo deste RowSets… parece interessante…

Valeu,
Renato

C

Cara,

RowSets é tão facil quanto tirar doce de criança…hehhehe

Comece baixando a implementacao da Sun:

http://java.sun.com/products/jdbc/download.html#rowset1_0_1

Ha documentacao eh bastante completa. Só existe um pequeno detalhe. Pode ocorrer um bug na execucao do seu projeto. Eh por falta de um recurso de localizacao (um arquivo com msg. traduzidas). Para solucionar vc tera que chamar no metodo main do seu projeto o seguinte:

java.util.locate.setDefault&#40;Locale.ENGLISH&#41;;

Agora um exemplo de um metodo:

public CachedRowSetImpl pesquisarCliente&#40;&#41; throws RemoteException &#123;
   CachedRowSetImpl result = null;
   Connection conn = null;
   PreparedStatement pstmt = null;
   ResultSet rset = null;
   try &#123;     
      conn = DB.getConnection&#40;&#41;; // classe utilitaria DB
      pstmt = conn.prepareStatement&#40;"SELECT * FROM cliente"&#41;; // otimize!
      rset = pstmt.executeQuery&#40;&#41;;
      if &#40;rset.next&#40;&#41; &#123;
         result = new CachedRowSetImpl&#40;&#41;;
         result.populate&#40;rset&#41;;  // aqui ocorre a magica !!!
      &#125;
   &#125; catch &#40;SQLException e&#41; &#123;
      thow new RuntimeException&#40;"Ocorreu um erro grave",e&#41;;
   &#125; finally &#123;
      DB.closeResultSet&#40;rset&#41;; // nao se esqueca de fechar !!!
      DB.closePreparedStatement&#40;pstmt&#41;; // nao se esqueca de fechar !!!
      DB.closeConnection&#40;conn&#41;; // nao se esqueca de fechar !!!
   &#125;
   return result;    
&#125;

Vc pode tambem chamar comando SQL diretamente do RowSet.
Porém , apesar do codigo ser um pouco maior, é muito mais rapido fazer
da forma mostrada.

Um dos metodos que vc podera se interessar é o setPageSize(), que
define a quantidade de linhas que vc pode recuperar por vez.

R

Comazzi,

Fiz o Serializable na classe “cliente”, porém, a aplicação client não consegue acessar esta classe (acho até isso lógico, pois a classe “cliente”
esta no servidor).

public class CLocadoraImpl extends UnicastRemoteObject implements CLocadora {

class Cliente implements Serializable {
	private int cod_cliente;
	private String nom_cliente;		
	
	public int getCodigo() {			
		return cod_cliente;
	}
	
	public String getNome() {			
		return nom_cliente;
	}
	
	public void setCodigo(int codigo) {
	  this.cod_cliente = codigo;
	}
	
	public void setNome(String nome) {
	  this.nom_cliente = nome;
	}
}

public List pesquisarCliente() throws RemoteException {
	//String [] [] cliente = {null,null};

	conectaBanco();		
			
    List listResultado = new ArrayList();
    
    //    java.util.ArrayList list2;
    
    Statement statement;
	ResultSet resultSet;
	resultSet = null;
	
	try {
	 String query = "SELECT * FROM cliente order by cod_cliente ";
	
	 statement = connection.createStatement();
	 resultSet = statement.executeQuery( query );		 

	 int x = 0;
	 Cliente cl = null;
	 while(resultSet.next()){
	   cl = new Cliente();
	   cl.setCodigo(resultSet.getInt(1));
	   cl.setNome(resultSet.getString(2));
	   listResultado.add(cl);		   
	    
//	   listResultado.add(x,resultSet.getString(2));
//	   listResultado.add(x,resultSet.getString(3));
	   x = x + 1;
	  }	
	 		 
	 statement.close();
	 return listResultado; 
	 
	 }
	 catch ( SQLException sqlex ) {		 	
	 sqlex.printStackTrace();
	 return listResultado;
	 }

// return listResultado;
}

Na Aplicação Client esta assim:
CLocadora obj = (CLocadora) Naming.lookup("//localhost/CLocadoraServer");
lista = obj.pesquisarCliente(); // DA ERRO AQUI

java.lang.ClassCastException: cannot assign instance of CLocadoraImpl_Stub to field CLocadoraImpl$Cliente.this$0 of type CLocadoraImpl in instance of CLocadoraImpl$Cliente
at java.io.ObjectStreamClass$FieldReflector.setObjFieldValues(ObjectStreamClass.java:1840)

Cara, tô ficando pirado com esse negócio… que aparentemente é simples… :shock:

Se vc tiver uma idéia melhor …
Valeu…
Renato.

R

Comazzi,

Gostei deste RowSets… vou fazer testes … é simples pra caramba…

Valeu
Renato.
Ps.: Mandei uma mensagem anterior pra ti referente ao problema do Serializable.

C

teu problema parece ser outro.

tenta gerar novamente stubs com o comando rmic. Experimenta relancar
o servidor.

e vc vai conseguir pegar os clientes sim !!!

lista = obj.pesquisarCliente&#40;&#41;; 
for &#40;int i = 0, n = lista.size&#40;&#41;; i &lt; n ; i++&#41; &#123;
  Cliente cliente = &#40;Cliente&#41; lista.get&#40;i&#41;;
   System.out.println&#40;cliente.getNome&#40;&#41;&#41;;
&#125;

Obs: usando ArrayList em vez do Rowset, o programa ficara MUITOOO
mais rapido. A desvantagem eh que vc fica meio que preso…

R

:frowning:
Comazzi !

O erro persiste, ja tinha tentado gerar novamente o Stub e reiniciar o
rmiregistry …

Lembrando que o erro da na Aplicação Client:

lista = obj.pesquisarCliente();

Sinceramente, não sei mais o que fazer… só sei que tem algum
gato nessa classe “cliente”…

Renato.

C

Humm…

Sempre que faco algum servico RMI, eu gosto de implementar sempre um metodo chamado echo:

public String echo&#40;String mensagem&#41; &#123;
   return "ECHO&#58; " + mensagem;
&#125;

Faz isso…adiciona esse metodo e ve se esta funcionando. Acho que o problema esta “fora do programa”… ok ?

R

Comazzi,

Tenho um outro método nesta classe, que valida o login, ele esta funcionando corretamente, inclusive testei em máquinas diferentes…
A diferença entre os métodos é que o de validação de login retorna
true ou false…

Por isso acho que o problema é no programa …

Vc já fez algum programa que retorna um list com dados de uma tabela utilizando RMI ??

Tenho certeza que o problema deve ser um detalhe bem simples que não estamos conseguindo ver…

Renato.

_fs

Só para confirmar, você fez

public class MeuObjeto implements java.io.Serializable

certo?

R

Sim, só que a classe não esta definida como public…
será que é isso ? Mas aí tenho que enfiar ela em um
arquivo separado…

class Cliente implements Serializable {

private int cod_cliente;

private String nom_cliente;
public int getCodigo() {

return cod_cliente;

}
public String getNome() {

return nom_cliente;

}
public void setCodigo(int codigo) {

this.cod_cliente = codigo;

}
public void setNome(String nome) {

this.nom_cliente = nome;

}

}
C

nao tem nenhuma importancia deixar ela em arquivo separado.

é até mais correto…

R

blz, vou fazer os testes… mas só por causa de uma simples seleção tenho que criar uma classe publica…

Volto a fazer a novamente a pergunta (putz, daqui a pouco vc’s vão perder a paciência comigo) …

Tem outra forma de eu carregar este list sem esta classe ? O que é mais usado ? Um exemplo (de preferencia completo) por favor !!!

Valeu !!!
Renato.

Criado 11 de outubro de 2004
Ultima resposta 15 de out. de 2004
Respostas 20
Participantes 5