Apache Geode CHANGELOG

Extending the ReflectionBasedAutoSerializer

You can extend the ReflectionBasedAutoSerializer to handle serialization in a customized manner. This section provides an overview of the available method-based customization options and an example of extending the serializer to support BigDecimal and BigInteger types.

Reasons to Extend the ReflectionBasedAutoSerializer

One of the main use cases for extending the ReflectionBasedAutoSerializer is that you want it to handle an object that would currently need to be handled by standard Java serialization. There are several issues with having to use standard Java serialization that can be addressed by extending the PDX ReflectionBasedAutoSerializer.

  • Each time we transition from a Geode serialized object to an object that will be Java I/O serialized, extra data must get serialized. This can cause a great deal of serialization overhead. This is why it is worth extending the ReflectionBasedAutoSerializer to handle any classes that normally would have to be Java I/O serialized.
  • Expanding the number of classes that can use the ReflectionBasedAutoSerializer is beneficial when you encounter object graphs. After we use Java I/O serialization on an object, any objects under that object in the object graph will also have to be Java I/O serialized. This includes objects that normally would have been serialized using PDX or DataSerializable.
  • If standard Java I/O serialization is done on an object and you have enabled check-portability, then an exception will be thrown. Even if you are not concerned with the object’s portability, you can use this flag to find out what classes would use standard Java serialization (by getting an exception on them) and then enhancing your auto serializer to handle them.

Overriding ReflectionBasedAutoSerializer Behavior

You can customize the specific behaviors in ReflectionBasedAutoSerializer by overriding the following methods:

  • isClassAutoSerialized customizes which classes to autoserialize.
  • isFieldIncluded specifies which fields of a class to autoserialize.
  • getFieldName defines the specific field names that will be generated during autoserialization.
  • isIdentifyField controls which field is marked as the identity field. Identity fields are used when a PdxInstance computes its hash code to determine whether it is equal to another object.
  • getFieldType determines the field type that will be used when autoserializing the given field.
  • transformFieldValue controls whether specific field values of a PDX object can be transformed during serialization.
  • writeTransform controls what field value is written during auto serialization.
  • readTransform controls what field value is read during auto deserialization.

These methods are only called the first time the ReflectionBasedAutoSerializer sees a new class. The results will be remembered and used the next time the same class is seen.

For details on these methods and their default behaviors, see the JavaDocs on ReflectionBasedAutoSerializer for details.

Example of Optimizing Autoserialization of BigInteger and BigDecimal Types

This section provides an example of extending the ReflectionBasedAutoSerializer to optimize the automatic serialization of BigInteger and BigDecimal types.

The following code sample illustrates a subclass of the ReflectionBasedAutoSerializer that optimizes BigInteger and BigDecimal autoserialization:

public static class BigAutoSerializer extends ReflectionBasedAutoSerializer {
   public BigAutoSerializer(Boolean checkPortability, string… patterns) {
    super(checkPortability, patterns);
}

@Override
public FieldType get FieldType(Field f, Class<?> clazz) {
   if (f.getType().equals(BigInteger.class)) {
        return FieldType.BYTE_ARRAY; 
      } else if (f.getType().equals(BigDecimal.class)) {
        return FieldType.STRING; 
      } else {
        return super.getFieldType(f, clazz);
      }
    }
@Override
    public boolean transformFieldValue(Field f, Class<?> clazz) {
      if (f.getType().equals(BigInteger.class)) {
        return true;
      } else if (f.getType().equals(BigDecimal.class)) {
        return true;
      } else {
        return super.transformFieldValue(f, clazz);
      }
    }

@Override
    public Object writeTransform(Field f, Class<?> clazz, Object originalValue) {
      if (f.getType().equals(BigInteger.class)) {
        byte[] result = null;
        if (originalValue != null) {
          BigInteger bi = (BigInteger)originalValue;
          result = bi.toByteArray();
        }
        return result;
      } else if (f.getType().equals(BigDecimal.class)) {
        Object result = null;
        if (originalValue != null) {
          BigDecimal bd = (BigDecimal)originalValue;
          result = bd.toString();
        }
        return result;
      } else {
        return super.writeTransform(f, clazz, originalValue);
      }
    }

@Override
    public Object readTransform(Field f, Class<?> clazz, Object serializedValue) {
      if (f.getType().equals(BigInteger.class)) {
        BigInteger result = null;
        if (serializedValue != null) {
          result = new BigInteger((byte[])serializedValue);
        }
        return result;
      } else if (f.getType().equals(BigDecimal.class)) {
        BigDecimal result = null;
        if (serializedValue != null) {
          result = new BigDecimal((String)serializedValue);
        }
        return result;
      } else {
        return super.readTransform(f, clazz, serializedValue);
      }
    }

  }