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]にあります。