Class Installable<T>

java.lang.Object
eu.bandm.tools.util.files.Installable<T>
Type Parameters:
T - the type of object to store
All Implemented Interfaces:
Supplier<T>

@PropertyDependency({"user.dir","file.separator"}) public class Installable<T> extends Object implements Supplier<T>
Wrapper for a reference to an object that may be either created at runtime or serialized as a resource.

When an object is an asset that is costly to initialize, for instance because it requires data to be computed by a complex algorithm, it may be advantageous to have the initial data precomputed and load it from persistent storage, thus trading space for startup time. However, the successful initialization then requires the precomputed data to be actually available as a loadable resource.

This class functions as a wrapper to such a costly-to-initialize asset object, which can either load precomputed data or transparently fall back to procedural construction.

Usage (Run Time)

Instead of creating an object explicitly during initialization,

 class Owner {
   static final Asset myAsset = createCostlyAsset();
 }

… the initialization can be delegated to a new Installable wrapper object with enough metadata to choose between deserialization and creation:

 class Owner {
   static final Installable<Asset> myAsset = new Installable<Asset>(Owner.class, Asset.class, "myAsset", () -> createCostlyAsset());
 }

The actual asset object can be retrieved later via Supplier.get().

Installation (Build Time)

During application build time, a data file with the serialized asset object can be created and written someplace:

   myAsset.store(myGeneratedFilesDirectory);

The file name is determined by the given metadata, see getResourceName(). The file can then be placed in the class path of the application being built, thus making the serialized object available at run time. Note that the code of the owner class is shared between both phases.

The process can be automated for all accessible static fields of a class:

   Installable.storeAllStaticFields(myGeneratedFilesDirectory, false, Owner.class);
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static class 
    A simple command line interface application for writing data files.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final String
    The separator between the class name and simple name of a resource.
  • Constructor Summary

    Constructors
    Constructor
    Description
    Installable(Class<?> ownerClass, Class<? extends T> valueClass, String name, Supplier<? extends T> creator)
    Creates a new instance.
  • Method Summary

    Modifier and Type
    Method
    Description
    get()
    Returns the stored object.
    Returns the resource name for the stored object.
    void
    store(File targetDirectory)
    Writes the stored object to a file.
    static void
    storeAllStaticFields(File targetDirectory, boolean deep, Class<?> ownerClass)
    Writes all appropriate static fields of a class to files.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

  • Constructor Details

    • Installable

      public Installable(Class<?> ownerClass, Class<? extends T> valueClass, String name, Supplier<? extends T> creator)
      Creates a new instance.

      An attempt is made to load the serialized object as a resource. If that fails, the object is created newly.

      The resource given name, localized to an owner class, is used to try and obtain a data file via Class.getResource(java.lang.String). The file should contain a single serialized object graph written via ObjectOutput.writeObject(java.lang.Object), which is then deserialized. All usual caveats apply.

      If deserialization succeeds, the deserialized object is stored. Otherwise, the given function object is invoked to create the object from scratch.

      Parameters:
      ownerClass - the class that owns the stored object and the resource
      valueClass - the type of the stored object
      name - the simple name of the object and resource; must be a valid Java identifier
      creator - a function object to create the object on the fly
      Throws:
      IllegalArgumentException - if name is not a valid Java identifier
      RuntimeException - if creator is invoked and throws an exception
  • Method Details

    • get

      public T get()
      Returns the stored object.

      Invoking this method does not cause the object to be created or loaded (that happens during constructor invocation). The identical object is returned every time this method is invoked.

      Specified by:
      get in interface Supplier<T>
      Returns:
      the stored object
    • getResourceName

      public String getResourceName()
      Returns the resource name for the stored object.

      The resource name is always of the form c+s+n, where c is the unqualified name of the owner class, s is the value of resourceSeparator, and n is the unqualified name of the resource.

      The stored object will be loaded from the named resource file if possible.

      Returns:
      a string containing the resource name for the stored object
    • store

      public void store(File targetDirectory) throws IOException
      Writes the stored object to a file.

      The relative file name is the resource name for the stored object.

      To install the file as a resource, place it in the classpath beside the owner class.

      Parameters:
      targetDirectory - the target directory
      Throws:
      IOException - if the object file cannot be written
      See Also:
    • storeAllStaticFields

      public static void storeAllStaticFields(File targetDirectory, boolean deep, Class<?> ownerClass) throws IOException
      Writes all appropriate static fields of a class to files.

      All accessible static fields of type Installable of the given owner class are queried via reflection, and processed with store(java.io.File).

      Exceptions that arise from reflection are silently caught, and the concerned field is omitted. By contrast, IOExceptions that arise from writing are not caught.

      Parameters:
      targetDirectory - the target directory
      deep - if true, turn the package prefix of the owner class into subdirectories which must exist already; if false, store files in target directory directly
      ownerClass - the owner class
      Throws:
      IOException - if some object file cannot be written