public interface Externalizable

Known subtypesAppState, AccessToken, Cookie, CachedData, Receipt

Externalizable is similar to the Java SE Externalizable interface this interface. Notice that due to the lack of reflection and use of obfuscation these objects must be registered with the Util class.

Also notice that all externalizable objects must have a default public constructor.

Built-In Object types

The externalization process supports serializing these types and considers them to be Externalizable. E.g. you can just write Storage.getInstance().writeObject(new Object[] {"Str1", "Str2");} and it will work as expected.

Notice that while these objects can be written, the process doesn’t guarantee they will be read with the same object type. E.g. if you write a java.util.LinkedList you could get back a java.util.ArrayList as both implement java.util.Collection:

java.lang.String, java.util.Collection, java.util.Map, java.util.ArrayList, java.util.HashMap, java.util.Vector, java.util.Hashtable, java.lang.Integer, java.lang.Double, java.lang.Float, java.lang.Byte, java.lang.Short, java.lang.Long, java.lang.Character, java.lang.Boolean, Object[], byte[], int[], float[], long[], double[].

The sample below demonstrates the usage and registration of the Externalizable interface:

// File: Main.java
public class Main {
  public void init(Object o) {
    theme = UIManager.initFirstTheme("/theme");

    // IMPORTANT: Notice we don't use MyClass.class.getName()! This won't work due to obfuscation!
    Util.register("MyClass", MyClass.class);
  }

  public void start() {
    //...
  }

  public void stop() {
    //...
  }

  public void destroy() {
    //...
  }
}
// File: MyClass.java
public class MyClass implements Externalizable {
  // allows us to manipulate the version, in this case we are demonstrating a data change between the initial release
  // and the current state of object data
  private static final int VERSION = 2;

  private String name;
  private Map data;

  // this field was added after version 1
  private Date startedAt;

  public int getVersion() {
    return VERSION;
  }

  public void externalize(DataOutputStream out) throws IOException {
    Util.writeUTF(name, out);
    Util.writeObject(data, out);
    if(startedAt != null) {
        out.writeBoolean(true);
        out.writeLong(startedAt.getTime());
    } else {
        out.writeBoolean(false);
    }
  }
  public void internalize(int version, DataInputStream in) throws IOException {
    name = Util.readUTF(in);
    data = (Map)Util.readObject(in);
    if(version > 1) {
        boolean hasDate = in.readBoolean();
        if(hasDate) {
            startedAt = new Date(in.readLong());
        }
    }
  }
  public String getObjectId() {
    // IMPORTANT: Notice we don't use getClass().getName()! This won't work due to obfuscation!
    return "MyClass";
  }
}
// File: ReadAndWrite.java
// will read the file or return null if failed
MyClass object = (MyClass)Storage.getInstance().readObject("NameOfFile");

// write the object back to storage
Storage.getInstance().writeObject("NameOfFile", object);

WARNING: The externalization process caches objects so the app will seem to work and only fail on restart!

Methods

public abstract int getVersion()Returns the version for the current persistance code, the version will be pased to internalized thus allowing the internalize method to recognize classes persisted in older revisions
public abstract void externalize(DataOutputStream out) throws IOExceptionAllows us to store an object state, this method must be implemented in order to save the state of an object
public abstract void internalize(int version, DataInputStream in) throws IOExceptionLoads the object from the input stream and allows deserialization
public abstract String getObjectId()The object id must be unique, it is used to identify the object when loaded even when it is obfuscated.

Method details

getVersion

public abstract int getVersion()
Returns the version for the current persistance code, the version will be pased to internalized thus allowing the internalize method to recognize classes persisted in older revisions

Returns

version number for the persistant code

externalize

public abstract void externalize(DataOutputStream out) throws IOException
Allows us to store an object state, this method must be implemented in order to save the state of an object

Parameters

out DataOutputStream
the stream into which the object must be serialized

Throws

java.io.IOException
the method may throw an exception

internalize

public abstract void internalize(int version, DataInputStream in) throws IOException
Loads the object from the input stream and allows deserialization

Parameters

version int
the version the class returned during the externalization processs
in DataInputStream
the input stream used to load the class

Throws

java.io.IOException
the method may throw an exception

getObjectId

public abstract String getObjectId()
The object id must be unique, it is used to identify the object when loaded even when it is obfuscated.

Returns

a unique id