The ObjectMismatchTrigger interface is
show in Example 8.1, “ObjectMismatchTrigger interface”.
Example 8.1. ObjectMismatchTrigger interface
public interface ObjectMismatchTrigger
{
public void writeObjectToStream(
ManagedObjectStreamClass remoteClassDescriptor,
ObjectOutputStream out) throws IOException;
public void readObjectFromStream(
ManagedObjectStreamClass remoteClassDescriptor,
ObjectInputStream in) throws IOException;
}It defines these methods:
These methods are only called on the node where the new class
version is installed. In all cases, the
remoteClassDescriptor parameter contains a description
of the old version of the class. For example, in Figure 8.1, “Object mismatch method invocation”, the
remoteClassDescriptor parameter always contains a
description of O1.
The ManagedObjectStreamClass provides
access to the remote serialVersionUID for a class
using the getSerialVersionUID() method. The version
information can be used to perform conditional mapping based on the
actual class version on a remote node. This makes it possible to support
multiple versions across a cluster. The
ObjectMismatchTrigger interface can use the version
information associated with the remote class to conditionally map the
differences.
![]() | |
If no |
When supporting multiple deployed versions of a class, the upgrade utility must be run against the new class version and the most current old version. Not doing this may cause unresolved version mismatches are runtime.
The ManagedObjectStreamClass contains
an ordered array of all fields, starting with the top most parent, to
the current child class where an
ObjectMismatchTrigger method is called. These fields
must be processed in order. This is done using the
ManagedObjectStreamClass.getFields() method.
The general approach to field mapping using the
ManagedObjectStreamClass class is to iterate over all
of the fields returned by the
ManagedObjectStreamClass and map them into the new
field definitions. The ManagedObjectStreamClass
always contains the field definitions for the old class version.
An alternative approach to field mapping is to use the
ObjectInputStream.GetField and
ObjectOutputStream.PutField classes. These classes
provide random access to fields by name. Again, the
ObjectInputStream.GetField and
ObjectOutputStream.PutField always contain the field
definitions for the old class version.
![]() | |
The use of the |
See the section called “Inheritance” for details on how
inheritance affects field processing. A field mapping example is shown
in Example 8.3, “Updated class definition”. This example shows
the use of both the ManagedObjectStreamClass and the
ObjectInputStream.GetField class.
Classes that extend other classes, must ensure that the parent class processes the object stream before the child. This can be done a couple of ways:
Use super to call the parent's
implementation of the ObjectMismatchTrigger
method. This will only work if the inheritance hierarchy hasn't
changed between the old and new class versions.
Directly set the parent's field values. This is the only
option if the inheritance hierarchy has changed between the old and
new class versions. This does imply that a child must have access to
all parent class fields either because they are
protected, or there are setters available.
When an ObjectMismatchTrigger method is
executed, the method always has complete access to any parent class
fields in the old class version.
ObjectMismatchTrigger methods are only called
on the leaf type of an inheritance hierarchy. They are not called on any
of the parent types.
Here is an example using a call to super to
populate a parent's fields:
//
// Both old and new class versions extend Base
//
class Child extends Base
{
public void readObjectFromStream(
ManagedObjectStreamClass remoteClassDesc,
ObjectInputStream in) throws IOException
{
//
// Call the parent to process its fields (like a constructor,
// this must be called before reading the child fields).
//
super.readObjectFromStream(remoteClassDesc, in);
//
// Process child fields
//
}
}Here is another example, where the class hierarchy has changed between the old and new class version.
// VERSION 1:
@Managed
class InheritBase implements ObjectMismatchTrigger, Serializable
{
int int_val;
}
class InheritChild extends InheritBase
{
byte [] byte_array;
}
class Inherit extends InheritChild
{
String [] str_array;
}
//
// VERSION 2: collapsed the class hierachy into a single class
//
@Managed
class Inherit implements ObjectMismatchTrigger, Serializable
{
int int_val;
byte [] byte_array;
String [] str_array;
public void readObjectFromStream(
ManagedObjectStreamClass remoteClassDesc,
ObjectInputStream in) throws IOException
{
//
// Process all fields directly here, this includes
// the parent class fields (InheritBase & InheritChild)
// in VERSION 1
//
}
}Reflection must be used to set final
fields in a class in the readObjectFromStream method.
The Java language prohibits the setting of final
fields after an object is created - but that is exactly what is required
when mapping a final field in the
readObjectFromStream method.
To set a final field in
readObjectFromStream requires code like the
following, where field id is defined as
final.
try
{
java.lang.reflect.Field f = this.getClass().getDeclaredField("id");
f.setAccessible(true);
f.set(this, val);
}
catch (NoSuchFieldException ex)
{
throw new IOException(ex);
}
catch (IllegalAccessException ex)
{
throw new IOException(ex);
}Errors processing an object stream are reported using a
com.kabira.platform.DataError exception. This
exception contains information on the value that was in error. For
example:
com.kabira.platform.DataError: Stream Corrupted: invalid type code: 0x77, expected type code: 0x70
The type code values are defined by the Java Serialization specification Object Serialization Stream Protocol chapter. The constant definitions are also found in the java.io.ObjectStreamConstants javadoc.
The error above indicates that a TC_BLOCKDATA
type code was seen when a TC_NULL was expected. This
error was caused by attempting to write an integral type
(out.writeBytes()) when a string was expected
(out.writeObject()).