Apache Geode CHANGELOG

Serializing Your Domain Object with a PdxSerializer

For a domain object that you cannot or do not want to modify, use the PdxSerializer class to serialize and deserialize the object’s fields. You use one PdxSerializer implementation for the entire cache, programming it for all of the domain objects that you handle in this way.

With PdxSerializer, you leave your domain object as-is and handle the serialization and deserialization in the separate serializer. You register the serializer in your cache PDX configuration. Program the serializer to handle all of the domain objects you need.

If you write your own PdxSerializer and you also use the ReflectionBasedAutoSerializer, then the PdxSerializer needs to own the ReflectionBasedAutoSerializer and delegate to it. A Cache can only have a single PdxSerializer instance.

Note: The PdxSerializer toData and fromData methods differ from those for PdxSerializable. They have different parameters and results.

Procedure

  1. In the domain classes that you wish to PDX serialize, make sure each class has a zero-arg constructor. For example:

    public PortfolioPdx(){}
    
  2. If you have not already implemented PdxSerializer for some other domain object, perform these steps:

    1. Create a new class as your cache-wide serializer and make it implement PdxSerializer. If you want to declare your new class in the cache.xml file, have it also implement Declarable.

      Example:

      import org.apache.geode.cache.Declarable;
      import org.apache.geode.pdx.PdxReader;
      import org.apache.geode.pdx.PdxSerializer;
      import org.apache.geode.pdx.PdxWriter;
      
      public class ExamplePdxSerializer implements PdxSerializer, Declarable {
      ...
      
    2. In your cache PDX configuration, register the serializer class in the cache’s <pdx> <pdx-serializer> <class-name> attribute.

      Example:

      // Configuration setting PDX serializer for the cache
      <cache>
        <pdx>
          <pdx-serializer>
           <class-name>com.company.ExamplePdxSerializer</class-name>
          </pdx-serializer>
        </pdx> 
        ...
      </cache>
      

      Or use the CacheFactory.setPdxSerializer API.

      Cache c = new CacheFactory
         .setPdxSerializer(new ExamplePdxSerializer())
         .create();
      

    Note: You cannot specify a custom pdx-serializer class using gfsh, however the configure pdx command automatically configures the org.apache.geode.pdx.ReflectionBasedAutoSerializer class. See configure pdx.

  3. Program PdxSerializer.toData to recognize, cast, and handle your domain object:

    1. Write each standard Java data field of your domain class using the PdxWriter write methods.
    2. Call the PdxWriter markIdentityField method for each field you want to have Geode use to identify your object. Put this after the field’s write method. Geode uses this information to compare objects for operations like distinct queries. If you do not set as least one identity field, then the equals and hashCode methods will use all PDX fields to compare objects and consequently, will not perform as well. It is important that the fields used by your equals and hashCode implementations are the same fields that you mark as identity fields.
    3. For a particular version of your class, you need to consistently write the same named field each time. The field names or number of fields must not change from one instance to another for the same class version.
    4. For best performance, do fixed width fields first and then variable length fields.
    5. If desired, you can check the portability of the object before serializing it by adding the checkPortability parameter when using thePdxWriter writeObject, writeObjectArray, and writeField methods.

    Example toData code:

    public boolean toData(Object o, PdxWriter writer)
      {
        if(!(o instanceof PortfolioPdx)) {
          return false;
        }
    
        PortfolioPdx instance = (PortfolioPdx) o;
        writer.writeInt("id", instance.id)
        //identity field
        .markIdentityField("id")
        .writeDate("creationDate", instance.creationDate)
        .writeString("pkid", instance.pkid)
        .writeObject("positions", instance.positions)
        .writeString("type", instance.type)
        .writeString("status", instance.status)
        .writeStringArray("names", instance.names)
        .writeByteArray("newVal", instance.newVal)
    
        return true;
      }
    
    1. Program PdxSerializer.fromData to create an instance of your class, read your data fields from the serialized form into the object’s fields using the PdxReader read methods, and return the created object.

      Provide the same names that you did in toData and call the read operations in the same order as you called the write operations in your toData implementation.

      Geode provides the domain class type and PdxReader to the fromData method.

      Example fromData code:

        public Object fromData(Class<?> clazz, PdxReader reader)
        {
          if(!clazz.equals(PortfolioPdx.class)) {
            return null;
          }
      
          PortfolioPdx instance = new PortfolioPdx();
          instance.id = reader.readInt("id");
          instance.creationDate = reader.readDate("creationDate");
          instance.pkid = reader.readString("pkid");
          instance.positions = (Map<String, PositionPdx>)reader.readObject("positions");
          instance.type = reader.readString("type");
          instance.status = reader.readString("status");
          instance.names = reader.readStringArray("names");
          instance.newVal = reader.readByteArray("newVal");
      
          return instance;
        }
      
  4. If desired, you can also enable extra validation in your use of PdxWriter. You can set this by setting the system property gemfire.validatePdxWriters to true. Note that you should only set this option if you are debugging new code as this option can decrease system performance.