Serializando e deserializando em XML e JSON

É possível se serializar objetos em XML e JSON.

XML

Veja no exemplo a seguir como um objeto Bastiao é serializado em XML usando o XMLEncoder. Por enquanto, você pode entender intuitivamente o XML comparando-o com o HTML. No entanto, no XML os tags podem ser customizados para atender a um contexto específico.

A serialização do objeto bastião irá gerar um arquivo thebastian.xml com o estado do objeto (veja arquivo que será criado).

O XML tem a seguinte estrutura:

<object class="REPL.$JShell$23G$Bastiao">
  <void property="estado">
   <string>acordado</string>
  </void>
  <void property="idade">
   <int>3</int>
  </void>
  <void property="nome">
   <string>Asdrubal</string>
  </void>
</object>

Note que os tags XML foram ajustados para atender à estrutura do Bastiao através de reflexão.

Veja que a serialização foi combinada com streams para a gravação dos dados.


In [5]:
import java.io.Serializable;
import java.beans.XMLEncoder;
import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class Bastiao implements Serializable
{
    private static final long serialVersionUID = 3863010501019562695L;
    
    private int idade;
    private String estado;
    private String nome;
    
    public final static int MAIOR_IDADE = 3;
    
    public Bastiao()
    {
        
    }
    
    public Bastiao(int idade, String estado, String nome)
    {
        this.idade = idade;
        this.estado = estado;
        this.nome = nome;
    }
    
    public void aparece()
    {
        // cabeleira
        if (idade >= 2)
            System.out.println("  *");
        
        // corpo com olhos
        if (estado.equalsIgnoreCase("acordado"))
            System.out.println(" o*o");
        else
            System.out.println(" -*-");
        
        // barba
        if (idade >= 3)
            System.out.println("*****");
        
        System.out.println(nome);
        
        System.out.println();
    }
    
    public void cresce()
    {
        if (idade < MAIOR_IDADE)
            idade++;
        aparece();
    }
    
    public void acorda()
    {
        estado = "acordado";
        aparece();
    }
    
    public void dorme()
    {
        estado = "dormindo";
        aparece();
    }
    
    /* Getters e setters
     */

    public int getIdade() {
        return idade;
    }

    public void setIdade(int idade) {
        this.idade = idade;
    }

    public String getEstado() {
        return estado;
    }

    public void setEstado(String estado) {
        this.estado = estado;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }
}

Bastiao theBastian = new Bastiao(3, "acordado", "Asdrubal");

try {
    XMLEncoder encoder = new XMLEncoder(
            new BufferedOutputStream(
                    new FileOutputStream("thebastian.xml") ) );
    encoder.writeObject(theBastian);
    encoder.close();

    System.out.println("Objeto gravado com sucesso!");
} catch (FileNotFoundException e) {
    e.printStackTrace();
}


Objeto gravado com sucesso!

Deserializando XML

A deserialização é o processo inverso usando o XMLDecoder, como pode ser visto a seguir:


In [7]:
import java.beans.XMLDecoder;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

Bastiao theBastian;

try {
    XMLDecoder decoder = new XMLDecoder(
            new BufferedInputStream(
                    new FileInputStream("thebastian.xml") ) );

    theBastian = (Bastiao)decoder.readObject();
    decoder.close();

    theBastian.aparece();
} catch (FileNotFoundException e) {
    e.printStackTrace();
}


  *
 o*o
*****
Asdrubal

Canalizando a saída de um stream para uma String

É possível canalizar a saída de uma steam para uma String (em vez, por exemplo, de um arquivo) usando-se o ByteArrayOutputStream. Veja a seguir como a serialização XML foi direcionada para um ByteArrayOutputStream que guarda os dados na memória. Em seguida, é possível usar o método toString() para transaformar o stream numa String. Assim, é possível se transformar o estado do Bastiao em uma String XML.


In [13]:
Bastiao theBastian = new Bastiao(2, "dormindo", "Doriana");

ByteArrayOutputStream bastiaoXMLStream = new ByteArrayOutputStream();
XMLEncoder encoder = new XMLEncoder(bastiaoXMLStream);
encoder.writeObject(theBastian);
encoder.close();

String bastiaoXML = bastiaoXMLStream.toString();
System.out.println(bastiaoXML);


<?xml version="1.0" encoding="UTF-8"?>
<java version="10.0.1" class="java.beans.XMLDecoder">
 <object class="REPL.$JShell$23G$Bastiao">
  <void property="estado">
   <string>dormindo</string>
  </void>
  <void property="idade">
   <int>2</int>
  </void>
  <void property="nome">
   <string>Doriana</string>
  </void>
 </object>
</java>

Canalizando uma String como entrada de uma String

Também é possível se fazer o inverso com o ByteArrayInputStream. Veja como a String XML que tem o estado do Bastiao foi convertida em um objeto:


In [14]:
import java.beans.XMLDecoder;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

Bastiao theBastian;

XMLDecoder decoder = new XMLDecoder(
   new ByteArrayInputStream(bastiaoXML.getBytes()));

theBastian = (Bastiao)decoder.readObject();
decoder.close();

theBastian.aparece();


  *
 -*-
Doriana

Exercício

Considere a implementação do pattern Observer de Pontos de Transação feitos no notebook conta-observer-dao.ipynb. Adapte o exemplo para que um ponto de transação envie para objetos IMovimento transações serializadas em XML (usando o modelo de String em memória, não por arquivo).

Os objetos conta devem deserializar o XML e aplicar e registrar a transação, como no modelo original.

Resolução


In [ ]: