Kryoの紹介

1概要

Kryo は、速度、効率、およびユーザーフレンドリーなAPIに重点を置いたJavaのシリアル化フレームワークです。

この記事では、Kryoフレームワークの主な機能を探り、その機能を紹介するための例を実装します。

2 Mavenの依存関係

最初に必要なことは、 komo 依存関係を pom.xml に追加することです。

<dependency>
    <groupId>com.esotericsoftware</groupId>
    <artifactId>kryo</artifactId>
    <version>4.0.1</version>
</dependency>

このアーティファクトの最新バージョンはhttps://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22com.esotericsoftware%22%20AND%20a%3A%22kryo%22[Mavenにあります。中央]。

3 Kryoの基本

Kryoのしくみと、それを使用してオブジェクトをシリアル化および逆シリアル化する方法を調べることから始めましょう。

3.1. 前書き

このフレームワークは、そのすべての機能に対する主要なエントリポイントとして Kryo クラスを提供します。

このクラスはシリアル化プロセスを調整し、クラスをオブジェクトのグラフをバイト表現に変換する詳細を処理する Serializer インスタンスにマッピングします。

バイトの準備ができたら、それらは Output オブジェクトを使用してストリームに書き込まれます。このようにして、それらはファイル、データベースに保存されるか、またはネットワークを介して送信されることができます。

後でオブジェクトが必要になると、 Input インスタンスを使用してそれらのバイトを読み取り、それらをJavaオブジェクトにデコードします。

3.2. オブジェクトの直列化

例に入る前に、まず、この記事の各テストケースで使用するいくつかの変数を初期化するためのユーティリティメソッドを作成しましょう。

@Before
public void init() {
    kryo = new Kryo();
    output = new Output(new FileOutputStream("file.dat"));
    input = new Input(new FileInputStream("file.dat"));
}

これで、Kryoを使ってオブジェクトを書いたり読んだりすることがどれほど簡単かを見ることができます。

@Test
public void givenObject__whenSerializing__thenReadCorrectly() {
    Object someObject = "Some string";

    kryo.writeClassAndObject(output, someObject);
    output.close();

    Object theObject = kryo.readClassAndObject(input);
    input.close();

    assertEquals(theObject, "Some string");
}

close() メソッドの呼び出しに注目してください。 Output クラスと Input クラスはそれぞれ OutputStream InputStream を継承しているため、これが必要です。

複数のオブジェクトを直列化することも同様に簡単です。

@Test
public void givenObjects__whenSerializing__thenReadCorrectly() {
    String someString = "Multiple Objects";
    Date someDate = new Date(915170400000L);

    kryo.writeObject(output, someString);
    kryo.writeObject(output, someDate);
    output.close();

    String readString = kryo.readObject(input, String.class);
    Date readDate = kryo.readObject(input, Date.class);
    input.close();

    assertEquals(readString, "Multiple Objects");
    assertEquals(readDate.getTime(), 915170400000L);
}

適切なクラスを readObject() メソッドに渡しているので、コードがキャストフリーになります。

4シリアライザ

このセクションでは、どの Serializers が既に利用可能であるかを示してから、私たちは自分自身を作成し​​ます。

4.1. デフォルトのシリアライザ

Kryoがオブジェクトをシリアル化すると、以前に登録された Serializer クラスのインスタンスを作成してバイトへの変換を行います。これらはデフォルトのシリアライザと呼ばれ、私たちの側で設定をしなくても使用できます。

ライブラリには、プリミティブ、リスト、マップ、列挙などを処理するシリアライザがすでにいくつか用意されています。特定のクラスにシリアライザが見つからない場合は、 FieldSerializer が使用され、ほとんどすべての種類のオブジェクトを処理できます。

これがどのように見えるかを見てみましょう。まず、 Person クラスを作成しましょう。

public class Person {
    private String name = "John Doe";
    private int age = 18;
    private Date birthDate = new Date(933191282821L);

   //standard constructors, getters, and setters
}

それでは、このクラスからオブジェクトを作成して読み返しましょう。

