Chapter 7. Marshalling Java Objects

Marshalling converts Java objects into binary format so they can be transferred over the wire or stored to disk. The reverse process, unmarshalling, transforms data from binary format into Java objects.

Data Grid performs marshalling and unmarshalling to:

  • Send data to other Data Grid nodes in a cluster.
  • Store data in persistent cache stores.
  • Store data in binary format to provide lazy deserialization capabilities.
Note

Data Grid handles marshalling for all internal types. You need to configure marshalling only for the Java objects that you want to store.

Data Grid uses ProtoStream as the default for marshalling Java objects to binary format. Data Grid also provides other Marshaller implementations you can use.

7.1. Using the ProtoStream Marshaller

Data Grid integrates with the ProtoStream API to encode and decode Java objects into Protocol Buffers (Protobuf); a language-neutral, backwards compatible format.

Procedure

  1. Create implementations of the ProtoStream SerializationContextInitializer interface so that Data Grid can marshall your Java objects.
  2. Configure Data Grid to use the implementations.

    • Programmatically:

      GlobalConfigurationBuilder builder = new GlobalConfigurationBuilder();
      builder.serialization()
             .addContextInitializers(new LibraryInitializerImpl(), new SCIImpl());
    • Declaratively

      <serialization>
          <context-initializer class="org.infinispan.example.LibraryInitializerImpl"/>
          <context-initializer class="org.infinispan.example.another.SCIImpl"/>
      </serialization>

7.2. Using JBoss Marshalling

JBoss Marshalling is a serialization-based marshalling library and was the default marshaller in previous Data Grid versions.

Note
  • You should not use serialization-based marshalling with Data Grid. Instead you should use Protostream, which is a high-performance binary wire format that ensures backwards compatibility.
  • JBoss Marshalling and the AdvancedExternalizer interface are deprecated and will be removed in a future release. However, Data Grid ignores AdvancedExternalizer implementations when persisting data unless you use JBoss Marshalling.

Procedure

  1. Add the infinispan-jboss-marshalling dependency to your classpath.
  2. Configure Data Grid to use the JBossUserMarshaller.

    • Programmatically:

      GlobalConfigurationBuilder builder = new GlobalConfigurationBuilder();
      builder.serialization().marshaller(new JBossUserMarshaller());
    • Declaratively:

      <serialization marshaller="org.infinispan.jboss.marshalling.core.JBossUserMarshaller"/>

7.3. Using Java Serialization

You can use Java serialization with Data Grid to marshall your objects, but only if your Java objects implement Java’s Serializable interface.

Procedure

  1. Configure Data Grid to use JavaSerializationMarshaller as the marshaller.
  2. Add your Java classes to the deserialization white list.

    • Programmatically:

      GlobalConfigurationBuilder builder = new GlobalConfigurationBuilder();
      builder.serialization()
             .marshaller(new JavaSerializationMarshaller())
             .whiteList()
             .addRegexps("org.infinispan.example.", "org.infinispan.concrete.SomeClass");
    • Declaratively:

      <serialization marshaller="org.infinispan.commons.marshall.JavaSerializationMarshaller">
          <white-list>
              <class>org.infinispan.concrete.SomeClass</class>
              <regex>org.infinispan.example.*</regex>
          </white-list>
      </serialization>

7.4. Using the Kryo Marshaller

Data Grid provides a marshalling implementation that uses Kryo libraries.

Prerequisites for Data Grid Servers

To use Kryo marshalling with Data Grid servers, add a JAR that includes the runtime class files for the Kryo marshalling implementation as follows:

  1. Copy infinispan-marshaller-kryo-bundle.jar from the Data Grid Maven repository.
  2. Add the JAR file to the server/lib directory in your Data Grid server installation directory.

Prerequisites for Data Grid Library Mode

To use Kryo marshalling with Data Grid as an embedded library in your application, do the following:

  1. Add the infinispan-marshaller-kryo dependency to your pom.xml.

    <dependency>
      <groupId>org.infinispan</groupId>
      <artifactId>infinispan-marshaller-kryo</artifactId>
      <version>${version.infinispan}</version>
    </dependency>
  2. Specify the org.infinispan.marshaller.kryo.KryoMarshaller class as the marshaller.

    GlobalConfigurationBuilder builder = new GlobalConfigurationBuilder();
    builder.serialization()
           .marshaller(new org.infinispan.marshaller.kryo.KryoMarshaller());

Procedure

  1. Implement a service provider for the SerializerRegistryService.java interface.
  2. Place all serializer registrations in the register(Kryo) method; where serializers are registered with the supplied Kryo object using the Kryo API, for example:

    kryo.register(ExampleObject.class, new ExampleObjectSerializer())
  3. Specify the full path of implementing classes in your deployment JAR file within:

    META-INF/services/org/infinispan/marshaller/kryo/SerializerRegistryService

