Sobes.tech
Senior

¿Cómo crear tu propio protocolo de serialización?

sobes.tech AI

Respuesta de la IA

Para crear un propio protocolo de serialización en Java, es necesario definir el formato de datos y implementar la lógica de lectura/escritura.

  1. Definir el formato de datos: Decidir cómo se representarán los objetos en forma de bytes. Esto puede ser un formato binario (más compacto) o de texto (más legible). Por ejemplo, se puede usar un prefijo de longitud antes de los campos.

  2. Implementar lectura y escritura:

    • Crear una clase MySerializer (u otra similar), que contenga los métodos serialize y deserialize.
    • El método serialize tomará un objeto y un OutputStream, escribiendo los bytes del objeto en el flujo según el formato definido.
    • El método deserialize tomará un InputStream y reconstruirá el objeto a partir de los bytes.
  3. Marcar las clases para serialización: Las clases que necesitan ser serializadas deben tener un mecanismo para interactuar con el serializador. Esto puede ser:

    • Implementar la interfaz Serializable (pero entonces se usará el mecanismo estándar de Java).
    • Definir métodos personalizados writeObject y readObject (similar a readObject y writeObject para la serialización estándar, pero con una firma propia).
    • Usar anotaciones para indicar los campos que deben ser serializados y su orden.
  4. Manejo de referencias a objetos: Considerar cómo se serializarán objetos con referencias cíclicas o referencias duplicadas al mismo objeto. Se puede usar un mecanismo de almacenamiento de IDs de objetos.

  5. Manejo de versiones: Prever cómo se realizará la deserialización de datos serializados en versiones anteriores del protocolo.

Ejemplo de implementación básica (sin manejar casos complejos):

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class MySerializer {

    // Escribe un campo entero
    public void writeInt(OutputStream os, int value) throws IOException {
        os.write((value >>> 24) & 0xFF);
        os.write((value >>> 16) & 0xFF);
        os.write((value >>> 8) & 0xFF);
        os.write((value >>> 0) & 0xFF);
    }

    // Lee un campo entero
    public int readInt(InputStream is) throws IOException {
        int value = 0;
        value = (is.read() << 24);
        value |= (is.read() << 16);
        value |= (is.read() << 8);
        value |= (is.read() << 0);
        return value;
    }

    // Escribe un campo de cadena (simplemente: longitud + bytes de la cadena)
    public void writeString(OutputStream os, String value) throws IOException {
        byte[] bytes = value.getBytes("UTF-8");
        writeInt(os, bytes.length); // Escribir la longitud
        os.write(bytes); // Escribir los bytes
    }

    // Lee un campo de cadena
    public String readString(InputStream is) throws IOException {
        int length = readInt(is); // Leer la longitud
        byte[] bytes = new byte[length];
        is.read(bytes); // Leer los bytes
        return new String(bytes, "UTF-8");
    }

    // Serializar un objeto simple Person
    public void serialize(OutputStream os, Person person) throws IOException {
        writeString(os, person.getName());
        writeInt(os, person.getAge());
    }

    // Deserializar un objeto simple Person
    public Person deserialize(InputStream is) throws IOException {
        String name = readString(is);
        int age = readInt(is);
        return new Person(name, age);
    }

    // Clase auxiliar para ejemplo
    public static class Person {
        private String name;
        private int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public int getAge() {
            return age;
        }
    }

    public static void main(String[] args) throws IOException {
        MySerializer serializer = new MySerializer();
        Person originalPerson = new Person("Alice", 30);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        serializer.serialize(baos, originalPerson);
        byte[] serializedData = baos.toByteArray();

        ByteArrayInputStream bais = new ByteArrayInputStream(serializedData);
        Person deserializedPerson = serializer.deserialize(bais);

        System.out.println("Original: " + originalPerson.getName() + ", " + originalPerson.getAge());
        System.out.println("Deserialized: " + deserializedPerson.getName() + ", " + deserializedPerson.getAge());
    }
}

Crear un protocolo propio requiere una planificación cuidadosa y considerar muchos factores, como rendimiento, compacidad, control de versiones y manejo de estructuras de datos complejas. Frecuentemente, se usan bibliotecas existentes (ProtoBuf, Kryo, Avro) en lugar de crear un protocolo desde cero.