CLOVER🍀

That was when it all began.

Infinispan 10.0でMarshallingがリファクタリングされたという話(Embedded Mode)

これは、なにをしたくて書いたもの?

Infinispan 10.0.0.Finalがリリースされたということで。
※その後、すぐに10.0.1.Finalがリリースされましたが…

Blog: Infinispan 10.0.0.Final - Infinispan

Blog: Infinispan 10.0.1.Final - Infinispan

Infinispanは10.0で大きく変わったようなので、気になるところをちょっとずつ見ていこうかなと思っています。

今回は、Marshallingまわりを。

Marshalling

Infinispan 10.0で、Marshallingが大きくリファクタリングされたようです。

Blog: Infinispan 10.0.0.Final - Infinispan

Marshalling
The internal marshalling capabilities of Infinispan have undergone a significant refactoring in 10.0. The marshalling of internal Infinispan objects and user objects are now truly isolated. This means that it’s now possible to configure Marshaller implementations in embedded mode or on the server, without having to handle the marshalling of Infinispan internal classes. Consequently, it’s possible to easily change the marshaller implementation user for user types, in a similar manner to how users of the HotRod client are accustomed.

As a consequence of the above changes, the default marshaller used for marshalling user types is no longer based upon JBoss Marshalling. Instead we now utilise the ProtoStream library to store user types in the language agnostic Protocol Buffers format. The ProtoStream library provides several advantages over jboss-marshalling, most notably it does not make use of reflection and so is more suitable for use in AOT environments such as Quarkus.

ざっくり、以下のような感じです。

  • Infinispanの内部クラスと、ユーザーオブジェクトのMarshallingの分離
  • Embedded ModeとClient/Server ModeでのMarshallerの共通化が可能に
    • これまでは、Embedded ModeではExternalizer、AdvancedExternalizerを使っていた
  • デフォルトのMarshallingライブラリの変更(JBoss Marshalling → ProtoStream(Protocol Buffers))

Protocol Bufferesにしたのは、リフレクションを使わないことでQuarkusなどのネイティブイメージを使う環境下でもより扱いやすくなることを
狙っているようです。

今回、Embedded Modeでこのあたりを確認してみます。ユーザー定義のクラスを、Cacheに登録/取得してみましょう。

環境

今回の環境は、こちらです。

$ java -version
openjdk version "11.0.4" 2019-07-16
OpenJDK Runtime Environment (build 11.0.4+11-post-Ubuntu-1ubuntu218.04.3)
OpenJDK 64-Bit Server VM (build 11.0.4+11-post-Ubuntu-1ubuntu218.04.3, mixed mode, sharing)


$ mvn -version
Apache Maven 3.6.2 (40f52333136460af0dc0d7232c0dc0bcf0d9e117; 2019-08-28T00:06:16+09:00)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 11.0.4, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "4.15.0-66-generic", arch: "amd64", family: "unix"

利用するInfinispanのバージョンは、10.0.1.Finalとします。

準備

Maven依存関係。

        <dependency>
            <groupId>org.infinispan</groupId>
            <artifactId>infinispan-core</artifactId>
            <version>10.0.1.Final</version>
        </dependency>

実は、これだけでは今回のお題では不完全なのですが。

あとは、テストコードで確認したいので、JUnit 5とAssertJも入れておきます。

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.5.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.5.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <version>3.14.0</version>
            <scope>test</scope>
        </dependency>

   <!-- 省略 -->

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
            </plugin>
        </plugins>
    </build>

テストコードの雛形

それでは、テストコードの雛形を、以下のように作成します。
src/test/java/org/littlewings/infinispan/marshalling/MarshallingTest.java

package org.littlewings.infinispan.marshalling;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import org.infinispan.Cache;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.manager.EmbeddedCacheManager;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class MarshallingTest {
    public <K, V> void withCache(String cacheName, int numInstances, Consumer<Cache<K, V>> func) {
        List<EmbeddedCacheManager> cacheManagers =
                IntStream
                        .rangeClosed(1, numInstances)
                        .mapToObj(i -> {
                            try {
                                return new DefaultCacheManager("infinispan.xml");
                            } catch (IOException e) {
                                throw new UncheckedIOException(e);
                            }
                        })
                        .collect(Collectors.toList());

        cacheManagers.forEach(m -> m.getCache(cacheName));

        try {
            Cache<K, V> cache = cacheManagers.get(0).getCache(cacheName);
            func.accept(cache);
            cache.stop();
        } finally {
            cacheManagers.forEach(EmbeddedCacheManager::stop);
        }
    }

    // ここに、テストを書く!
}

