public class DefaultObjectCoder extends DefaultValueCoder implements KeyRenderer
An ObjectCoder
that uses reflection to access the properties and/or
fields of an object. An ObjectCoder
provides methods to encode
and decode properties or fields of an object into or from Key
s
and Value
s.
ObjectCoder
s allow Persistit to store and retrieve arbitrary
objects - even non-Serializable objects - without byte-code enhancement,
without incurring the space or time overhead of Java serialization or the
need to modify the class to perform custom serialization. During
initialization, an application typically associates an
ObjectCoder
with the Class
of each object that will
be stored in or fetched from the Persistit database. An
ObjectCoder
implements all of the logic necessary to encode and
decode the state of any object of that class to and from Persistit storage
structures.
A DefaultObjectCoder
is a generic implementation of the
ObjectCoder
interface. During initialization an application uses
the static registerObjectCoder
or
registerObjectCoderFromBean
method to
construct and register an ObjectCoder
for a particular class
with the current CoderManager
. To define a
DefaultObjectCoder
for a class, all that is required is two
arrays, one containing names of properties or fields that will be used in
constructing Key
values under which instances of the class will
be stored, and the other containing names of properties or fields that will
be encoded in the Value
associated with that key.
Unlike DefaultValueCoder
, which implements default serialization for
Persistit version 1.1, this extended implementation can encode and decode
non-serializable objects (that is, instances of classes that are do not
implement java.io.Serializable
). However, classes handled by
this ObjectCoder
must have a no-argument constructor which is
used to construct new objects instances in the
ValueCoder.get(Value, Class, CoderContext)
method. An extension of
this class may override the newInstance()
method to provide
customized logic for constructing new instances of the client class.
DefaultObjectCoder
may be used to serialize and deserialize the
private fields of an object through reflection. If the application using
Persistit is running in the context of a SecurityManager
, the
permission ReflectPermission("suppressAccessChecks")
is required
to permit this access. See the JDK documentation for
java.lang.reflect.AccessibleObject
and Persistit JSA 1.1 Object
Serialization for details. Similarly, the same permission is required
when deserializing an object with a private constructor.
For Java Runtime Environments 1.3 through 1.4.2, this class is unable to
deserialize fields marked final
due to a bug in the JRE (see bug
5044412). This bug was fixed in Java SE 5.0.
The following code fragment defines a simple class, registers a
DefaultObjectCoder
for it, then provides methods for storing and
and fetching instances to and from a Persistit database:
static class Vehicle
{
String id;
String description;
int speed;
int wheels;
int passengers
boolean canFly;
}
static
{
DefaultObjectCoder.registerObjectCoder(
Vehicle.class,
{"id"},
{"description", "speed", "wheels", "passengers", "canFly"});
}
void storeVehicle(Vehicle v, Exchange exchange)
throws PersistitException
{
exchange.getValue().put(v);
exchange.clear().append(v).store();
}
Vehicle getVehicle(String id, Exchange exchange)
throws PersistitException
{
Vehicle v = new Vehicle();
v.id = id;
//
// Using the id field as primary key, fetch the remaining fields
// of the object.
//
exchange.clear().append(v).fetch().get(v);
return v;
}
DefaultValueCoder.Builder
Modifier and Type | Method and Description |
---|---|
DefaultValueCoder.Builder |
addSecondaryIndexBuilder(String name,
String[] keyAccessorNames)
Construct and add a secondary index
Builder . |
void |
appendKeySegment(Key key,
Object object,
CoderContext context)
Append a key segment derived from an object to a
Key . |
Object |
decodeKeySegment(Key key,
Class clazz,
CoderContext context)
Decode a key segment as an Object value.
|
DefaultValueCoder.Builder |
getKeyBuilder()
Return the
Builder that copies data values between a
Key and a client object. |
DefaultValueCoder.Builder |
getSecondaryIndexBuilder(int index)
Return a
Builder s by index, according to the order in which
secondary index builders were added. |
DefaultValueCoder.Builder |
getSecondaryIndexBuilder(String name)
Return a
Builder by name. |
int |
getSecondaryIndexBuilderCount()
Return the count of secondary index builders.
|
boolean |
isZeroByteFree()
Since a key segment is terminated by a zero byte value the encoded
portion of the segment must not contain zeroes.
|
protected Object |
newInstance()
Construct a new instance of the client class.
|
static DefaultObjectCoder |
registerObjectCoder(Persistit persistit,
Class clientClass,
String[] keyAccessorNames,
String[] valueAccessorNames)
Convenience method that creates and registers a
DefaultObjectCoder for an arbitrary Java class. |
DefaultObjectCoder |
registerObjectCoderFromBean(Persistit persistit,
Class clientClass,
String[] keyPropertyNames)
Convenience method that creates and registers a
DefaultObjectCoder for a Java Bean. |
DefaultValueCoder.Builder |
removeSecondaryIndexBuilder(String name)
Remove a secondary index
Builder specified by its name. |
void |
renderKeySegment(Key key,
Object target,
Class clazz,
CoderContext context)
Populates the state of the supplied target
Object by
decoding the next key segment of the supplied Key . |
String |
toString()
Return a String description of this DefaultObjectCoder.
|
get, getClientClass, getHandle, getValueBuilder, put, putDefaultFields, render, setHandle
public DefaultObjectCoder registerObjectCoderFromBean(Persistit persistit, Class clientClass, String[] keyPropertyNames) throws IntrospectionException
Convenience method that creates and registers a
DefaultObjectCoder
for a Java Bean.
The supplied Class
must conform to the requirements of a
Java bean; in particular it must have a no-argument constructor. The
resulting ObjectCoder will serialize and deserialize the properties of
this bean as determined by the BeanInfo derived from introspecting the
bean's class or its associated BeanInfo class.
The keyPropertyNames
array specifies names of one or more
properties of the bean that are to be concatenated, in the order
specified by the array, to form the primary key under which instances of
this bean will be stored.
Persistit must be initialized at the time this method is called. This
method registers the newly created DefaultObjectCoder
the
Persistit instance's current CoderManager
.
clientClass
- The Class
of object this
DefaultObjectCoder
will encode and decodekeyPropertyNames
- Array of names of properties that constitute the primary key
of stored instancesDefaultObjectCoder
IntrospectionException
public static DefaultObjectCoder registerObjectCoder(Persistit persistit, Class clientClass, String[] keyAccessorNames, String[] valueAccessorNames)
Convenience method that creates and registers a
DefaultObjectCoder
for an arbitrary Java class. The class is
not required to be serializable (i.e., to implement
java.io.Serializable
), but it must have a no-argument
constructor. If the class implements Externalizable
, then
the constructor is required to be public, thus conforming to the contract
for Externalizable
classes. Otherwise, the constructor may
be public, protected, package-private or private.
The supplied Class
and the supplied names for fields or
properties constitute the state to be recorded in Persistit. The
resulting coder is capable of efficiently serializing and deserializing
instances of the client Class
in Persistit records.
Two String arrays determine the structure of the stored data. Each
element in these arrays identifies the name of either a field or a
property of the client Class
. For each name xyz, this
constructor first searches for a method with a signature compatible with
either
and a method with a signature compatible withTypegetXyz()
orboolean isXyz()
void setXyz(Type value)
In the case of the boolean property named isXyz
, the value
Type
must be boolean
; otherwise, the
type of the value specified by the setter must be assignable from return
type of the getter. In other words, the setXyz method must accept any
value that the getXyz method might return. If multiple setXyz methods
meet this requirement, the method with the most specific argument type is
selected.
If both setXyz and either getXyz or isXyz methods meeting these criteria
are found then the accessor is a property accessor, and will be stored
and retrieved from the object using these methods. Otherwise, the
accessor name must be the name of an accessible field of the client
Class
. Non-public fields are accessible only if permitted by
the security policy in which the code is executed and only on JDK
versions 1.2 and above. (See the JDK documentation for
java.lang.reflect.AccessibleObject
for details.)
The keyAccesssorNames
array identifies the properties or
fields whose values will constitute the primary key of an object stored
with this objectCoder
; the valueAccessorNames
array identifies the properties or fields that will constitute the value
associated with that key.
Persistit must be initialized at the time this method is called. This
method registers the newly created DefaultObjectCoder
the
Persistit instance's current CoderManager
.
clientClass
- The Class
whose instances are to be encoded and
decodedkeyAccessorNames
- Array of names of properties that constitute the primary key
of stored instances of the clientClass
.valueAccessorNames
- Array of names of properties that constitute the value of
stored instances of the clientClass
.DefaultObjectCoder
protected Object newInstance()
Class.newInstance()
. Subclasses may override this method to
provide custom logic for constructing new instances.DefaultObjectCoder
is registered.public DefaultValueCoder.Builder addSecondaryIndexBuilder(String name, String[] keyAccessorNames)
Builder
.name
- Name of the secondary indexkeyAccessorNames
- The property and/or field namespublic DefaultValueCoder.Builder removeSecondaryIndexBuilder(String name)
Builder
specified by its name.name
- Name if the secondary index to remove.null
if there was
none.public DefaultValueCoder.Builder getSecondaryIndexBuilder(int index)
Builder
s by index, according to the order in which
secondary index builders were added.public DefaultValueCoder.Builder getSecondaryIndexBuilder(String name)
Builder
by name.null
if there is no secondary index
with the specified name.public int getSecondaryIndexBuilderCount()
public DefaultValueCoder.Builder getKeyBuilder()
Builder
that copies data values between a
Key
and a client object. The resulting Key
value is intended to serve as the primary key for the object.public void appendKeySegment(Key key, Object object, CoderContext context) throws ConversionException
KeyCoder
Append a key segment derived from an object to a Key
. This method
will be called only if this KeyCoder
has been registered
with the current CoderManager
to encode objects having the class
of the supplied object.
Upon completion of this method, the backing byte array of the
Key
and its size should be updated to reflect the appended
key segment. Use the methods Key.getEncodedBytes()
,
Key.getEncodedSize()
and Key.setEncodedSize(int)
to manipulate
the byte array directly. More commonly, the implementation of this method
will simply append appropriate identifying fields within the object to
the key.
This method is not responsible for encoding the class of the object being appended. The caller encodes the identity of the class. This method merely needs to encode the state of the object.
appendKeySegment
in interface KeyCoder
key
- The Key
to append toobject
- The object to encodecontext
- An arbitrary object that can optionally be supplied by the
application to convey an application-specific context for the
operation. (See CoderContext
.) The default value is
null
.ConversionException
public Object decodeKeySegment(Key key, Class clazz, CoderContext context) throws ConversionException
KeyCoder
Decode a key segment as an Object value. This method is invoked when
Key.decode(Object)
attempts to decode a key segment that was
previously append by the KeyCoder.appendKeySegment(com.persistit.Key, java.lang.Object, com.persistit.encoding.CoderContext)
method. Thus the
implementation of this method must precisely decode the same bytes that
were generated by the companion appendKeySegment
method of
this ValueCoder
.
This method will be called only if this KeyCoder
is
registered with the current CoderManager
to encode and decode
objects of the class that is actually represented in the Key
. The class with which the key was encoded is provided as an argument.
This permits one KeyCoder
to handle multiple classes because
the implementation can dispatch to code appropriate for the particular
supplied class. The implementation should construct and return an Object
having the same class as the supplied class.
When this method is called the value Key.getIndex()
will be the
offset within the key of the first encoded byte. The key segment is
zero-byte terminated.
decodeKeySegment
in interface KeyCoder
key
- The Key
from which data should be decodedclazz
- The expected Class
of the returned objectcontext
- An arbitrary object that can optionally be supplied by the
application to convey an application-specific context for the
operation. (See CoderContext
.) The default value is
null
.ConversionException
public boolean isZeroByteFree()
KeyCoder
Since a key segment is terminated by a zero byte value the encoded portion of the segment must not contain zeroes. This method should indicate whether the encoding implemented by this KeyCoder produces zero bytes.
If this method returns false
then Persistit will insert
escape sequences into the encoding produced by
KeyCoder.appendKeySegment(Key, Object, CoderContext)
to a form with no
zeroes.
If this method returns true
then Persistit will verify that
there are no zero bytes and throw an ConversionException otherwise.
isZeroByteFree
in interface KeyCoder
public void renderKeySegment(Key key, Object target, Class clazz, CoderContext context) throws ConversionException
Populates the state of the supplied target Object
by
decoding the next key segment of the supplied Key
. This
method will be called only if this KeyRenderer
has been
registered with the current CoderManager
to encode objects having
the supplied Class
value. In addition, Persistit will never
call this method to decode a value that was null
when
written because null values are handled by built-in encoding logic.
renderKeySegment
in interface KeyRenderer
key
- The Key
from which interior fields of the object
are to be retrievedtarget
- An object into which the key segment is to be writtenclazz
- The class of the object that was originally encoded into
Value.context
- An arbitrary object that can optionally be supplied by the
application to convey an application-specific context for the
operation. (See CoderContext
.) The default value is
null
.ConversionException
public String toString()
toString
in class DefaultValueCoder
Copyright © 2025 Open Identity Platform Community. All rights reserved.