Class DefaultFeatureType

java.lang.Object
org.apache.sis.feature.AbstractIdentifiedType
org.apache.sis.feature.DefaultFeatureType
All Implemented Interfaces:
Serializable, FeatureType, Deprecable

public class DefaultFeatureType extends AbstractIdentifiedType implements FeatureType
Abstraction of a real-world phenomena. A FeatureType instance describes the class of all feature instances of that type.
Analogy: compared to the Java language, FeatureType is equivalent to Class while Feature instances are equivalent to Object instances of that class.
Warning: This class is expected to implement a GeoAPI FeatureType interface in a future version. When such interface will be available, most references to DefaultFeatureType in the API will be replaced by references to the FeatureType interface.

Naming

The feature type name is mandatory and should be unique. Those names are the main criterion used for deciding if a feature type is assignable from another type. Names can be scoped for avoiding name collision.

Properties and inheritance

Each feature type can provide descriptions for the following properties: In addition, a feature type can inherit the properties of one or more other feature types. Properties defined in the sub-type can override properties of the same name defined in the super-types, provided that values of the sub-type property are assignable to the super-type property.
Analogy: compared to the Java language, the above rule is similar to overriding a method with a more specific return type (a.k.a. covariant return type). This is also similar to Java arrays, which are implicitly covariant (i.e. String[] can be casted to CharSequence[], which is safe for read operations but not for write operations — the latter may throw ArrayStoreException).

Instantiation

DefaultFeatureType can be instantiated directly by a call to its constructor. But a more convenient approach may be to use the FeatureTypeBuilder instead, which provides shortcuts for frequently-used operations like creating various GenericName instances sharing the same namespace.

Immutability and thread safety