任意の数のCacheManagerを作成して、クラスタを構成できるようにします。

Infinispanの設定ファイルは、まずはこんな形で用意しました。
src/test/resources/infinispan.xml

<?xml version="1.0" encoding="UTF-8"?>
<infinispan
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="urn:infinispan:config:10.0 http://www.infinispan.org/schemas/infinispan-config-10.0.xsd"
        xmlns="urn:infinispan:config:10.0">

    <cache-container shutdown-hook="REGISTER">
        <transport stack="udp"/>

        <local-cache name="localCache"/>

        <distributed-cache name="distributedCache">
    </cache-container>

</infinispan>

デフォルトのUDPスタックでクラスタが組めるようにして、Local CacheとDistributed Cacheをそれぞれ定義しています。

Stringで確認してみる

最初に、ユーザー定義のクラスなんて難しいことは言わず、基本的な型で試してみましょう。

クラスタのNode数1で、Local CacheとDistributed Cacheで確認。

    @Test
    public void simplyClassLocalCache() {
        this.<String, String>withCache("localCache", 1, cache -> {
            cache.put("key1", "value1");
            cache.put("key2", "value2");
            cache.put("key3", "value3");

            assertThat(cache.get("key1")).isEqualTo("value1");
            assertThat(cache.get("key2")).isEqualTo("value2");
            assertThat(cache.get("key3")).isEqualTo("value3");
        });
    }

    @Test
    public void simplyClassDistributedCache() {
        this.<String, String>withCache("distributedCache", 1, cache -> {
            cache.put("key1", "value1");
            cache.put("key2", "value2");
            cache.put("key3", "value3");

            assertThat(cache.get("key1")).isEqualTo("value1");
            assertThat(cache.get("key2")).isEqualTo("value2");
            assertThat(cache.get("key3")).isEqualTo("value3");
        });
    }

これは、問題なく動きます。

クラスタのNode数を3に増加。

    @Test
    public void simplyClassClusteredLocalCache() {
        this.<String, String>withCache("localCache", 3, cache -> {
            cache.put("key1", "value1");
            cache.put("key2", "value2");
            cache.put("key3", "value3");

            assertThat(cache.get("key1")).isEqualTo("value1");
            assertThat(cache.get("key2")).isEqualTo("value2");
            assertThat(cache.get("key3")).isEqualTo("value3");
        });
    }

    @Test
    public void simplyClassClusteredDistributedCache() {
        this.<String, String>withCache("distributedCache", 3, cache -> {
            cache.put("key1", "value1");
            cache.put("key2", "value2");
            cache.put("key3", "value3");

            assertThat(cache.get("key1")).isEqualTo("value1");
            assertThat(cache.get("key2")).isEqualTo("value2");
            assertThat(cache.get("key3")).isEqualTo("value3");
        });
    }

これも、問題なく動きます。

ユーザー定義クラスを使う

では、ユーザー定義のクラスを使ってみましょう。

書籍をお題にします。
src/test/java/org/littlewings/infinispan/marshalling/Book.java

package org.littlewings.infinispan.marshalling;

public class Book {
    String isbn;

    String title;

    int price;

    //@ProtoFactory
    public static Book create(String isbn, String title, int price) {
        Book book = new Book();

        book.setIsbn(isbn);
        book.setTitle(title);
        book.setPrice(price);

        return book;
    }

    // getter/setterは省略
}

Serializableにしていないところにやや意図的なところもありますが、こちらに対してLocal Cacheの時と同様のバリエーションを実行します。

