T003: Serialización de Objetos para persistencia en Java

publicado a la‎(s)‎ 14 may. 2012 11:34 por Hernan Nina Hanco   [ actualizado el 4 jun. 2013 11:00 ]

I) Objetivo

  • Conocer la Serialización de objetos como técnica de persistencia de datos..


II) Marco conceptual


Almacenar objetos en un Archivo

La serialización consiste en convertir un objeto en una secuencia de bytes para guardarlo en un archivo o enviarlo por la red, y luego reconstruirlo, con los valores que tenía al ser serializado, para su posterior utilización. La serialización es muy utilizada en las bases de datos relacionales, pero tiene también otras aplicaciones. En Java, esta capacidad de serialización, es decir, de guardar información sobre un objeto para luego recuperarla, se llama persistencia.


Para que un objeto sea serializable basta con que la clase a la que pertenezca, o una superclase de ésta, implemente la interfaz Serializable o su subinterfaz Externalizable, ambas en el paquete java.io.


Implementar Serializable es muy sencillo, porque no tiene métodos. En realidad actúa como un marcador que indica que los objetos de una clase (o de sus subclases) son serializables, de esta manera:


class MiClase implements Serializable


Para utilizar correctamente Serializable, hay que tener en cuenta algunos detalles.

  • Primero, lo que estamos serializando son objetos y sus campos, así que las variables marcadas como static, es decir, que pertenecen a la clase y no al objeto, no pueden ser serializadas.
  • Segundo, supongamos que queremos serializar un objeto que contiene una referencia a una instancia de una clase que no es serializable. Esto produciría la ya conocida NotSerializableException. Para evitarlo, debemos marcar esa instancia como transient. Todos los campos marcados como transient serán ignorados por la JVM en el proceso de serialización.

Veamos todo esto con un ejemplo:


public class MiClase implements Serializable{

     private int variable1;

     private static double variable2;

     private transient OtraClase oc = new OtraClase();

}

class OtraClase{} //OtraClase no es serializable


Cuando un objeto de la clase MiClase sea serializado, sólo su variable "variable1" será serializada. La variable "variable2" no, porque es static y por tanto pertenece a la clase y no al objeto, y la variable oc tampoco porque está marcada transient. Si no añadiéramos el modificador transient tendríamos una NotSerializableException, pero también podemos utilizarlo cuando no nos interese serializar algo.


III) Practicas


1) Ejemplo de serialización y recuperación de objetos.

Implementar una Clase Agenda Serializable

package demo;

/**
 *
 * @author hernan
 */
import java.io.*;
class Agenda implements Serializable {

    private String nombre;
    private String p_Apellido;
    private String s_Apellido;
    /*getters y setters*/

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public String getP_Apellido() {
        return p_Apellido;
    }

    public void setP_Apellido(String p_Apellido) {
        this.p_Apellido = p_Apellido;
    }

    public String getS_Apellido() {
        return s_Apellido;
    }

    public void setS_Apellido(String s_Apellido) {
        this.s_Apellido = s_Apellido;
    }

    
    public Agenda(String nombre, String p_Apellido, 
            String s_Apellido) {
        super();
        this.nombre = nombre;
        this.p_Apellido = p_Apellido;
        this.s_Apellido = s_Apellido;
    }

    @Override
    public String toString() {
        return (getNombre() + " " + 
                getP_Apellido() + " " + getS_Apellido());
    }
}


Implementar una clase para Serializar objetos de la clase Agenda


package demo;

import java.io.*;

/**

 *

 * @author hernan

 */

public class Serializacion {


    public static void main(String[] args) {

        // Crear objetos de clase Agenda

        Agenda a1 = new Agenda("Ana1", "Martínez1", "Fernández1");

        Agenda a2 = new Agenda("Ernesto", "García", "Pérez");

        // iniciar el proceso de serialización

        // colocar los objetos a1 y a2 en disco

        try {

            //Creamos el archivo

            FileOutputStream fs =

                    new FileOutputStream("agenda1.ser");

            //Esta clase tiene el método writeObject() que necesitamos

            ObjectOutputStream os =

                    new ObjectOutputStream(fs);


            //El método writeObject() serializa el objeto 

            //y lo escribe en el archivo         

            os.writeObject(a1);

            os.writeObject(a2);

            //Hay que cerrar siempre el archivo

            os.close();

        } catch (FileNotFoundException e) {

            e.printStackTrace();

        } catch (IOException e) {

            e.printStackTrace();

        }

        System.out.println(

                "Los Objetos se han serializado correctamente.");

    }

}


Implementar una clase para desealizar objetos de la clase Agenda.

package demo;

import java.io.*;
/**
 *
 * @author hernan
 */
public class Deserealizacion {

    public static void main(String[] args) {
        Agenda a1 = null;
        Agenda a2 = null;
        try {
            // abrir o Recuperar un archivo de disco
            FileInputStream fis = 
                    new FileInputStream("agenda1.ser");
            // Stream para recuperar o reconstruir objetos
            ObjectInputStream ois = 
                    new ObjectInputStream(fis);
            //El método readObject() recupera el objeto
            a1 = (Agenda) ois.readObject();
            a2 = (Agenda) ois.readObject();
            ois.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        System.out.println(a1);
        System.out.println(a2);

    }
}

2)
Ejemplo práctico utilizando el modificador transient y reescribir los métodos writeObject y readObject

import java.io.*;

import java.util.*;


public class TestSer{

  public static void main(String[] args) throws Exception{

     FileOutputStream fos = new FileOutputStream("test.ser");

     ObjectOutputStream os = new ObjectOutputStream(fos);

     Prueba p = new Prueba(358);

     os.writeObject(p);

     os.close();

     FileInputStream fis = new FileInputStream("test.ser");

     ObjectInputStream is = new ObjectInputStream(fis);

     p = (Prueba) is.readObject();

     System.out.println("Datos: " + p.getDatos());

     System.out.println("Hora actual: " + p.getHoraActual());

     is.close();

  }

}

class Prueba implements Serializable{

  private static final long seriaVersionUID = 3L; //

  private transient int datos; //son transient pero necesitamos serializarlos

 private transient Date horaActual;//lo queremos sólo en el servidor receptor

  public Prueba(int datos){

     this.datos = datos;

     this.horaActual = new Date();

  }

  private void writeObject(ObjectOutputStream os){

     try{

        os.defaultWriteObject(); //el método por defecto

        /*ahora escribimos lo que queremos que haga*/

        os.writeInt(datos);

        System.out.println("Serialización");

     }catch(IOException e){

        e.printStackTrace();

     }

  }

  private void readObject(ObjectInputStream is){

     try{

        is.defaultReadObject();

        datos = is.readInt();

        horaActual = new Date();

        System.out.println("Recuperación");

     }catch(IOException e){

        e.printStackTrace();

     }catch(ClassNotFoundException e){

        e.printStackTrace();

     }

  }

  public int getDatos(){

     return datos;

  }

  public Date getHoraActual(){

     return horaActual;

  }

}


IV) Tarea

1) Probar la serialización con clases que tienen atributos transient y static. Interpretar los resultados.

2) Defina una clase Persona para encapsular el nombre de una persona y su dirección. El nombre y la dirección debe ser del Tipo Nombre y Tipo de Dirección. Escriba un programa que permite que los nombres y direcciones que deben introducirse desde el teclado, se almacenen como objetos de Persona en un archivo. Una vez que el archivo existe se añaden nuevas entradas al archivo.

3) Extender el programa anterior para listar las personas del archivo.

 

V) Referencias



Comments