Overview | Package | Class | Use | Tree | Deprecated | Index | Help
| Berkeley DB Java Edition version 3.0.12
PREV CLASS NEXT CLASS | FRAMES NO FRAMES
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD

## 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.

Overview | Package | Class | Use | Tree | Deprecated | Index | Help
| Berkeley DB Java Edition version 3.0.12
PREV CLASS NEXT CLASS | FRAMES NO FRAMES
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD

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