Entity Properties
Properties of an entity are declared by properties in its interface.
Supported Types
The following types of properties are supported:
primitive types (
Int
,Boolean
, etc);String
enum
an immutable
data class
with properties of supported typesa
sealed
class which implementations are immutable data classes or objects with properties of supported typesa nullable variant of a supported type
List
,Set
orMap
collections with elements of supported types
Property Kinds
There are three kinds of properties: mandatory, optional, and computable properties.
Mandatory
If a property doesn't have a default value, it is treated as mandatory. Values of mandatory properties must be provided when an entity is created by passing parameters to the companion
object.
Optional
If a property has a default value, it is treated as optional. Optional properties may be initialized in a lambda passed as the last parameter to the companion
object. To provide a default value for a property, define a getter for them and annotate it with @Default
. Properties whose type is nullable have a default value null
implicitly, but there are no implicit default values for other types, even for primitive types.
Computable
If a property has a getter without @Default
annotation, it is treated as computable. Computable properties may use data from other properties of the same entity and other entities referenced from it only. Their values aren't saved in the storage but computed each time a property is accessed.
VirtualFileUrl
Represents a reference to a file or directory. Workspace model entities must use properties of this type to store references to files instead of storing their paths or URLs as String
properties, because it consumes less memory and provides an efficient way to locate a VirtualFile
.
Use VirtualFileUrlManager.getOrCreateFromUrl()
or VirtualFile.toVirtualFileUrl()
extension function to create an instance.
Use VirtualFileUrl.virtualFile
extension property to locate a VirtualFile
from a VirtualFileUrl
.
Also, it is possible to automatically update references in entities when corresponding files are moved or renamed. Currently, it is implemented to specific types of entities only in VirtualFileUrlWatcher
.
Locating VirtualFileUrl
EntityStorage.getVirtualFileUrlIndex()
provides a way to quickly find entities referring to a particular VirtualFileUrl
.
EntitySource
Describes a place where an entity came from. It may be:
a configuration file on disk (property
EntitySource.virtualFileUrl
should be implemented to point to that file)some strings that identify the source
a marker object if entities are generated automatically by some algorithm which doesn't use external data
Each entity must specify its source via the WorkspaceEntity.entitySource
property. For example, entities loaded from configuration files under the .idea directory use JpsProjectFileEntitySource
.
Information about entity sources is used by the MutableEntityStorage.replaceBySource()
function. See also Replace By Source section.
An entity source must be serializable along with entities, so there are some restrictions on its implementation. It must be a data class
that contains read-only properties of the following types:
primitive types
String
enum
List
of another allowed typeanother
data class
with properties of the allowed typessealed abstract class
where all implementations satisfy these requirements
SymbolicEntityId
The ID is supposed to be based on names specified by a user in the UI or in configuration files, not on some autogenerated IDs. Can be interpreted as a business key for the concrete entity type. SymbolicEntityId
for an entity may include a reference to SymbolicEntityId
of its parent entity if it is necessary to make them unique. For example, ModuleId
includes only the name of the module, but FacetId
includes the name of the facet and a reference to ModuleId
of the module the facet belongs to.
The Workspace Model store is prohibited from containing two entities with the same SymbolicEntityId
. For example, SymbolicIdAlreadyExistsException
will be thrown when trying to add a ModuleEntity
with a ModuleId
that is already present in the EntityStorage
.
To specify a SymbolicEntityId
for an entity, the entity interface must extend WorkspaceEntityWithSymbolicId
and provide an implementation of its symbolicId
property which returns an instance of the corresponding class. Type parameter <E>
of the returned instance must be equal to the entity interface. A specific implementation of SymbolicEntityId
may be used in properties of an entity to create a symbolic link to an entity of the corresponding type.
Note that unlike parent-child "hard" links, symbolic links aren't guaranteed to be resolvable. When a linked entity is removed, the entity referring to it doesn't change, and the ID will resolve to null
. However, if after modification of an entity, its symbolicId
changes, properties of all other entities containing a value equal to the previous ID are automatically replaced with the new ID.
The storage maintains an index, which can be used to quickly find all entities referring to a given entity via symbolic links, see EntityStorage.referrers()
function.
An implementation must be a data class
which contains read-only properties of the following types:
primitive types
String
enum
another
data class
with properties of the allowed typessealed abstract class
where all implementations satisfy these requirements
References between Entities
There are two ways to refer from one entity to another: using parent-child relationship (hard links) and via symbolic references (soft links).
Parent-Child Relationship
Some types of entities may be connected by "parent-child" relationship. It is introduced by a property in the parent entity interface which refers to the child entity (entities) with @Child
annotation, and a property in the child entity interface which refers to the parent entity. For example, content roots are defined inside a module in the project model, so ContentRootEntity
is defined as a child of ModuleEntity
.
The storage automatically maintains the consistency of this relationship during modifications:
if a parent entity is removed, all its child entities are also removed
if a child entity is removed, the corresponding property in its parent entity is updated so it no longer refers to the removed entity
The property referring to child entity may have a type
@Child ChildEntity?
indicating that there are zero or one child entities of the given typeList<@Child ChildEntity>
indicating that there are zero, one, or more child entities of the given type
The property referring to the parent entity may have a type
ParentEntity
indicating that the parent is mandatoryParentEntity?
indicating that the parent is optional
If the parent is optional, it is possible to create a child entity without the parent entity and set the reference to the parent entity to null
for an existing child entity. Also, if the reference to a child entity is removed from the corresponding property in the parent entity, it causes automatic removal of the child entity if it specifies that the parent is mandatory and sets the parent reference to null
if the parent is optional.
See the "Parent-child relationship between entities" section in WorkspaceEntity
code documentation for more details.
Symbolic References
If a configuration described by an entity refers to a configuration described by another entity, a symbolic reference may be used. It may happen that the referenced configuration doesn't exist: in that case the reference cannot be resolved.
To define a symbolic reference, the interface of the referenced entity must extend WorkspaceEntityWithSymbolicId
, provide an implementation of SymbolicEntityId
and return it from its symbolicId
property. The entity which refers to it must store an instance of that SymbolicEntityId
implementation in one of its properties.
For example, a module from the project model may depend on other modules. This is implemented by a property with the type ModuleId
which is stored inside ModuleDependencyItem
data class
stored in the ModuleEntity.dependencies
property.
The value of a property containing an implementation of SymbolicEntityId
is automatically updated if the symbolicId
property of the referenced entity changes after modification.