クラスタのNode数が1で、Local CacheとDistributed Cache。

    @Test
    public void userDefinedClassLocalCache() {
        this.<String, Book>withCache("localCache", 1, cache -> {
            List<Book> books =
                    Arrays
                            .asList(
                                    Book.create("978-1782169970", "Infinispan Data Grid Platform Definitive Guide", 5337),
                                    Book.create("978-1785285332", "Getting Started With Hazelcast - Second Edition", 3848),
                                    Book.create("978-1783988181", "Mastering Redis", 6172)
                            );

            books.forEach(b -> cache.put(b.getIsbn(), b));

            assertThat(cache.get("978-1782169970").getTitle()).isEqualTo("Infinispan Data Grid Platform Definitive Guide");
            assertThat(cache.get("978-1785285332").getTitle()).isEqualTo("Getting Started With Hazelcast - Second Edition");
            assertThat(cache.get("978-1783988181").getTitle()).isEqualTo("Mastering Redis");
        });
    }

    @Test
    public void userDefinedClassDistributedCache() {
        this.<String, Book>withCache("distributedCache", 1, cache -> {
            List<Book> books =
                    Arrays
                            .asList(
                                    Book.create("978-1782169970", "Infinispan Data Grid Platform Definitive Guide", 5337),
                                    Book.create("978-1785285332", "Getting Started With Hazelcast - Second Edition", 3848),
                                    Book.create("978-1783988181", "Mastering Redis", 6172)
                            );

            books.forEach(b -> cache.put(b.getIsbn(), b));

            assertThat(cache.get("978-1782169970").getTitle()).isEqualTo("Infinispan Data Grid Platform Definitive Guide");
            assertThat(cache.get("978-1785285332").getTitle()).isEqualTo("Getting Started With Hazelcast - Second Edition");
            assertThat(cache.get("978-1783988181").getTitle()).isEqualTo("Mastering Redis");
        });
    }

こちらは、動作します。

クラスタのNode数を3にして、Local Cache。

    @Test
    public void userDefinedClassClusteredLocalCache() {
        this.<String, Book>withCache("localCache", 3, cache -> {
            List<Book> books =
                    Arrays
                            .asList(
                                    Book.create("978-1782169970", "Infinispan Data Grid Platform Definitive Guide", 5337),
                                    Book.create("978-1785285332", "Getting Started With Hazelcast - Second Edition", 3848),
                                    Book.create("978-1783988181", "Mastering Redis", 6172)
                            );

            books.forEach(b -> cache.put(b.getIsbn(), b));

            assertThat(cache.get("978-1782169970").getTitle()).isEqualTo("Infinispan Data Grid Platform Definitive Guide");
            assertThat(cache.get("978-1785285332").getTitle()).isEqualTo("Getting Started With Hazelcast - Second Edition");
            assertThat(cache.get("978-1783988181").getTitle()).isEqualTo("Mastering Redis");
        });
    }

まあ、あまり意味はないですが、こちらはうまくいきます。

クラスタのNode数を3にして、Distributed Cache。

    @Test
    public void userDefinedClassClusteredDistributedCache() {
        this.<String, Book>withCache("distributedCache", 3, cache -> {
            List<Book> books =
                    Arrays
                            .asList(
                                    Book.create("978-1782169970", "Infinispan Data Grid Platform Definitive Guide", 5337),
                                    Book.create("978-1785285332", "Getting Started With Hazelcast - Second Edition", 3848),
                                    Book.create("978-1783988181", "Mastering Redis", 6172)
                            );

            books.forEach(b -> cache.put(b.getIsbn(), b));

            assertThat(cache.get("978-1782169970").getTitle()).isEqualTo("Infinispan Data Grid Platform Definitive Guide");
            assertThat(cache.get("978-1785285332").getTitle()).isEqualTo("Getting Started With Hazelcast - Second Edition");
            assertThat(cache.get("978-1783988181").getTitle()).isEqualTo("Mastering Redis");
        });
    }

これは、失敗します。

