Berkeley DB Java Edition
version 3.0.12

com.sleepycat.persist.evolve
Interface Converter

All Superinterfaces:
Serializable

public interface Converter
extends Serializable

Converts an old version of an object value to conform to the current class definition.

Conversions of simple types are generally simple. For example, a String field that contains only integer values can be easily converted to an int field:

  // The old class.  Version 0 is implied.
  //
  @Persistent
  class Address {
      String zipCode;
      ...
  }

  // The new class.  A new version number must be assigned.
  //
  @Persistent(version=1)
  class Address {
      int zipCode;
      ...
  }

  // The converter class.
  //
  class MyConverter1 implements Converter {

      public void initialize(EntityModel model) {
          // No initialization needed.
      }

      public Object convert(Object fromValue) {
          return Integer.valueOf((String) fromValue);
      }
  }

  // Create a field conversion mutation.
  //
  Conversion conversion = new Conversion(Address.class.getName(), 0,
                                         "zipCode", new MyConverter1());

  // Configure the conversion as described here.

A converter may perform arbitrary transformations on an object. For example, a converter may transform a single String address field into four fields for street, city, state and zip code, or vice versa.

  // The old class.  Version 0 is implied.
  //
  @Entity
  class Person {
      String address;
      ...
  }

  // The new class.  A new version number must be assigned.
  //
  @Entity(version=1)
  class Person {
      Address address;
      ...
  }

  // The new address class.
  //
  @Persistent
  class Address {
      String street;
      String city;
      String state;
      int zipCode;
      ...
  }

  class MyConverter2 implements Converter {
      private transient RawType newPersonType;
      private transient RawType addressType;

      public void initialize(EntityModel model) {
          newPersonType = model.getRawType(Person.class.getName());
          addressType = model.getRawType(Address.class.getName());
      }

      public Object convert(Object fromValue) {

          // Get field value maps for old and new objects.
          //
          RawObject person = (RawObject) fromValue;
          RawObject address = new RawObject(addressType, null, null);
          Map<String,?> personValues = person.getValues();
          Map<String,?> addressValues = address.getValues();

          // Remove the old address and replace it with a new one.
          //
          String oldAddress = (String) personValues.remove("address");
          addressValues.put("street", parseStreet(oldAddress));
          addressValues.put("city", parseCity(oldAddress));
          addressValues.put("state", parseState(oldAddress));
          addressValues.put("zipCode", parseZipCode(oldAddress));
          personValues.put("address", address);

          return new RawObject(newPersonType, personValues, person.getSuper());
      }

      private String parseStreet(String oldAddress) { ... }
      private String parseCity(String oldAddress) { ... }
      private String parseState(String oldAddress) { ... }
      private Integer parseZipCode(String oldAddress) { ... }
  }

  // Create a field conversion mutation.
  //
  Conversion conversion = new Conversion(Person.class.getName(), 0,
                                         "address", new MyConverter2());

  // Configure the conversion as described here.

Note that when a converter returns a RawObject, it must return it with a RawType that is current as defined by the current class definitions. The proper types can be obtained from the EntityModel in the converter's initialize method.

A converter can handle changes to class hierarchies. For example, if a "name" field originally declared in class A is moved to its superclass B, a converter can move the field value accordingly:

  // The old classes.  Version 0 is implied.
  //
  @Persistent
  class A extends B {
      String name;
      ...
  }
  @Persistent
  class B {
      ...
  }

  // The new classes.  A new version number must be assigned.
  //
  @Persistent(version=1)
  class A extends B {
      ...
  }
  @Persistent(version=1)
  class B {
      String name;
      ...
  }

  class MyConverter3 implements Converter {
      private transient RawType newAType;
      private transient RawType newBType;

      public void initialize(EntityModel model) {
          newAType = model.getRawType(A.class.getName());
          newBType = model.getRawType(B.class.getName());
      }

      public Object convert(Object fromValue) {
          RawObject oldA = (RawObject) fromValue;
          RawObject oldB = oldA.getSuper();
          Map<String,?> aValues = oldA.getValues();
          Map<String,?> bValues = oldB.getValues();
          bValues.put("name", aValues.remove("name"));
          RawObject newB = new RawObject(newBType, bValues, oldB.getSuper());
          RawObject newA = new RawObject(newAType, aValues, newB);
          return newA;
      }
  }

  // Create a class conversion mutation.
  //
  Conversion conversion = new Conversion(B.class.getName(), 0,
                                         new MyConverter3());

  // Configure the conversion as described here.

A converter may return an instance of a different class entirely, as long as it conforms to current class definitions. For example, a field that is used to discriminate between two types of objects could be removed and replaced by two new subclasses:

  // The old class.  Version 0 is implied.
  //
  @Persistent
  class Pet {
      boolean isCatNotDog;
      ...
  }

  // The new classes.  A new version number must be assigned to the Pet class.
  //
  @Persistent(version=1)
  class Pet {
      ...
  }
  @Persistent
  class Cat extends Pet {
      ...
  }
  @Persistent
  class Dog extends Pet {
      ...
  }

  class MyConverter4 implements Converter {
      private transient RawType newPetType;
      private transient RawType dogType;
      private transient RawType catType;

      public void initialize(EntityModel model) {
          newPetType = model.getRawType(Pet.class.getName());
          dogType = model.getRawType(Dog.class.getName());
          catType = model.getRawType(Cat.class.getName());
      }

      public Object convert(Object fromValue) {
          RawObject pet = (RawObject) fromValue;
          Map<String,?> petValues = pet.getValues();
          Boolean isCat = (Boolean) petValues.remove("isCatNotDog");
          RawObject newPet = new RawObject(newPetType, petValues,
                                           pet.getSuper());
          RawType newType = isCat.booleanValue() ? catType : dogType;
          return new RawObject(newType, null, newPet);
      }
  }

  // Create a class conversion mutation.
  //
  Conversion conversion = new Conversion(Pet.class.getName(), 0,
                                         new MyConverter4());

  // Configure the conversion as described here.

The primary limitation is that a converter may access at most a single entity instance at one time. Conversions involving multiple entities at once may be performed using a ConversionStore.

Author:
Mark Hayes

Method Summary
 Object convert(Object fromValue)
          Converts an old version of an object value to conform to the current class definition.
 void initialize(EntityModel model)
          Initializes the converter, allowing it to obtain raw type information from the entity model.
 

Method Detail

initialize

void initialize(EntityModel model)
Initializes the converter, allowing it to obtain raw type information from the entity model.


convert

Object convert(Object fromValue)
Converts an old version of an object value to conform to the current class definition.

If a RuntimeException is thrown by this method, it will be wrapped in a DatabaseException and thrown to the original caller. Similarly, a DatabaseException will be thrown if the object returned by this method does not conform to current class definitions.

The class of the input and output object may be one of the simple types or RawObject, or an array of one of these types.

Parameters:
fromValue - the object value being converted. The type of this value is defined by the old class version that is being converted.
Returns:
the converted object. The type of this value must conform to the current class definition.

Berkeley DB Java Edition
version 3.0.12

Copyright (c) 1996-2006 Sleepycat Software, Inc. - All rights reserved.