Represents a feature of arbitrary complexity.
This interface answers the question: How do we store feature attributes?
(The answer to the more useful question, How do we access feature attribute,
is contained in the Expression class.
Warning: We are revising the Feature Model to be more complete in the
next round of GeoTools. If you do any data access in your classes please try
and make use of Expression to access your information, if you do this you will
not be affected by the change (beyond a few search and replace operations).
The most generic approach would be to pass all feature attributes as objects
and use Java variable and method references to access them. However, this is
also the most useless approach because it establishes no unified methods for getting
attribute information (since it is totally Object dependent), without
elaborate reflection/introspection, which is inconvenient to use. Unlike
its
FeatureType counterpart, this interface does not attempt to
serve as a typing framework. Rather, multiple implementations of this
interface should generally be for performance reasons.
This interface serves two important purposes. Most obviously, it gives
users of features a unified, consistent framework for accessing and
manipulating feature data. Perhaps more importantly, the
FeatureType
and Feature
interfaces also work
together to give implementers a framework for constraining and enforcing
constraints (respectively) on allowed feature types. As such, this
interface is as general as possible in terms of the types of objects to
which it provides access. Keep in mind that creating new features is
relatively difficult and should only be done to optimize performance for
highly constrained schema types. For the vast majority of schemas, the
generic feature implementation will work fine.
Notes for Feature Clients:
Clients should always use feature accessor methods (getAttribute and
setAttribute) to modify the state of internal attribute objects. It is
possible that some feature implementations will allow object state changes
by clients outside of the class, but this is strongly discouraged. In
general, feature implementations will make defensive copies of objects
passed to clients and it is therefore not guaranteed that client state
changes that take place outside of the feature will be reflected in the
internal state of the feature object! For this reason, clients should
always use the set methods to change feature attribute object states!
Notes for Feature Implementers:
It is the responsibility of the implementing class to ensure that the
Feature
attributes stay synchronized with its FeatureType
definition. Features should never get out of synch with their declared
schemas and should never alter their schemas! There are four
conventions of which implementers of this interface must be aware in order
to successfully manage a Feature
:
-
FeatureType Reference
Features must always hold a single (immutable: see
FeatureType
) schema reference and this reference should not be
altered after a feature has been created. To ensure this, is is strongly
recommended that features take a valid reference to an existing immutable
schema in its constructor and declare that reference final.
-
Default Geometry
Each feature must have a default geometry, but this primary geometry may be
null. This means that a feature may contain no geometries, but it must
always have a method for accessing a geometry object (even if it is null).
It also means that a feature with multiple geometries must pick one as its
default geometry. Note that the designation of the default geometry is
stored as part of the FeatureType
and is therefore immmutable.
-
Attributes
All features contain zero or more attributes, which
can have one or more occurrences inside the feature. Attributes may be any
valid Java object. If attributes are instances of Feature
,
they are handled specially by the Feature
methods, in that
their attributes may be accessed directly by their containing feature. All
other object variables and methods must be accessed through the objects
themselves. It is up to implementers of Feature
to make sure
that each attribute value conforms to its internal schema. A feature
should never reach a state where its attributes (or sub-attributes) do not
conform to their FeatureType
definitions. There are three
ways to implement this. The first is to simply make features immutable;
however, given the ubiquity and required flexibility of features, this is
likely not possible. The second (and second easiest), is to make all
feature attributes immutable. For most cases, this is probably the best way
to handle this issue. The third way, is to never give out a reference that
would allow a client to change an attribute object's class (most obviously,
an array reference). Generally speaking, features should attempt to
minimize external object references by attempting to clone incoming
attributes before adding them and outgoing attributes before sending them.
For features with non-cloneable attributes, of course, this is not
possible, so this is left to the discretion of the implementor.
-
Constructors
Constructors should take arguments with enough
information to create a valid representation of the feature. They should
also always include a valid schema that can be used to check the proposed
attributes. This is necessary to ensure that the feature is always in a
valid state, relative to its schema.
-
hashCode() and equals(Object other)
Determining equality and equivalence for Feature instances is of utmost
importance. This must be done in a constistent manner, as many other areas
of geotools will rely on these relations. See java.lang.Object for details.