WARN: ISPN000559: Cannot marshall 'class org.littlewings.infinispan.marshalling.Book'
java.lang.IllegalArgumentException: No marshaller registered for Java type org.littlewings.infinispan.marshalling.Book
    at org.infinispan.protostream.impl.SerializationContextImpl.getMarshallerDelegate(SerializationContextImpl.java:279)
    at org.infinispan.protostream.WrappedMessage.writeMessage(WrappedMessage.java:240)
    at org.infinispan.protostream.ProtobufUtil.toWrappedStream(ProtobufUtil.java:196)
    at org.infinispan.marshall.persistence.impl.PersistenceMarshallerImpl.objectToBuffer(PersistenceMarshallerImpl.java:157)
    at org.infinispan.marshall.persistence.impl.PersistenceMarshallerImpl.objectToByteBuffer(PersistenceMarshallerImpl.java:137)
    at org.infinispan.marshall.persistence.impl.PersistenceMarshallerImpl.objectToByteBuffer(PersistenceMarshallerImpl.java:145)
    at org.infinispan.marshall.core.GlobalMarshaller.writeRawUnknown(GlobalMarshaller.java:638)
    at org.infinispan.marshall.core.GlobalMarshaller.writeUnknown(GlobalMarshaller.java:627)
    at org.infinispan.marshall.core.GlobalMarshaller.writeUnknown(GlobalMarshaller.java:618)
    at org.infinispan.marshall.core.GlobalMarshaller.writeNonNullableObject(GlobalMarshaller.java:384)
    at org.infinispan.marshall.core.GlobalMarshaller.writeNullableObject(GlobalMarshaller.java:352)
    at org.infinispan.marshall.core.BytesObjectOutput.writeObject(BytesObjectOutput.java:26)
    at org.infinispan.commands.write.PutKeyValueCommand.writeTo(PutKeyValueCommand.java:81)
    at org.infinispan.marshall.exts.ReplicableCommandExternalizer.writeCommandParameters(ReplicableCommandExternalizer.java:70)
    at org.infinispan.marshall.exts.ReplicableCommandExternalizer.writeObject(ReplicableCommandExternalizer.java:66)
    at org.infinispan.marshall.exts.ReplicableCommandExternalizer.writeObject(ReplicableCommandExternalizer.java:54)
    at org.infinispan.marshall.core.GlobalMarshaller.writeInternal(GlobalMarshaller.java:656)
    at org.infinispan.marshall.core.GlobalMarshaller.writeNonNullableObject(GlobalMarshaller.java:371)
    at org.infinispan.marshall.core.GlobalMarshaller.writeNullableObject(GlobalMarshaller.java:352)
    at org.infinispan.marshall.core.BytesObjectOutput.writeObject(BytesObjectOutput.java:26)
    at org.infinispan.commands.remote.SingleRpcCommand.writeTo(SingleRpcCommand.java:52)
    at org.infinispan.marshall.exts.ReplicableCommandExternalizer.writeCommandParameters(ReplicableCommandExternalizer.java:70)
    at org.infinispan.marshall.exts.CacheRpcCommandExternalizer.marshallParameters(CacheRpcCommandExternalizer.java:120)
    at org.infinispan.marshall.exts.CacheRpcCommandExternalizer.writeObject(CacheRpcCommandExternalizer.java:116)
    at org.infinispan.marshall.exts.CacheRpcCommandExternalizer.writeObject(CacheRpcCommandExternalizer.java:66)
    at org.infinispan.marshall.core.GlobalMarshaller.writeInternal(GlobalMarshaller.java:656)
    at org.infinispan.marshall.core.GlobalMarshaller.writeNonNullableObject(GlobalMarshaller.java:371)
    at org.infinispan.marshall.core.GlobalMarshaller.writeNullableObject(GlobalMarshaller.java:352)
    at org.infinispan.marshall.core.GlobalMarshaller.writeObjectOutput(GlobalMarshaller.java:181)
    at org.infinispan.marshall.core.GlobalMarshaller.writeObjectOutput(GlobalMarshaller.java:174)
    at org.infinispan.marshall.core.GlobalMarshaller.objectToBuffer(GlobalMarshaller.java:302)

        〜省略〜

作成したクラスに対するMarshallerがない、と言われています。

java.lang.IllegalArgumentException: No marshaller registered for Java type org.littlewings.infinispan.marshalling.Book

ちなみに、この設定だとDistributed CacheでNodeが複数にならないとMarshallingが実行されないだけであって、たとえば
以下のように必ずMarshallingが行われるようにすると、ユーザー定義のクラスを扱ったテストはLocal Cache、Distributed Cacheを
問わず失敗するようになります。

        <local-cache name="localCache">
            <memory>
                <binary size="-1"/>
            </memory>
        </local-cache>

        <distributed-cache name="distributedCache">
            <memory>
                <binary size="-1"/>
            </memory>
        </distributed-cache>

本当に、JBoss Marshallingが使われなくなったんですね。

さて、どうしましょう。

Marshallingのドキュメントを読む

ここで、Marshallingのドキュメントをちゃんと読み直してみます。

Marshalling

ProtoStreamがデフォルトだと言っています。

ProtoStream (Default)

プリミティブなどの一部のクラスは、Marshallingが可能なようです。

Usage

先ほどのStringの例で、Distributed Cacheを使っても失敗しなかったのは、これが理由ですね。

プリミティブまわりだと、このあたり。

https://github.com/infinispan/infinispan/blob/10.0.1.Final/core/src/main/java/org/infinispan/marshall/core/Primitives.java#L43-L65

さて、ドキュメントに従うと、ユーザー定義のクラスにアノテーションを付与して、Protocol BuffersのIDLやMarshallerを自動生成
するようにして、SerializationContextInitializerとして登録します。

Generating SerializationContextInitializers

まず、pom.xmlに以下を追加。

        <dependency>
            <groupId>org.infinispan.protostream</groupId>
            <artifactId>protostream-processor</artifactId>
            <version>4.3.0.Final</version>
            <optional>true</optional>
        </dependency>

ビルド時での、アノテーションからの自動生成に使うだけなので、optional trueでよいでしょう。

続いて、Bookクラスに@ProtoFieldアノテーションを付与して、Protocol Buffersとしてのフィールド定義を行います。
src/test/java/org/littlewings/infinispan/marshalling/Book.java

package org.littlewings.infinispan.marshalling;

import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;

public class Book {
    @ProtoField(number = 1, required = true)
    String isbn;

    @ProtoField(number = 2, required = true)
    String title;

    @ProtoField(number = 3, required = true, defaultValue = "0")
    int price;

    @ProtoFactory
    public static Book create(String isbn, String title, int price) {
        Book book = new Book();

        book.setIsbn(isbn);
        book.setTitle(title);
        book.setPrice(price);

        return book;
    }

    // getter/setterは省略
}

@ProtoFactoryについては、必要に応じてファクトリメソッドやコンストラクタを指定してください。

なお、@ProtoFieldアノテーションには、staticフィールド、privateフィールドには付与できません。

https://github.com/infinispan/protostream/blob/4.3.0.Final/core/src/main/java/org/infinispan/protostream/annotations/impl/ProtoMessageTypeMetadata.java#L306-L317

さらに、SerializationContextInitializerインターフェースを継承したクラスを作成し、@AutoProtoSchemaBuilderアノテーションを付与して
protoファイルの自動生成の設定を行います。
src/test/java/org/littlewings/infinispan/marshalling/LibraryInitializer.java

package org.littlewings.infinispan.marshalling;

import org.infinispan.protostream.SerializationContextInitializer;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;

@AutoProtoSchemaBuilder(
        includeClasses = {
                Book.class
        },
        schemaFileName = "library.proto",
        schemaFilePath = "proto/",
        schemaPackageName = "book")
public interface LibraryInitializer extends SerializationContextInitializer {
}

@AutoProtoSchemaBuilderアノテーションには、Marshalling対象のクラスと、生成するProtocol BufferesのIDLファイルの情報を
設定します。

これで、ビルド時にprotoファイルとMarshaller、作成したSerializationContextInitializerのサブインターフェースの実装クラスが
生成されます。

$ find target/test-classes target/generated-test-sources -type f
target/test-classes/proto/library.proto
target/test-classes/infinispan.xml
target/test-classes/org/littlewings/infinispan/marshalling/LibraryInitializerImpl.class
target/test-classes/org/littlewings/infinispan/marshalling/MarshallingTest.class
target/test-classes/org/littlewings/infinispan/marshalling/LibraryInitializer.class
target/test-classes/org/littlewings/infinispan/marshalling/Book.class
target/test-classes/org/littlewings/infinispan/marshalling/Book$___Marshaller_f17d03721c1841044d5c821f6b06c39a80a6392a51f12f33aaaabb0dabbd74cc.class
target/generated-test-sources/test-annotations/org/littlewings/infinispan/marshalling/LibraryInitializerImpl.java
target/generated-test-sources/test-annotations/org/littlewings/infinispan/marshalling/Book$___Marshaller_f17d03721c1841044d5c821f6b06c39a80a6392a51f12f33aaaabb0dabbd74cc.java

生成されたprotoファイルは、こんな感じです。
target/test-classes/proto/library.proto

