4.4.4. Structs

In Section 4.3, “Objects” the interface CapStruct was introduced as a superinterface of CapObject for providing readable properties of an entity. While CapObjects are mutable and thus not suitable as values, the interface Struct also inherits from CapStruct and represents an unmodifiable structured object.

Structs can be stored in markup properties of the content repository, if the markup property uses the predefined grammar coremedia-struct-2008. The Unified API will transparently convert instances of Struct to and from XML. The storage format is compatible with the struct abstraction that used to be provided with CoreMedia Starter Kit.

Structs support only a limited range of primitive property types, namely strings, integers, Boolean, links to Content and lists thereof. However, structs may also contain arbitrarily nested structs and lists of structs as complex property values. While structs themselves are immutable, they provide the builder() method that returns a builder object that can be used to create other similar structs.

[Caution]Caution

StructBuilders are not structs. They cannot be used as property values.

A StructBuilder provides methods to set property values and to declare new properties. The method set(String, Object) sets a single property, whereas the method setAll(Map) sets multiple properties at once. The methods declare... take varying arguments depending on the type of property they define. For list properties, the methods set(String, int, Object), add(String, Object) and add(String, int, Object) provide ways to replace a list element or to add a new list element. Likewise, remove(String, int) removes a single element from a list.

When building nested structs, a struct builder always considers either the top-level struct or one of the substructs as the current struct. Set and declare operations are always performed on the current struct. Using the methods enter(String) a substruct of the current struct can be selected as the new current struct. In the case of struct lists, use enter(String, int). When calling up(), the current struct can be set back one level towards the top-level struct. Calling at(...), you can navigate directly to a deeply nested substruct ignoring the previous current struct. The method currentPath() returns the current path, allowing you to return to a given substruct later on.

The method mode(...) requests one of three different behaviors that are represented by the enumeration class StructBuilderMode. The mode determines how the struct builder reacts when a declare or set operation conflicts with the existing declaration of a property. By default, a new property can be directly set without declaring it, as long as the value is not null or a list containing values of mixed types, because a suitable property descriptor can be inferred. But that is not allowed in all modes.

  • STRICT: Declare operations fail if the property already exists. Set operations fail if no property descriptor exists and they fail if the existing property descriptor does not allow the value. Property descriptors are never inferred.

  • DEFAULT: Declare operations fail if the property already exists. Set operations fail if the existing property descriptor does not allow the value or if a new property descriptor cannot be inferred.

  • LOOSE: Declare operations never fail. Set operations fail only if the desired property descriptor cannot be inferred. If a new value does not match an existing property descriptor, the existing descriptor is replaced by another descriptor that allows the value.

You can use the method remove(String) to remove a property declaration from the current struct. In strict and default mode, this is necessary before a property can be redeclared. Using removeAll() the current struct be reset to an empty struct.

The method defaultTo(Struct) can be used to extend the current struct with those property declarations of the argument struct that were not previously present in the current struct. This is useful to set default values when initializing a struct or when merging multiple levels of struct-based configurations. When an existing struct property is defaulted to another struct property, the default is applied recursively. When an existing struct list property is defaulted to a struct property (not a struct list property), each list element is augmented with default values individually.

Finally, when the struct is completely built, you can retrieve it from the builder by means of the build() method. The builder remains usable to build additional similar structs. At any time, you can also retrieve the current struct using currentStruct().

[Caution]Caution

StructBuilder instances are not thread-safe. Builders must not be accessed concurrently by multiple threads.