Sobes.tech
Senior

Kaip sukurti savo serializacijos protokolą?

sobes.tech AI

Atsakymas iš AI

Norint sukurti savo serializacijos protokolą Java, reikia nustatyti duomenų formatą ir įgyvendinti skaitymo/rašymo logiką.

  1. Nustatyti duomenų formatą: Spręsti, kaip objektai bus pateikiami baitų formatu. Tai gali būti binarinis formatas (kompaktiškesnis) arba tekstinis (labiau skaitomas). Pavyzdžiui, galima naudoti ilgio prefiksą prieš laukus.

  2. Įgyvendinti skaitymą ir rašymą:

    • Sukurti klasę MySerializer (ar panašią), kuri turės metodus serialize ir deserialize.
    • Metodas serialize priims objektą ir OutputStream, įrašydamas objekto baitus į srautą pagal nustatytą formatą.
    • Metodas deserialize priims InputStream ir atkurs objektą iš baitų.
  3. Žymėti klases serializacijai: Klasės, kurias reikia serializuoti, turi turėti mechanizmą sąveikai su serializatoriumi. Tai gali būti:

    • Serializable sąsajos įgyvendinimas (bet tada bus naudojamas standartinis Java mechanizmas).
    • Naudotojo apibrėžti metodai writeObject ir readObject (panašiai kaip readObject ir writeObject standartinei serializacijai, bet su savo parašais).
    • Anotacijų naudojimas nurodyti laukus, kurie turi būti serializuoti, ir jų tvarką.
  4. Nuorodų apdorojimas: Apsvarstyti, kaip serializuoti objektus su ciklinėmis nuorodomis ar dubliuojančiomis nuorodomis į tą patį objektą. Galima naudoti ID mechanizmą.

  5. Versijų apdorojimas: Numatyti, kaip bus vykdoma deserializacija iš senesnės protokolo versijos duomenų.

Pavyzdinis bazinis įgyvendinimas (be sudėtingų atvejų apdorojimo):

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

public class MySerializer {

    // Rašo sveikojo skaičiaus lauką
    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);
    }

    // Skaito sveikojo skaičiaus lauką
    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;
    }

    // Rašo eilutės lauką (paprastas būdas: ilgis + eilutės baitai)
    public void writeString(OutputStream os, String value) throws IOException {
        byte[] bytes = value.getBytes("UTF-8");
        writeInt(os, bytes.length); // Rašo eilutės ilgį
        os.write(bytes); // Rašo eilutės baitus
    }

    // Skaito eilutės lauką
    public String readString(InputStream is) throws IOException {
        int length = readInt(is); // Skaito eilutės ilgį
        byte[] bytes = new byte[length];
        is.read(bytes); // Skaito eilutės baitus
        return new String(bytes, "UTF-8");
    }

    // Pavyzdys serializuojant paprastą Person objektą
    public void serialize(OutputStream os, Person person) throws IOException {
        writeString(os, person.getName());
        writeInt(os, person.getAge());
    }

    // Pavyzdys deserializuojant Person objektą
    public Person deserialize(InputStream is) throws IOException {
        String name = readString(is);
        int age = readInt(is);
        return new Person(name, age);
    }

    // Pagalbinė klasė pavyzdžiui
    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("Originalas: " + originalPerson.getName() + ", " + originalPerson.getAge());
        System.out.println("Deserializuotas: " + deserializedPerson.getName() + ", " + deserializedPerson.getAge());
    }
}

Sukurti savo protokolą reikalauja kruopštaus planavimo ir daugelio veiksnių apsvarstymo, tokių kaip našumas, kompaktiškumas, versijavimas ir sudėtingų duomenų struktūrų apdorojimas. Dažnai naudojamos jau esamos bibliotekos (ProtoBuf, Kryo, Avro) vietoje nuo nulio kuriant protokolą.