Using the Geode PDX Autoserializer
It’s extremely easy for .NET applications to store and retrieve data from Geode. All that’s required
is a single line of code to set the PdxSerializer
to the .NET client’s ReflectionBasedAutoSerializer
:
cache.TypeRegistry.PdxSerializer = new ReflectionBasedAutoSerializer();
(The autoserializer can be registered only in the application code. It cannot be configured declaratively in cache.xml
.)
After an autoserializer has been registered, all user classes can automatically be stored without needing to implement any
interfaces. For example, the following Put
command stores value
, which is an instance of a user defined class, in
the region.
region.Put(key, value);
The .NET client’s ReflectionBasedAutoSerializer
supports the full list of .NET primitives and other common
built-in types.
Types without a no-arg constructor are not supported by the ReflectionBasedAutoSerializer
. This
includes all user defined structs. System.Data.Datatable
is an example of a system class that is not
supported due to lack of a no-arg constructor.
Java Interoperability with .NET Specific Types
Java does not have unsigned data types or exact equivalents of Guid
and Decimal
. Care should be
taken when passing these types between .NET and Java applications using the .NET
ReflectionBasedAutoSerializer
. For example, if storing UInt16
data (that is, 16-bit unsigned values),
be aware that values greater than UInt16.MaxValue/2 - 1
will show up as negative numbers in
Java. Using that data in a Java application may have unexpected behavior. If you expect to exceed
half the range for the given type (Byte.MaxValue/2
, UInt16.MaxValue/2
, UInt32.MaxValue/2
, or
UInt64.MaxValue/2
) you should use the next larger type. This obviously breaks down for
UInt64
, which has no next larger type. However, if your range exceeds UIn64.MaxValue/2
, you likely
have a much more complex set of issues to deal with, such as heavy paging due to such a large data
set.
Remote Queries of .NET Only Types
At this time the .NET Client does not support queries against user classes that have been stored on
the server using the ReflectionBasedAutoSerializer
.
When you register the reflection-based serializer, Geode uses it to serialize all
objects that do not implement IPdxSerializable
. You can customize the
auto-serialization behavior for your domain objects by adding serialization attributes to your
object’s fields.
Extending the PDX Autoserializer
For each object you intend to have autoserialized, you can customize the serialization as needed.
Note: If you also use PDX serialization in Java for the object, customize your serialization in the same way for both languages.
The following extension methods apply to autoserialization:
- WriteTransform. Controls what field value is written during auto serialization.
- ReadTransform. Controls what field value is read during auto deserialization.
- GetFieldType. Defines the specific field names that will be generated during autoserialization.
- IsIdentityField. 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.
- IsFieldIncluded. Specifies which fields of a class to autoserialize.
To specify an identifier field in your domain object, add the attribute PdxIdentityField
to the field.
For example:
[PdxIdentityField] private int id;
To exclude a field from serialization, add the .NET attribute NonSerialized
to the field.
For example:
[NonSerialized] private int myLocalData;
For each domain class Geode serializes using the autoserializer, all fields are
considered for serialization except those defined as static
, literal
or readonly
and those you
explicitly exclude using the .NET NonSerialized
attribute.
This example code demonstrates how to extend the autoserializer to customize serialization.
public class AutoSerializerEx : ReflectionBasedAutoSerializer
{
public override object WriteTransform(FieldInfo fi, Type type, object originalValue) {
if (fi.FieldType.Equals(Type.GetType("System.Guid"))) {
return originalValue.ToString();
} else if (fi.FieldType.Equals(Type.GetType("System.Decimal"))) {
return originalValue.ToString();
} else
return base.WriteTransform(fi, type, originalValue);
}
public override object ReadTransform(FieldInfo fi, Type type, object serializeValue) {
if (fi.FieldType.Equals(Type.GetType("System.Guid"))) {
Guid g = new Guid((string)serializeValue);
return g;
} else if (fi.FieldType.Equals(Type.GetType("System.Decimal"))) {
return Convert.ToDecimal((string)serializeValue);
} else
return base.ReadTransform(fi, type, serializeValue);
}
public override FieldType GetFieldType(FieldInfo fi, Type type) {
if (fi.FieldType.Equals(Type.GetType("System.Guid")) ||
fi.FieldType.Equals(Type.GetType("System.Decimal")))
return FieldType.STRING;
return base.GetFieldType(fi, type);
}
public override bool IsIdentityField(FieldInfo fi, Type type) {
if (fi.Name == "_identityField")
return true;
return base.IsIdentityField(fi, type);
}
public override string GetFieldName(FieldInfo fi, Type type) {
if (fi.Name == "_nameChange")
return fi.Name + "NewName";
return fi.Name;
}
public override bool IsFieldIncluded(FieldInfo fi, Type type)
{
if (fi.Name == "_notInclude")
return false;
return base.IsFieldIncluded(fi, type);
}
}