@Test
public void givenPerson__whenSerializing__thenReadCorrectly() {
    Person person = new Person();

    kryo.writeObject(output, person);
    output.close();

    Person readPerson = kryo.readObject(input, Person.class);
    input.close();

    assertEquals(readPerson.getName(), "John Doe");
}

FieldSerializer は自動的に作成されるため、 Person オブジェクトをシリアル化するために何も指定する必要はありませんでした。

4.2. カスタムシリアライザ

シリアル化プロセスをもっと細かく制御する必要がある場合、2つの選択肢があります。独自の Serializer クラスを作成してそれをKryoに登録するか、クラスにそれ自体で直列化を処理させることができます。

最初のオプションを説明するために、 Serializer を拡張するクラスを作成しましょう。

public class PersonSerializer extends Serializer<Person> {

    public void write(Kryo kryo, Output output, Person object) {
        output.writeString(object.getName());
        output.writeLong(object.getBirthDate().getTime());
    }

    public Person read(Kryo kryo, Input input, Class<Person> type) {
        Person person = new Person();
        person.setName(input.readString());
        long birthDate = input.readLong();
        person.setBirthDate(new Date(birthDate));
        person.setAge(calculateAge(birthDate));
        return person;
    }

    private int calculateAge(long birthDate) {
       //Some custom logic
        return 18;
    }
}

それでは、テストしましょう。

@Test
public void givenPerson__whenUsingCustomSerializer__thenReadCorrectly() {
    Person person = new Person();
    person.setAge(0);

    kryo.register(Person.class, new PersonSerializer());
    kryo.writeObject(output, person);
    output.close();

    Person readPerson = kryo.readObject(input, Person.class);
    input.close();

    assertEquals(readPerson.getName(), "John Doe");
    assertEquals(readPerson.getAge(), 18);
}

age フィールドは、以前は0に設定されていましたが、18に等しいことに注意してください。

また、 @ DefaultSerializer アノテーションを使用して、 Person オブジェクトを処理する必要があるたびに PersonSerializer を使用したいことをKryoに知らせることもできます。これは register() メソッドの呼び出しを避けるのに役立ちます。

@DefaultSerializer(PersonSerializer.class)
public class Person implements KryoSerializable {
   //...
}

2番目のオプションとして、 Person クラスを変更して KryoSerializable インターフェースを拡張しましょう。

public class Person implements KryoSerializable {
   //...

    public void write(Kryo kryo, Output output) {
        output.writeString(name);
       //...
    }

    public void read(Kryo kryo, Input input) {
        name = input.readString();
       //...
    }
}

このオプションのテストケースは前のものと同じなので、ここには含まれません。ただし、この記事のソースコードにあります。

4.3. Javaシリアライザ

散発的なケースでは、Kryoはクラスをシリアル化することができません。これが起こり、カスタムシリアライザを書くことが選択できない場合は、 JavaSerializer を使って標準のJavaシリアライゼーションメカニズムを使うことができます。これはクラスが通常通りに Serializable インターフェースを実装することを必要とする。

前述のシリアライザを使った例です。

public class ComplexObject implements Serializable {
    private String name = "Bael";

   //standard getters and setters
}
@Test
public void givenJavaSerializable__whenSerializing__thenReadCorrectly() {
    ComplexClass complexObject = new ComplexClass();
    kryo.register(ComplexClass.class, new JavaSerializer());

    kryo.writeObject(output, complexObject);
    output.close();

    ComplexClass readComplexObject = kryo.readObject(input, ComplexClass.class);
    input.close();

    assertEquals(readComplexObject.getName(), "Bael");
}

5結論

このチュートリアルでは、Kryoライブラリの最も注目すべき機能について説明しました。

私たちは複数の単純なオブジェクトをシリアル化し、カスタムオブジェクトを扱うために FieldSerializer クラスを使いました。また、カスタムシリアライザを作成し、必要に応じて標準のJavaシリアル化メカニズムにフォールバックする方法を示しました。

いつものように、この記事の完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/libraries-data[over on Github]にあります。