Instances of this class are immutable if all properties (GenericName and InternationalString instances) and all arguments (AttributeType instances) given to the constructor are also immutable. Such immutable instances can be shared by many objects and passed between threads without synchronization.
Since:
0.5
Version:
0.8
See Also:
  • Field Details

    • serialVersionUID

      private static final long serialVersionUID
      For cross-version compatibility.
      See Also:
    • isAbstract

      private final boolean isAbstract
      If true, the feature type acts as an abstract super-type.
      See Also:
    • isSimple

      private transient boolean isSimple
      true if this feature type contains only attributes with [1 … 1] multiplicity, or operations. The feature type shall not contains associations.
      See Also:
    • isSparse

      private transient boolean isSparse
      true if the feature instances are expected to have lot of unset properties, or false if we expect most properties to be specified.
    • isResolved

      private transient boolean isResolved
      true if we determined that this feature type does not have, directly or indirectly, any unresolved name (i.e. a DefaultAssociationRole.valueType specified only be the feature type name instead of its actual instance). A value of true means that all names have been resolved. However, a value of false only means that we are not sure, and that resolve(FeatureType, Map) should check again.
      Note: Strictly speaking, this field should be declared volatile since the names could be resolved late after construction, after the DefaultFeatureType instance became used by different threads. However, this is not the intended usage of deferred associations. Furthermore, a wrong value (false when it should be true) should only cause more computation than needed, without changing the result.
    • superTypes

      private final Set<DefaultFeatureType> superTypes
      The direct parents of this feature type, or an empty set if none.
      See Also:
    • assignableTo

      private transient Set<org.opengis.util.GenericName> assignableTo
      The names of all parents of this feature type, including parents of parents. This is used for a more efficient implementation of isAssignableFrom(DefaultFeatureType).
      See Also:
    • properties

      private final List<AbstractIdentifiedType> properties
      Any feature operation, any feature attribute type and any feature association role that carries characteristics of a feature type. This list does not include the properties inherited from the super-types.
      See Also:
    • allProperties

      private transient Collection<AbstractIdentifiedType> allProperties
      All properties, including the ones declared in the super-types. This is an unmodifiable view of the byName values.
      See Also:
    • byName

      private transient Map<String,AbstractIdentifiedType> byName
      A lookup table for fetching properties by name, including the properties from super-types. This map shall not be modified after construction.
      See Also:
    • indices

      private transient Map<String,Integer> indices
      Indices of properties in an array of properties similar to properties, but excluding operations. This map includes the properties from the super-types. Parameterless operations (to be handled in a special way) are identified by index -1. The size of this map may be smaller than the byName size. This map shall not be modified after construction.
    • OPERATION_INDEX

      static final Integer OPERATION_INDEX
      Value in indices map for parameterless operations. Those operations are not stored in feature instances, but can be handled as virtual attributes computed on-the-fly.
  • Constructor Details

  • Method Details

    • createName

      org.opengis.util.GenericName createName(org.opengis.util.NameFactory factory, String value)
      Creates a name from the given string. This method is invoked at construction time, so it should not use any field in this AbtractIdentifiedObject instance.
      Overrides:
      createName in class AbstractIdentifiedType
    • readObject

      private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
      Invoked on deserialization for restoring the byName and other transient fields.
      Parameters:
      in - the input stream from which to deserialize a feature type.
      Throws:
      IOException - if an I/O error occurred while reading or if the stream contains invalid data.
      ClassNotFoundException - if the class serialized on the stream is not on the classpath.
    • computeTransientFields

      private void computeTransientFields(List<AbstractIdentifiedType> properties)
      Computes transient fields (assignableTo, byName, indices, isSimple).

      As a side effect, this method checks for missing or duplicated names.

      Parameters:
      properties - same content as properties (may be the reference to the same list), but optionally in a temporarily modifiable list if we want to allow removal of duplicated values. See scanPropertiesFrom(FeatureType, Collection) javadoc for more explanation.
      Throws:
      IllegalArgumentException - if two properties have the same name.
    • scanPropertiesFrom

      private void scanPropertiesFrom(DefaultFeatureType source, Collection<? extends AbstractIdentifiedType> sourceProperties)
      Fills the byName map using the non-transient information in the given source. This method invokes itself recursively in order to use the information provided in super-types. This method also performs an opportunist verification of argument validity.

      this shall be the instance in process of being created, not any other instance (i.e. recursive method invocations are performed on the same this instance).

      This method requires that the caller gives source.getProperties(false) himself for two reasons:

      • Avoid a call to the user-overrideable getProperties(boolean) method while this DefaultFeatureType instance is still under constructor.
      • Allow the DefaultFeatureType(Map, boolean, FeatureType[], PropertyType[]) constructor to pass a temporary modifiable list that allow element removal.
      Parameters:
      source - the feature from which to get properties.
      sourceProperties - source.getProperties(false) (see above method javadoc).
      Throws:
      IllegalArgumentException - if two properties have the same name.
    • ownerOf

      private static org.opengis.util.GenericName ownerOf(DefaultFeatureType type, Collection<? extends AbstractIdentifiedType> properties, AbstractIdentifiedType toSearch)
      Returns the name of the feature which defines the given property, or null if not found. This method is for information purpose when producing an error message - its implementation does not need to be efficient.

      API note: a non-static method would be more elegant in this "SIS for GeoAPI 3.0" branch. However this method needs to be static in other SIS branches, because they work with interfaces rather than SIS implementation. We keep the method static in this branch too for easier merges.

    • resolve

      private boolean resolve(DefaultFeatureType feature, Map<FeatureType,Boolean> previous)
      If an associated feature type is a placeholder for a FeatureType to be defined later, replaces the placeholder by the actual instance if available. Otherwise do nothing.

      This method is needed only in case of cyclic graph, e.g. feature A has an association to feature B which has an association back to A. It may also be A having an association to itself, etc.

      this shall be the instance in process of being created, not other instance (i.e. recursive method invocations are performed on the same this instance).

      Parameters:
      feature - the feature type for which to resolve the properties.
      previous - previous results, for avoiding never ending loop.
      Returns:
      true if all names have been resolved.
    • resolve

      private boolean resolve(DefaultFeatureType feature, Collection<? extends AbstractIdentifiedType> toUpdate, Map<FeatureType,Boolean> previous, boolean resolved)
      Implementation of resolve(FeatureType, Map), also to be invoked from the constructor.

      this shall be the instance in process of being created, not other instance (i.e. recursive method invocations are performed on the same this instance).

      Parameters:
      feature - the feature type for which to resolve the properties.
      toUpdate - feature.getProperties(false), which may contain the associations to update.
      previous - previous results, for avoiding never ending loop. Initially null.
      resolved - true if we already know that all names are resolved.
      Returns:
      true if all names have been resolved.
    • isParameterlessOperation

      static boolean isParameterlessOperation(AbstractIdentifiedType type)
      Returns true if the given property type stands for a parameterless operation which return a result.
      See Also:
    • isAbstract

      public final boolean isAbstract()
      Returns true if the feature type acts as an abstract super-type. Abstract types cannot be instantiated.
      Returns:
      true if the feature type acts as an abstract super-type.
    • isSparse

      final boolean isSparse()
      Returns true if the feature instances are expected to have lot of unset properties, or false if we expect most properties to be specified.
    • isSimple

      public boolean isSimple()
      Returns true if this feature type contains only attributes with [1 … 1] multiplicity, or operations (no feature association). Such feature types can be handled as a records.
      Returns:
      true if this feature type contains only simple attributes or operations.
    • maybeAssignableFrom

      static boolean maybeAssignableFrom(DefaultFeatureType base, DefaultFeatureType type)
      Returns true if the given base type may be the same or a super-type of the given type, using only the name as a criterion. This is a faster check than isAssignableFrom(DefaultFeatureType).

      Performance note: callers should verify that base != type before to invoke this method.

      API note: a non-static method would be more elegant in this "SIS for GeoAPI 3.0" branch. However this method needs to be static in other SIS branches, because they work with interfaces rather than SIS implementation. We keep the method static in this branch too for easier merges.

    • isAssignableFrom

      public boolean isAssignableFrom(DefaultFeatureType type)
      Returns true if this type is same or a super-type of the given type. The check is based mainly on the feature type name, which should be unique. However, as a safety, this method also checks that all properties in this feature type is assignable from a property of the same name in the given type.

      Constraints

      • If A is assignable from B and B is assignable from C, then A is assignable from C.
      Analogy: if we compare FeatureType to Class in the Java language, then this method is equivalent to Class.isAssignableFrom(Class).
      Specified by:
      isAssignableFrom in interface FeatureType
      Parameters:
      type - the type to be checked.
      Returns:
      true if instances of the given type can be assigned to association of this type.
    • isAssignableIgnoreName

      private static boolean isAssignableIgnoreName(AbstractIdentifiedType base, AbstractIdentifiedType other)
      Returns true if instances of the other type are assignable to the given base type. This method does not compare the names — this verification is presumed already done by the caller.
    • getSuperTypes

      public final Set<DefaultFeatureType> getSuperTypes()
      Returns the direct parents of this feature type.
      Analogy: if we compare FeatureType to Class in the Java language, then this method is equivalent to Class.getSuperclass() except that feature types allow multi-inheritance.
      Warning: The type of list elements will be changed to FeatureType if and when such interface will be defined in GeoAPI.
      Note for subclasses: this method is final because it is invoked (indirectly) by constructors, and invoking a user-overrideable method at construction time is not recommended. Furthermore, many Apache SIS methods need guarantees about the stability of this collection.
      Returns:
      the parents of this feature type, or an empty set if none.
    • getProperties

      public Collection<AbstractIdentifiedType> getProperties(boolean includeSuperTypes)
      Returns any feature operation, any feature attribute type and any feature association role that carries characteristics of a feature type. The returned collection will include the properties inherited from the super-types only if includeSuperTypes is true.
      Warning: The type of list elements will be changed to PropertyType if and when such interface will be defined in GeoAPI.
      Specified by:
      getProperties in interface FeatureType
      Parameters:
      includeSuperTypes - true for including the properties inherited from the super-types, or false for returning only the properties defined explicitly in this type.
      Returns:
      feature operation, attribute type and association role that carries characteristics of this feature type (not including parent types).
    • getProperty

      public AbstractIdentifiedType getProperty(String name) throws IllegalArgumentException
      Returns the attribute, operation or association role for the given name.
      Warning: The type of returned element will be changed to PropertyType if and when such interface will be defined in GeoAPI.
      Parameters:
      name - the name of the property to search.
      Returns:
      the property for the given name, or null if none.
      Throws:
      IllegalArgumentException - if the given argument is not a property name of this feature.
      See Also:
    • indices

      final Map<String,Integer> indices()
      Returns the map from names to indices in an array of properties. This is used for DenseFeature implementation.
    • newInstance

      public AbstractFeature newInstance() throws IllegalStateException
      Creates a new feature instance of this type.
      Analogy: if we compare FeatureType to Class and Feature to Object in the Java language, then this method is equivalent to Class.newInstance().
      Returns:
      a new feature instance.
      Throws:
      IllegalStateException - if this feature type is abstract.
    • hashCode

      public int hashCode()
      Returns a hash code value for this feature type.
      Overrides:
      hashCode in class AbstractIdentifiedType
      Returns:
      the hash code for this type.
    • equals

      public boolean equals(Object obj)
      Compares this feature type with the given object for equality.
      Overrides:
      equals in class AbstractIdentifiedType
      Parameters:
      obj - the object to compare with this type.
      Returns:
      true if the given object is equal to this type.
    • toString

      public String toString()
      Formats this feature in a tabular format.
      Overrides:
      toString in class Object
      Returns:
      a string representation of this feature in a tabular format.
      See Also: