Sobes.tech
Senior

Jak stworzyć własny protokół serializacji?

sobes.tech AI

Odpowiedź od AI

Aby stworzyć własny protokół serializacji w Java, należy zdefiniować format danych i zaimplementować logikę odczytu/zapisu.

  1. Zdefiniuj format danych: Zdecyduj, jak obiekty będą reprezentowane w postaci bajtów. Może to być format binarny (bardziej zwarty) lub tekstowy (bardziej czytelny). Na przykład można użyć prefiksu długości przed polami.

  2. Zaimplementuj odczyt i zapis:

    • Utwórz klasę MySerializer (lub podobną), która będzie zawierać metody serialize i deserialize.
    • Metoda serialize przyjmie obiekt i OutputStream, zapisując bajty obiektu do strumienia zgodnie z określonym formatem.
    • Metoda deserialize przyjmie InputStream i odtworzy obiekt z bajtów.
  3. Oznacz klasy do serializacji: Klasy, które mają być serializowane, powinny mieć mechanizm do współpracy z serializatorem. Może to być:

    • Implementacja interfejsu Serializable (wtedy używany jest standardowy mechanizm Java).
    • Definiowanie własnych metod writeObject i readObject (podobnie do readObject i writeObject dla standardowej serializacji, ale z własną sygnaturą).
    • Użycie adnotacji do wskazania pól, które mają być serializowane, i ich kolejności.
  4. Obsługa odwołań do obiektów: Rozważyć, jak będą serializowane obiekty z cyklicznymi odwołaniami lub duplikatami odwołań do tego samego obiektu. Można użyć mechanizmu przechowywania ID obiektów.

  5. Obsługa wersji: Zaplanuj, jak będzie przebiegała deserializacja danych serializowanych w starszych wersjach protokołu.

Przykład podstawowej implementacji (bez obsługi złożonych przypadków):

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

public class MySerializer {

    // Zapisuje pole całkowite
    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);
    }

    // Odczytuje pole całkowite
    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;
    }

    // Zapisuje pole tekstowe (prosty sposób: długość + bajty tekstu)
    public void writeString(OutputStream os, String value) throws IOException {
        byte[] bytes = value.getBytes("UTF-8");
        writeInt(os, bytes.length); // Zapisz długość
        os.write(bytes); // Zapisz bajty
    }

    // Odczytuje pole tekstowe
    public String readString(InputStream is) throws IOException {
        int length = readInt(is); // Odczytaj długość
        byte[] bytes = new byte[length];
        is.read(bytes); // Odczytaj bajty
        return new String(bytes, "UTF-8");
    }

    // Serializuje prosty obiekt Person
    public void serialize(OutputStream os, Person person) throws IOException {
        writeString(os, person.getName());
        writeInt(os, person.getAge());
    }

    // Deserializuje prosty obiekt Person
    public Person deserialize(InputStream is) throws IOException {
        String name = readString(is);
        int age = readInt(is);
        return new Person(name, age);
    }

    // Klasa pomocnicza do przykładu
    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());
    }
}

Stworzenie własnego protokołu wymaga starannego planowania i uwzględnienia wielu czynników, takich jak wydajność, zwartość, wersjonowanie i obsługa złożonych struktur danych. Często zamiast tworzenia protokołu od podstaw używa się już istniejących bibliotek (ProtoBuf, Kryo, Avro).