Hessianを用いたJavaバイナリシリアライズの実践的解説

  1. Hessian依存関係の設定
<dependency>
    <groupId>com.caucho</groupId>
    <artifactId>hessian</artifactId>
    <version>4.0.38</version>
</dependency>
  1. シリアライズとデシリアライズの実装
public static byte[] convertToBinary(Object data) {
    ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
    Hessian2Output serializer = new Hessian2Output(byteStream);
    
    try {
        serializer.writeObject(data);
        serializer.flush();
        return byteStream.toByteArray();
    } catch (IOException e) {
        throw new RuntimeException("Serialization failed", e);
    }
}

public static Object convertFromBinary(byte[] binaryData) {
    ByteArrayInputStream stream = new ByteArrayInputStream(binaryData);
    Hessian2Input deserializer = new Hessian2Input(stream);
    
    try {
        return deserializer.readObject();
    } catch (Exception e) {
        throw new RuntimeException("Deserialization failed", e);
    }
}

Hessianのシリアライズ処理はHessian2Outputクラス、デシリアライズはHessian2Inputクラスを用いて実現されます。基本的なフローはバイナリストリームの準備→シリアライザによるデータ変換→ストリームのフラッシュという流れです。

  1. シリアライズの内部処理

3.1 シリアライザの初期化

Hessian2Outputの内部では、8KBのバッファを用意し、シリアライズ処理を効率化しています。初期化時にすべての参照情報をリセットし、ストリームを設定します。

3.2 オブジェクトシリアライズの処理

シリアライズ処理では、オブジェクトの型に基づき適切なシリアライザを選択します。基本データ型の処理は以下のようになります:

public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
    if (obj == null) {
        out.writeNull();
        return;
    }
    
    Serializer serializer = getSerializerFactory().getSerializer(obj.getClass());
    serializer.writeObject(obj, out);
}

基本型のシリアライザでは、文字列や数値などのタイプに応じて異なる処理を実行します。例えば文字列のシリアライズでは、以下の手順で処理されます:

public void writeString(String value) throws IOException {
    if (value == null) {
        writeNull();
        return;
    }
    
    int length = value.length();
    if (length <= MAX_DIRECT_STRING) {
        writeDirectString(value, length);
    } else {
        writeChunkedString(value, length);
    }
}

3.3 カスタムオブジェクトのシリアライズ

カスタムクラスのシリアライズでは、クラス定義の記録とインスタンスデータの書き込みが行われます:

public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
    if (out.addReference(obj)) return;
    
    Class<?> clazz = obj.getClass();
    int refId = out.startObject(clazz.getName());
    
    if (refId >= 0) {
        writeInstance(obj, out);
    } else {
        writeClassDefinition(out, clazz);
        writeInstance(obj, out);
    }
}
  1. デシリアライズの内部処理

デシリアライズは、入力ストリームから各データのタイプを判別し、適切な処理を実行します:

public Object readObject() throws IOException {
    int typeTag = readByte();
    
    switch (typeTag) {
        case 'S': return readString();
        case 'I': return readInt();
        case 'O': return readObjectInstance();
        case 'N': return null;
        default: throw new IOException("Unknown type: " + (char)typeTag);
    }
}

オブジェクトの復元では、クラス定義を読み込み、その後インスタンスを構築します:

private Object readObjectInstance() throws IOException {
    String className = readString();
    ObjectDefinition def = readObjectDefinition(className);
    
    Object instance = createInstance(def);
    readFieldValues(instance, def);
    return instance;
}

カスタムオブジェクトの復元では、クラス定義に基づいて各フィールドを順次復元し、最終的に完全なオブジェクトを構築します。

タグ: Hessian Java binary serialization Binary format

8月2日 09:08 投稿