domingo, 21 de outubro de 2012

Já ouviu falar em serialização ?

De forma genérica a serialização é uma técnica usada para persistir objetos em um programa, em outras palavras, consiste em:
  • gravar os dados dos objetos em um banco de dados e/ou arquivos,
  • fazer a transmissão remota de objetos via rede.
Serializar é colocar os valores que o objeto está utilizando (suas propriedades) de uma forma que fique em série (sequencial). Fazendo isto estamos tornando o objeto Serializable, e, tornando um objeto Serializable, estamos atribuindo essa qualidade a ele, e dando privilégios para que o mesmo possa ser gravado em disco ou enviado por rede.

Na serialização podem ser gravados os atributos públicos e privados para um stream. O processo inverso é chamado - deserialização, que consiste em restaurar os atributos de um objeto gravado em um stream.

Vamos considerar a seguinte classe:
/*
* Esta classe será utilizada para exemplo de serialização XML
* Notem que ela tem o formato de um bean
*
* Temos algumas propriedades: inteiro, string, boolean, array
*
*/
package serializacao;
/**
*
* @author Henrique
*/
public class ClasseSerializada1 {
  /*
   * Propriedade inteiro
   */
  int i;
  public int getInteiro() { return i; }
  public void setInteiro(int i) { this.i = i; }

  /*
   * Propriedade minhaString
   */
  String s;
  public String getMinhaString() { return s; }
  public void setMinhaString(String s) { this.s = s;}

  /*
   * Propriedade Array de inteiro
   */
  int[] ia = new int[0];
  public int[] getArrayInteiro() { return ia; }
  public void setArrayInteiro(int[] iarray) {this.ia = iarray; }

  /*
   * Imprime as propriedades (usado no teste para vermos o que está no objeto)
   */
  public void print() {
    System.out.println(getInteiro());
     System.out.println(getMinhaString());
     int[] a = getArrayInteiro();
     System.out.print("[");
     for(int j = 0; j < a.length; j++) {
       System.out.print(a[j]+" ");
     }
     System.out.println("]");
  }
}

Notem que existem 3 propriedades públicas (encapsuladas com getters e setters).
Vamos criar uma outra classe para fazer a gravação e leitura. Notem que o processo é bastante parecido com a leitura e gravação de arquivos e por isto utilizamos Buffered___Stream e File___Stream.

O procedimento é bastante simples




  • Fazemos (na escrita) o encadeamento de XMLEncoder(BufferedOutputStream(FileOutputStream))
  • Usamos o XMLEncoder.writeObject para escrever o objeto no arquivo
Pronto!!!
Para ler é só fazer o inverso:

  • chamar XMLDecoder(BufferedInputStream(FileInputStream))
  • Usar XMLDecoder.readObject
    • Prestar atenção que temos que fazer um cast da classe correta

/*
* classe para teste de funcionamento
*/
package serializacao;
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
/**
*
* @author Henrique
*/
public class Serializacao1 {
  /*
   * A classe XMLEncoder serializa um objeto parecido com java.io.ObjectOutput
   *  --> é por isto que transferimos as streams para gerar o arquivo de
   * O XMLEncoder somente persiste as propriedades públicas das classes
   * Para cada propriedade pública, XMLEncoder chama o método getter
   * (getPropriedade) correspondente e persiste o valor retornado
   *
   * Desta forma qualquer propriedade privada (que não possuir getter e setter)
   * não será persistida ==> veremos isto em outro post
  */
  public void serializar(String nomeArquivo, ClasseSerializada1 obj) {
   try {
      // Serializa o object no arquivo XML
      XMLEncoder encoder;
      encoder = new XMLEncoder(
      new BufferedOutputStream(
        new FileOutputStream(nomeArquivo)));
      encoder.writeObject(obj);
      encoder.close();
   } catch (FileNotFoundException e) {
     // imprime erro na console
     System.out.println(e.getMessage());
   }
  }

  /*
   * Na deserialização, um objeto criado é inicializado com os valores
   * persistidos no arquivo XML (as propriedades públicas)
   *
   * le o arquivo serializado para dentro do objeto ClasseSerializada
   * retorno o objeto lido do arquivo XML
   */
  public ClasseSerializada1 deserializar(String nomeArquivo) {
    ClasseSerializada1 obj = null;
    try {
      XMLDecoder decoder = new XMLDecoder(
      new BufferedInputStream(
         new FileInputStream(nomeArquivo)));
      obj = (ClasseSerializada1) decoder.readObject();
      decoder.close();
    } catch (FileNotFoundException e) {
      // imprime erro na console
      System.out.println(e.getMessage());
    }
    return obj; // retorna o objeto lido do arquivo XML
  }

}
 



Agora uma classe simples de teste.
/*
* classe para teste de funcionamento

  */ 
 package serializacao;
  /**
      * 

    * @author Henrique
    */
 public class TesteSerializacao { 

  /**   * @param args the command line arguments
   */ 
  public static void main(String[] args) { 

    static String nomeArquivoXML = "classeserializada.xml";
 

    Serializacao1 s1 = new Serializacao1();
    ClasseSerializada o = new ClasseSerializada();
    // define as propriedades
    o.setInteiro(1);
    o.setMinhaString("Esta string será serializada");
    o.setArrayInteiro(new int[]{1, 2, 3, 4});
    // imprime para conferirmos os resultados
    System.out.println("*************** Objeto criado");
    o.print();
    // grava (serializa) o objeto o
    s1.serializar(nomeArquivoXML, o);
    // faz alterações nos campos para podermos ver que
    // a deserialização funciona
    o.setInteiro(3);
    o.setMinhaString("string alterada");
    o.setArrayInteiro(new int[]{1, 2});
    System.out.println("*************** Objeto alterado");
    o.print(); // imprime o objeto alterado para vermos
    // busca os dados a partir do arquivo XML
    o = deserializar(nomeArquivoXML);
    System.out.println("********** Objeto deserializado");
    o.print(); // gera a mesma saída do primeiro o.print() deste método
  }
}


O arquivo XML gerado está mostrado abaixo. Notem que a classe serializada está identificada (pacote + classe) e as propriedades estão todas listadas e identificadas.

<?xml version="1.0" encoding="UTF-8"?>
<java class="java.beans.XMLDecoder" version="1.7.0_07">
<object class="serializacao.ClasseSerializada">
<void property="arrayInteiro">
  <array class="int" length="4">
    <void index="0"> <int>1</int> </void>
    <void index="1"> <int>2</int> </void>
    <void index="2"> <int>3</int> </void>
    <void index="3"> <int>4</int> </void>
  </array>
</void>
<void property="inteiro">
  <int>1</int>
</void>
<void property="minhaString">
  <string>Esta string será serializada</string>
</void>
</object>
</java>

Vemos no próximo posto como impedir uma propriedade pública de ser serializada e como serializar uma propriedade privada.

Podemos tornar a classe Serializacao1 mais genérica, recebendo e devolvendo objetos da classe  Object e fazendo o cast fora.


public class Serializacao {
  public void serializar(String nomeArquivo, Object obj) {
      ... // fica tudo igual

   }

  public Object deserializar(String nomeArquivo) {
    Object obj = null;
    try {
      XMLDecoder decoder = new XMLDecoder(
      new BufferedInputStream(
         new FileInputStream(nomeArquivo)));
      obj = decoder.readObject();
      decoder.close();
    } catch (FileNotFoundException e) {
      // imprime erro na console
      System.out.println(e.getMessage());
    }
    return obj; // retorna o objeto lido do arquivo XML
  }
}


No próximo post vamos usar este formato, ok?

Nenhum comentário:

Postar um comentário