Classmod/Properties

From LoadingByte Wiki
Jump to navigation Jump to search

A property is a feature which stores any object it is provided with. The main property interface lies in the com.quartercode.classmod.extra package. Note that collection properties are optimized to store any object collection and make it accessible.

Properties

The default property interface in com.quartercode.classmod.extra defines a get() and a set() method for accessing and changing the stored object. However, an interface called PropertyDefinition is defined as well. As you might have already guessed, property definitions allow to customize properties and their behavior.

Property creation

Creating such a property definition is easy by using the Classmod Factory:

import static com.quartercode.classmod.ClassmodFactory.*;
...

public class Square extends DefaultFeatureHolder {

    public static final PropertyDefinition<Integer> SIDE_LENGTH;

    static {
        SIDE_LENGTH = create(new TypeLiteral<PropertyDefinition<Integer>>() {}, "name", "sideLength", "storage", new StandardStorage<>());
    }

}

The generic parameter of PropertyDefinition defines which type of object can be stored inside properties created from the definition. Moreover, the storage parameter for the create() method specifies how the objects which are put into created properties are stored. StandardStorage is the default storage implementation and just stores any object inside a variable. The other storage types, ReferenceStorage and TransientStorage, are important for persistence and are explained on that page.

Initial values (and value factories)

Note that the property definition can also be instructed to assign a default (initial) value to each property created from it. Value factories are used to create these default values. By default, ConstantValueFactory and CloneValueFactory are are available in com.quartercode.classmod.extra.valuefactory. However, you can create your own value factories using your own (anonymous) implementations of the functional interface. For example, you might want to create an anonymous value factory implementation for using a non-clonable initial value, e.g. another feature holder.

Since SIDE_LENGTH stores an immutable object (since its a primitive integer), an efficient ConstantValueFactory, which just returns the value passed into its constructor, can be used. For other clonable and mutable objects, the CloneValueFactory should be used.

...
SIDE_LENGTH = create(new TypeLiteral<PropertyDefinition<Integer>>() {}, "name", "sideLength", "storage", new StandardStorage<>(), "initialValue", new ConstantValueFactory<>(42));
...

Getter/Setter executors

The property definition interface also defines several methods for adding or removing getter and setter executors. Those are function executors which are called whenever the get() or set() methods are called on a created property instance. For more information on functions, you can visit the linked page.

Getter function executors are called without parameters and return the value returned by the get() method. By default, a function executor with the default priority returns the value stored by the internal property storage. In contrast, setter function executors are called with the new content as the only parameter. The default setter function executor, which also has the default priority, changes the internally stored object to the parameter.

public void addGetterExecutor(String name, Class<? extends FeatureHolder> variant, FunctionExecutor<T> executor)
public void addGetterExecutor(String name, Class<? extends FeatureHolder> variant, FunctionExecutor<T> executor, int priority)
public void removeGetterExecutor(String name, Class<? extends FeatureHolder> variant)

public void addSetterExecutor(String name, Class<? extends FeatureHolder> variant, FunctionExecutor<Void> executor)
public void addSetterExecutor(String name, Class<? extends FeatureHolder> variant, FunctionExecutor<Void> executor, int priority)
public void removeSetterExecutor(String name, Class<? extends FeatureHolder> variant)

If you do not understand all the parameters, you should visit the page about functions.

Collection properties

Collection properties are special properties that are optimized for storing collections. In contrast to the normal properties, they do not offer a set() method. Instead, elements can be added and removed using add() and remove(). Of course, a CollectionPropertyDefinition exists as well.

Collection property creation

Creating a collection property definition by using the Classmod Factory is as easy as creating a regular property definition:

import static com.quartercode.classmod.ClassmodFactory.*;
...

public class Polygon extends DefaultFeatureHolder {

    public static final CollectionPropertyDefinition<Point, List<Point>> POINTS;

    static {
        POINTS = create(new TypeLiteral<CollectionPropertyDefinition<Point, List<Point>>>() {}, "name", "points", "storage", new StandardStorage<>(), "collection", new CloneValueFactory<>(new ArrayList<>()));
    }

}

Note that the provision of a collection implementation value factory (most of the times, it will be a CloneValueFactory) is necessary. That value factory creates the internal collection objects which cannot be replaced after its creation. All the other parameters are equal to the ones used for creating a regular property definition (apart from initialValue, because that one is replaced by collection).

Getter/Adder/Remover executors

Collection properties also support function executors. The default getter function executor returns an unmodifiable view to the internally stored collection. However, since there is no setter method available on collection properties, only adder and remover function executors can be added to a definition. As setter executors, they are called with the element for addition or removal as the only parameter. The default adder and remover executors also use the default priority and add or remove the provided element to or from the collection.

public void addGetterExecutor(String name, Class<? extends FeatureHolder> variant, FunctionExecutor<C> executor);
public void addGetterExecutor(String name, Class<? extends FeatureHolder> variant, FunctionExecutor<C> executor, int priority);
public void removeGetterExecutor(String name, Class<? extends FeatureHolder> variant);

public void addAdderExecutor(String name, Class<? extends FeatureHolder> variant, FunctionExecutor<Void> executor);
public void addAdderExecutor(String name, Class<? extends FeatureHolder> variant, FunctionExecutor<Void> executor, int priority);
public void removeAdderExecutor(String name, Class<? extends FeatureHolder> variant);

public void addRemoverExecutor(String name, Class<? extends FeatureHolder> variant, FunctionExecutor<Void> executor);
public void addRemoverExecutor(String name, Class<? extends FeatureHolder> variant, FunctionExecutor<Void> executor, int priority);
public void removeRemoverExecutor(String name, Class<? extends FeatureHolder> variant);