Fork me on GitHub

Operations

therian is implemented as an open-ended mechanism for executing type-safe Operations defined in Java. The core Operations are the reason we’re here:

Convert<SOURCE, TARGET>

Represents type conversion from a readable SOURCE Position to a writable TARGET Position. A successful evaluation result is a TARGET instance, but the value is also set upon the target position, if specified:

Convert.to(targetPosition, sourcePosition);
Convert.to(targetType, sourcePosition);

A Convert Operation is usually supported by a Converter subclass.

Copy<SOURCE, TARGET>

Represents the copying of values from a readable SOURCE Position to a readable TARGET Position. A Copy operation has a Void result type:

Copy.to(targetPosition, sourcePosition);

A Copy Operation is usually supported by a Copier subclass.

Copy.Safely<SOURCE, TARGET>

Typically a therian Operation will throw an OperationException on an unsuccessful evaluation; this “safe” version of the Copy Operation suppresses the exception:

Copy.Safely.to(targetPosition, sourcePosition);

Supporting Operations

therian defines a number of supporting Operations which are used to assist in the implementation of the more central Operations:

Add<SOURCE, TARGET>

Requests the addition of a readable SOURCE Position to a readable TARGET “container” position, in the nature of element to Collection. This Operation’s Boolean result indicates whether successful execution resulted in a modification to the TARGET.

Add.to(targetPosition, sourcePosition);

AddAll<SOURCE, TARGET>

Requests the addition of a readable SOURCE “container” Position’s content to a readable TARGET “container” position. Like Add, this Operation’s Boolean result indicates whether successful execution resulted in a modification to the TARGET.

AddAll.to(targetPosition, sourcePosition);

GetElementType<T>

Requests the element Type of a readable “container” Position or other org.apache.commons.lang3.reflect.Typed instance. therian provides built-in support for:

  • array types
  • java.lang.Iterable
  • java.util.Enumeration
  • java.util.Iterator
  • java.util.Map

An unrecognized type will be treated as a singleton container; i.e. it will return its own type. As always custom Operators can be supplied that understand how to get the element Type of any custom type.

GetElementType.of(position);
GetElementType.of(typed);

ImmutableCheck<T>

Checks whether the value of a readable Position is immutable. Specifically this is useful when executing a deep Copy Operation; by default, the base Copier class supports the notion that a Copy to a TARGET Position with an immutable value is rejected. This follows from the notion that a Copy Operation has the implicit intent of mutating its TARGET. therian’s ConvertingCopier provides the ability, in these cases, to fall back to a Convert Operation, enforcing the so-called “principle of least surprise.” therian ships with the DefaultImmutableChecker which detects the immutability of:

  • null
  • java.lang.String
  • java.lang.Enum+
  • java.lang.annotation.Annotation
  • java.lang.Class
  • java.util.Arrays#asList()
  • java.util.Collections#singleton()
  • java.util.Collections#singletonList()
  • java.util.Collections#singletonMap()
  • java.util.Collections#emptySet()
  • java.util.Collections#unmodifiableSet()
  • java.util.Collections#emptyList()
  • java.util.Collections#unmodifiableList()
  • java.util.Collections#unmodifiableSortedSet()
  • java.util.Collections#emptyMap()
  • java.util.Collections#unmodifiableMap()
  • java.util.Collections#unmodifiableSortedMap()

Clients can provide custom ImmutableChecker extensions to inform therian which custom types must be considered immutable.

ImmutableCheck.of(readablePosition)

Size<T>

Gets the size of a readable “container” Position as Integer. therian is equipped to take the sizes of:

  • arrays (via #length)
  • java.lang.CharSequence (via #length())
  • java.lang.Collection (via #size())
  • java.lang.Iterable (by #iterator() size)
  • java.util.Iterator (by iteration)
  • java.util.Map (by #size())

null objects have size 0; other objects not supported by some Size Operator are considered singletons and have size 1. As usual, custom Size Operators can handle custom types.

Size.of(readablePosition);

Custom Operations

Therian is open-ended and can be used to create custom Operation/Operator combinations. The most important thing to know when creating a custom Operation is that therian must be able to discern its Type parameter assignments at runtime, a feature not normally available with parameterized Java types. To support this requirement, an Operation subclass should provide, for each declared type variable V, a corresponding method taking no parameters, returning Typed<V>, and annotated with @BindTypeVariable. This will allow therian to detect the type bindings of the Operation and thus locate its supporting Operators.