// File name: library.proto
// Generated from : org.littlewings.infinispan.marshalling.LibraryInitializer

syntax = "proto2";

package book;



message Book {
   
   required string isbn = 1;
   
   required string title = 2;
   
   required int32 price = 3 [default = 0];
}

生成されたファイルのパスや中身には、アノテーションの内容が反映されていますね。

@AutoProtoSchemaBuilder(
        includeClasses = {
                Book.class
        },
        schemaFileName = "library.proto",
        schemaFilePath = "proto/",
        schemaPackageName = "book")

...

    @ProtoField(number = 1, required = true)
    String isbn;

    @ProtoField(number = 2, required = true)
    String title;

    @ProtoField(number = 3, required = true, defaultValue = "0")
    int price;

自動生成されたSerializationContextInitializerインターフェースの実装は、こちらですね。Implという接尾語が付与されるようです。
今回、LibraryInitializerという名前で作成したので、LibraryInitializerImplですね。

target/test-classes/org/littlewings/infinispan/marshalling/LibraryInitializerImpl.class
target/generated-test-sources/test-annotations/org/littlewings/infinispan/marshalling/LibraryInitializerImpl.java

で、だいぶわかりづらいのですが、自動生成されたクラスを、serialization要素内に、context-initializerとして登録します。

    <cache-container shutdown-hook="REGISTER">
        <transport stack="udp"/>

        <serialization>
            <context-initializer class="org.littlewings.infinispan.marshalling.LibraryInitializerImpl"/>
        </serialization>

        <local-cache name="localCache"/>

        <distributed-cache name="distributedCache"/>
    </cache-container>

今回の場合、「LibraryInitializerImpl」というクラス名になりますね。

これで、今回のBookクラスに対するMarshallerが登録され、先ほどのコードがテストにパスするようになります。
強制的にMarshallingするようにしても大丈夫です。

ユーザー定義のクラスに対する、Marshallingできるようになりました、と。

今後は、こんな感じの使い方になるんですねぇ。

その他

オマケ的にいくつか。ドキュメントの紹介のみですが。

IDLおよびMarshallerの自動生成を行わない場合

今回はユーザー定義のクラスを作成し、ProtoStreamのアノテーションを付与しました。ですが、このように自分でソースコード
変更することができないようなクラスがMarshalling対象となる場合は、以下のようにprotoファイルやMarshallerを作成します。

Manually Implementing SerializationContextInitializers

まあ、先の例で自動生成していた部分を、自分でやります、と。

SerializationContextInitializerを実装したクラスも作成して、同じようにcontext-initializerとして登録すればよさそうです。

Java Serialization Marshaller

Javaシリアライズの仕組みをMarshallerとして使う場合。

Java Serialization Marshaller

JBoss Marshalling

以前の、Marshallingのデフォルト実装ですね。

JBoss Marshalling

こちらはinfinispan-coreから分離され、infinipsan-jboss-marshallingとなったので、使用する場合は別途依存関係を追加する必要があります。

ですが、JBoss Marshallingは非推奨となり、将来削除される予定みたいなのでもう使うことはないんだろうな、と。

JBoss Marshalling is deprecated and planned for removal in a future version of Infinispan.

また、AdvancedExternalizerもなくなりそうですね。

Infinispan ignores implementations of the AdvancedExternalizer interface when persisting data unless you configure JBoss marshalling. However, this interface is also deprecated and planned for removal.

Custom Marshaller

独自のMarshallerを使う場合。

Custom Implementation

Protocol Buffersでもなく、Javaシリアライズでもなく、独自のMarshallingを導入する場合に使うことになるかなと。

まとめ

Infinispan 10.0でリファクタリングされた、Marshallingについて、まずはEmbedded Modeで試してみました。

今後は、Protocol Buffersを利用するようになるんでしょうね。

ただ、Protocol Buffersのバージョンは2なので、そのうち3になることを…。Road Mapには、乗っているんですけどね。

SerializationContextInitializerの定義や設定への反映、protostream-processorの依存関係の追加など、やや戸惑うところがありましたが、
なんとか通せて良かったです。

今回作成したソースコードは、こちらに置いてあります。

https://github.com/kazuhira-r/infinispan-getting-started/tree/master/embedded-without-jboss-marshalling