Property definitions - fieldenms/tg GitHub Wiki
The central concept in TG is "entity", which consists of "properties". This article discusses structural aspects of property definitions with the main emphasis on deriving the metadata, used for database interactions.
Properties are fundamental constituent parts of entities that define their structure and define the relationships between entities. Properties carry the type information and the integrity constraints. Please refer to Entities and their validation for more details about integrity constraints.
In Java terms, a property is a field declared as part of an entity (descendant of AbstractEntity
) that is annotated with @IsProperty
, which has a getter and a setter (explicit or implicit).
All properties are classified according to the following essential criteria:
- Nature
-
Persistent - backed by a data storage, where property values can be saved to and retrieved from.
-
Transient - not backed by a data storage.
Typically used in synthetic and action entities, but also applicable to persistent entities. Transient properties are further categorised into:
- Calculated - usually read-only values, derived by computing the associated EQL expression.
- CritOnly - used to provide additional search criteria, hence application is limited to Synthetic Entities.
- Plain - all other transient properties, which can be used for intermediate state with all the benefits properties provide (e.g., integrity constraints).
- Type
- Entity - entity types.
- Collectional - represent a collection of values.
-
Primitive - types with a single component (e.g.,
String
,Integer
). -
Component - product types with one or more distinct attributes, where identity is defined by values of those attributes (e.g.
Money
,Kilometer
,Tonn
). - Special – a set of special types that do not fall into any of the above categories, introduced mainly as an implementation convenience, but also convey modelling aspects (see below for more details).
The following property types are supported by the platform.
Technically speaking, any class that extends AbstractEntity
is an entity type.
However, there are different intentions of creating entity types, which lead to further categorisation.
-
Domain Entities: entities that represent a domain concept such as a vehicle, person, etc.
Such entities can be persistent or synthetic and their instances can exist in their own right. Action entities are also domain entities, but they cannot be property types.
Persistent and synthetic entities are product types, and represent a domain concept or association between domain concepts.
-
Value Entities: entities that exist strictly to be used as property types for properties of a domain entity.
The two main representatives are:
Union Entities
andPropertyDescriptor
.PropertyDescriptor
is a convenient abstraction to represent meta-information about entity properties in a way that application users can benefit from.For example, it is possible to model a configuration entity that could be used by users to designate properties of certain entity as required, or to assign some default values upon instantiation of those entities. Such configuration entity would have a property of type
PropertyDescriptor
, which can be represented as an autocompleter in the UI, and users would be able to search and select properties with a drop-down list.Union Entities
model sum types or tagged union. Their purpose is to hold a value that could take on several different, but fixed, persistent entity types. Only one of the entity types can be in use at any one time, and an active property explicitly indicates, which entity type is in use. All union entities should extendAbstractUnionEntity
.For example, domai entity
Rotable
can be in several "kinds" of locations –Workshop
andVehicle
. This can be modelled as union entityLocation
with two propertiesworkshop: Workshop
andvehicle: Vehicle
, and the system would guarantee that only one of those properties could have a value, and all the usual things like EQL support, UI support, etc.
Any type assignable to java.util.Collection
and parameterised with a type listed in items 1-3 (boxing of primitive types applies).
Additionally, any type assignable to Map
.
Types that represent what is considered to be an atomic value.
- Standard Java:
Long
,Integer
,BigDecimal
,Date
,String
,boolean
,Class
,Currency
,byte[]
. - Platform:
Colour
,Hyperlink
.
Component types represent values that have internal structure, but are not entities.
A component type is composed of one or more components.
For example, type Money
may be defined with 2 components:
amount : BigDecimal
currency : Currency
Component types provided by the platform are:
-
Money
-
RichText
Rich text cannot be used as a part of an entity key as it is not designed to have identity.
The are helper types. And there are currently only 2:
-
DynamicEntityKey
– a special type to represent compositekey
with one or more key members. -
NoKey
– a special type to represent propertykey
for action-entities that do have any practical use for a key.
Apart from the set of supported collection element types, the following rules apply to definitions of collectional properties:
- The field must be declared using the
final
modifier.
Entity definition must include a pair of accessor and setter methods for every declared property.
Accessor is synonymous with getter and serves the same purpose. The naming convention permits 2 kinds of prefixes immediately followed by the capitalised name of the property:
-
is
-- intended to be used withboolean
properties -
get
-- intended to be used with all other types of properties
In most cases an accessor method should simply return the property's value as-is.
However, for collectional properties an unmodifiable view should be returned to
facilitate immutability. The standard Collections
class provides a rich variety of methods
for this purpose.
Setter (also called mutator) is a method of a single argument that updates the
respective property's value. The only naming convention uses prefix set
followed
by the capitalised name of the property.
A setter method must be declared with public
or protected
visibility.
It is recommended to match the return type of a setter with the type of its declaring entity type,
in order to benefit from method chaining. This can be achieved by ending a setter's body with return this
.
All setter methods must be annotated with @Observable
in order to enable interception.
In most cases a setter method should update its property's value in a straightforward
manner -- by means of assignment. However, for collectional properties (which are final
)
it is required to first clear the collection and then add all elements of the argument.
@Observable
public Vehicle setParts(final List<Part> parts) {
this.parts.clear();
this.parts.addAll(parts);
return this;
}
Additionally, a property may admit a combination of the following characteristics:
-
Requiredness
Property must be assigned a value. After assignment, the value cannot be removed, only replaced.
-
KeyMembership
Property constitutes a part of its entity's key. Implies Requiredness.
-
OptionalKeyMembership
Requires KeyMembership, excludes Requiredness.
-
Finality
The first value that a property is persisted with remains unchanged for the whole lifetime of an entity.
-
...