Reference

7.5. Using the Protostuff Marshaller

Data Grid provides a marshalling implementation that uses Protostuff libraries.

Prerequisites for Data Grid Servers

To use Protostuff marshalling with Data Grid servers, add a JAR that includes the runtime class files for the Protostuff marshalling implementation as follows:

  1. Copy infinispan-marshaller-protostuff-bundle.jar from the Data Grid Maven repository.
  2. Add the JAR file to the server/lib directory in your Data Grid server installation directory.

Prerequisites for Data Grid Library Mode

To use Protostuff marshalling with Data Grid as an embedded library in your application, do the following:

  1. Add the infinispan-marshaller-protostuff dependency to your pom.xml.

    <dependency>
      <groupId>org.infinispan</groupId>
      <artifactId>infinispan-marshaller-protostuff</artifactId>
      <version>${version.infinispan}</version>
    </dependency>
  2. Specify the org.infinispan.marshaller.protostuff.ProtostuffMarshaller class as the marshaller.

    GlobalConfigurationBuilder builder = new GlobalConfigurationBuilder();
    builder.serialization()
           .marshaller(new org.infinispan.marshaller.protostuff.ProtostuffMarshaller());

Procedure

Do one of the following to register custom Protostuff schemas for object marshalling:

  • Call the register() method.

    RuntimeSchema.register(ExampleObject.class, new ExampleObjectSchema());
  • Implement a service provider for the SerializerRegistryService.java interface that places all schema registrations in the register() method.

    You should then specify the full path of implementing classes in your deployment JAR file within:

    META-INF/services/org/infinispan/marshaller/protostuff/SchemaRegistryService

7.6. Using Custom Marshallers

Data Grid provides a Marshaller interface for custom marshallers.

Programmatic procedure

GlobalConfigurationBuilder builder = new GlobalConfigurationBuilder();
builder.serialization()
      .marshaller(new org.infinispan.example.marshall.CustomMarshaller())
      .whiteList().addRegexp("org.infinispan.example.*");

Declarative procedure

<serialization marshaller="org.infinispan.example.marshall.CustomMarshaller">
    <white-list>
        <class>org.infinispan.concrete.SomeClass</class>
        <regex>org.infinispan.example.*</regex>
    </white-list>
</serialization>

Tip

Custom marshaller implementations can access a configured white list via the initialize() method, which is called during startup.

7.7. Adding Java Classes to Deserialization White Lists

Data Grid does not allow deserialization of arbritrary Java classes for security reasons, which applies to JSON, XML, and marshalled byte[] content.

You must add Java classes to a deserialization white list, either using system properties or specifying them in the Data Grid configuration.

System properties

// Specify a comma-separated list of fully qualified class names
-Dinfinispan.deserialization.whitelist.classes=java.time.Instant,com.myclass.Entity

// Specify a regular expression to match classes
-Dinfinispan.deserialization.whitelist.regexps=.*

Declarative

<cache-container>
   <serialization version="1.0" marshaller="org.infinispan.marshall.TestObjectStreamMarshaller">
      <white-list>
         <class>org.infinispan.test.data.Person</class>
         <regex>org.infinispan.test.data.*</regex>
       </white-list>
   </serialization>
</cache-container>

Note

Java classes that you add to the deserialization whitelist apply to the Data Grid CacheContainer and can be deserialized by all caches that the CacheContainer controls.

7.8. Storing Deserialized Objects in Data Grid Servers

You can configure Data Grid to use the application/x-java-object MediaType as the format for your data. In other words, Data Grid stores your data as Plain Old Java Objects (POJOs) instead of binary content.

If you store POJOs, you must put class files for all custom objects on the Data Grid server classpath.

Procedure

  • Add JAR files that contain custom classes and/or service providers for marshaller implementations in the server/lib directory.
├── server
│   ├── lib
│   │   ├── UserObjects.jar
│       └── README.txt

7.9. Storing Data in Binary Format

Data Grid can store data in its serialized form, in binary format, and then either serialize or deserialize Java objects as needed. This behavior is also referred to as lazy deserialization.

Programmatic procedure

ConfigurationBuilder builder = ...
builder.memory().storageType(StorageType.BINARY);

Declarative procedure

<memory>
   <binary />
</memory>

Equality Considerations

When storing data in binary format, Data Grid uses the WrappedBytes interface for keys and values. This wrapper class transparently takes care of serialization and deserialization on demand, and internally may have a reference to the object itself being wrapped, or the serialized, byte array representation of the object. This has an effect on the behavior of equality, which is important to note if you implement an equals() methods on keys.

The equals() method of the wrapper class either compares binary representations (byte arrays) or delegates to the wrapped object instance’s equals() method, depending on whether both instances being compared are in serialized or deserialized form at the time of comparison. If one of the instances being compared is in one form and the other in another form, then one instance is either serialized or deserialized.