Feature

This page consists of a series of code examples showing how to do common tasks with the GeoTools feature model.

Reference:

Build a Feature Type

Since FeatureType is immutable you will often see them used as constants as shown in the following examples:

Simple case:

SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();

//set the name
b.setName( "Flag" );

//add some properties
b.add( "name", String.class );
b.add( "classification", Integer.class );
b.add( "height", Double.class );

//add a geometry property
b.setCRS( DefaultGeographicCRS.WSG84 ); // set crs first
b.add( "location", Point.class ); // then add geometry

//build the type
final SimpleFeatureType FLAG = b.buildFeatureType();

Alternative chaining:

SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
SimpleFeatureType type;

// you can chain builder methods
final SimpleFeatureType FLAG =
       b.name("Flag").add("name", String.class ).
       add( "classification", Integer.class ).add( "height", Double.class ).
       crs( DefaultGeographicCRS.WSG84 ).add( "location", Point.class ).buildFeatureType();

Include namespace information:

// you can set a namespace
b.setNamespaceURI( "http://geotools.org/example" );

Geometry Type

Multiple geometries (with implicit default geometry):

b.setCRS( DefaultGeographicCRS.WSG84 );

//add some geometry properties (first added is the default)
b.add( "region", Polygon.class );
b.add( "hub", Point.class );
b.add( "network", MultiLineString.class );

Multiple geometries with explicit default geometry:

b.setCRS( DefaultGeographicCRS.WSG84 );

b.add( "hub", Point.class );
b.add( "region", Polygon.class );
b.add( "network", MultiLineString.class );

//set the default geometry
b.setDefaultGeometry( "region" ):

CRS for geometries:

CoordinateReferenceSystem crs = CRS.decode("EPSG:4326");

//set the coordinate reference system
b.setCRS( crs );

// when geometry properties are added they will use the crs set above
b.add( "position", Point.class );
b.add( "route", LineString.class );

Alternative: Unknown CRS:

b.setCRS( null );
b.add( "position", Point.class );
b.add( "route", LineString.class );

Multiple CRS for Geometries:

CoordinateReferenceSystem crs1 = CRS.decode("EPSG:3005");
CoordinateReferenceSystem crs2 = DefaultGeographicCRS.WSG84;

b.setCRS( crs1 );
b.add( "local", Point.class );

b.setCRS( crs2 );
b.add( "world", Point.class );

Alternative: Chaining:

CoordinateReferenceSystem crs1 = CRS.decode("EPSG:3005");
CoordinateReferenceSystem crs2 = DefaultGeographicCRS.WSG84;

b.crs( crs1 ).add( "local", Point.class );
b.crs( crs2 ).add( "world", Point.class );

Alternative: Using an CRS:

b.srs( "EPSG:3005" ).add( "local", Point.class );
b.srs( "EPSG:4326" ).add( "world", Point.class );

Attribute Descriptor

Simple Case:

AttributeTypeBuilder build = new AttributeTypeBuilder();
build.setNillable(true);
build.setBinding(String.class);

AttributeDescriptor descriptor = build.buildDescriptor( "name" );

Alternative: With Explicit Attribute Type:

AttributeTypeBuilder build = new AttributeTypeBuilder();
build.setNillable(true);
build.setBinding(String.class);
build.setName("Text");

AttributeType textType = build.buildType();
AttributeDescriptor descriptor = build.buildDescriptor( "name", textType );

Building a Geometry Descriptor:

build.setNillable(true);
build.setCRS(crs);
build.setBinding(Polygon.class);

GeometryType geometryType = build.buildGeometryType();
GeometryDescriptor build.buildDescriptor( "the_geom",   geometryType ) );

Building a Geometry Descriptor with Limited Length:

AttributeTypeBuilder build = new AttributeTypeBuilder();
build.setNillable(true);
build.setBinding(String.class);
build.setLength(15);
AttributeDescriptor descriptor = build.buildDescriptor( "username" );

Name

Creating a specific name:

Name roadName = new NameImpl("http://localhost/","Road");

Creating a global name:

Name roadName = new NameImpl(null,"Road");

DataUtilities

DataUtilities has a method that you can use to quickly create a FeatureType for test cases:

final SimpleFeatureType FLAG = DataUtilities.createType("Flag","Location:Point,Name:String");

You can define the Coordinate Reference System using the following (authority is optional, should be specified if it’s not EPSG):

SimpleFeatureType FLAG = DataUtilities.createType("Flags","geom:MultiPoint:srid=4326,Name:String");
SimpleFeatureType FLAG_IAU = DataUtilities.createType("Flags","geom:Point:authority:IAU;srid=49900,Name:String");

You can also ask for the String representation of a FeatureType:

System.out.println( DataUtilities.spec( FLAG ) );

For more information see DataUtilities.

FeatureFactory

You can also use FeatureFactory directly; this is advised when building nested features (as we only have a SimpleFeatureTypeBuilder at present).

Using a TypeFactory:

TypeFactory typeFactory = CommonFactoryFinder.getTypeFactory( null );
SimpleTypeFactory featureTypeFactory =   CommonFactoryFinder.getSimpleTypeFeatureFactory( null );

URI namespace = new URI("http://localhost/Flag/");
CoordinateReferenceSystem crs = CRS.decode("EPSG:4326");

Name locationName = new NameImpl( namespace, "Location" );
InternationalString locationDescription = new SimpleInternationalString("Location of the base of this Flag, in WSG84");
GeometryAttributeType GEOM = typeFactory.createGeometryType( locationName, Point.class, crs, false, false, null, null, locationDescription );

Name idName = new NameImpl( namespace, "Id" );
AttributeType ID = typeFactory.createAttributeType( idName, Integer.class, false, false, null, null, null );

Name locationName = new NameImpl( namespace, "Name" );
AttributeType NAME = typeFactory.createAttributeType( nameName, String.class, false, false, null, null, null );

Name name = new NameImpl( new URI("http://localhost/"), "Flag" );
InternationalString description = new SimpleInternationalString("A Flag used to place a marker on the world");

AttributeDescriptor defaultGeoemtry = typeFactory.createAttributeDescriptor(GEOM, geomName, 1, 1, true, null );

List<AttributeDescriptor> types = new ArrayList<AttributeDescriptor>();
types.add( defaultGeometry );
types.add( typeFactory.createAttributeDescriptor(ID, idName, 1, 1, false, Integer.valueOf(0) ) );
types.add( typeFactory.createAttributeDescriptor(NAME, nameName, 1, 1, true, null ) );

final FeatureType FLAG = featureTypeFactory.createSimpleFeatureType( name, types, defaultGeometry, crs, Collections.EMPTY_SET, description );

As you can see we usually recommend SimpleFeatureTypeBuilder as it provides assistance with the above work for you.

Build a Feature

Simple Case:

//the type, schema = ( name:String, classification:Integer, height:Double, location:Point)
SimpleFeatureType type = ...;

//create the builder
SimpleFeatureBuilder builder = new SimpleFeatureBuilder(type);

//add the values
builder.add( "Canada" );
builder.add( 1 );
builder.add( 20.5 );
builder.add( new Point( -124, 52 ) );

//build the feature with provided ID
SimpleFeature feature = builder.buildFeature( "fid.1" );

Alternative array of values provided in order:

Object[] values = new Object[]{
  "Canada", 1, 20.5, new Point( -124, 52  )
};
builder.addAll( values );

Alternative list of values provided in order:

ArrayList<Object> values = new ArrayList<Object>( 4 );
values.add("Canada");
values.add( 1 );
values.add( 20.5 );
values.add( new Point( -124, 52  ) );
builder.addAll( list );

Alternative setting by Name:

builder.set( "name", "Canada" );
builder.set( "classification", 1 );
builder.set( "height", 20.5 );
builder.set( "location", new Point( -124, 52  ) );

Alternative setting by index:

builder.set( 0, "Canada" );
builder.set( 1, 1 );
builder.set( 2 20.5 );
builder.set( 3, new Point( -124, 52  ) );

DataUtilities

DataUtilities has some utility methods that will create a “template” feature with sensible default values filled in based on the FeatureType.

For more information see DataUtilities.

FeatureFactory

Once again we will ask you to use FilterFactory directly if you are building up a Feature by hand.

Accessing

Direct access to values:

SimpleFeature feature = ...see above...;

for (Object value : feature.getAttributes() ) {
  System.out.print( value ",");
}
// prints Canada,1,20.5,POINT( -124, 52 ),

Access values using index:

for (int i = 0; i < feature.getAttributeCount(); i++ ) {
  Object value = feature.getAttribute( i );
  System.out.print( value ",");
}
// prints Canada,1,20.5,POINT( -124, 52 ),

Access values using Name:

for (Property property : feature.getProperties()) {
  String name = property.getName();
  Object value = feature.getAttribute( property.getName() );
  System.out.print( name+"="+value+"," );
}
// prints name=Canada,classification=1,height=20.5,location=POINT( -124, 52 ),

Property

Property access:

Property property = feature.getProperty( "name" );
String name = property.getName();
Object value = property.getValue();

Property access using Index:

Property property = feature.getProperty( 2 );
String name = property.getName();
Object value = property.getValue();

Geometry

Geometry value access:

Point point = (Point) feature.getDefaultGeometry();

Geometry value access as value:

Point point = (Point) feature.getAttribute( "location" );

Geometry value access as property:

GeometryAttribute geom = feature.getDefaultGeometryProperty();

String name = geom.getName();
Point point = (Point) geom.getValue();
CoordinateReferenceSystem crs = geom.getCRS();
BoundingBox bounds = geom.getBounds();

Geometry value access using name:

GeometryAttribute geom = (GeometryAttribute) feature.getProperty("location");

CoordinateReferenceSystem crs = geom.getCRS();
BoundingBox bounds = geom.getBounds();
Geometry point = (Geometry) theGeom.getValue();

Coordinate Reference System

CoordinateReferenceSystem access:

// Access the CRS of getDefaultGeometryProperty()
CoordinateReferenceSystem crs = feature.getCRS();

CoordinateReferenceSystem of default geometry property:

CoordinateReferenceSystem crs =
     feature.getDefaultGeometryProperty() == null ? null : feature.getDefaultGeometryProperty().getCRS();

CoordinateReferenceSystem of named Property:

GeometryAttribute location = (GeometryAttribute) feature.getProperty( "location" );
CoordinateReferenceSystem bounds = location.getCRS();

BoundingBox

BoundingBox access:

// Access the BoundingBox of getDefaultGeometryProperty()
BoundingBox bounds = feature.getBounds();

BoundingBox of getDefaultGeometryProperty():

BoundingBox bounds =
     feature.getDefaultGeometryProperty() == null ? null : feature.getDefaultGeometryProperty().getBounds();

BoundingBox of named Property:

GeometryAttribute location = (GeometryAttribute) feature.getProperty( "location" );
BoundingBox bounds = location.getBounds();

Name

Name access:

// can access both parts of a name - similar to XML QName
String localName = name.getLocalPart();
String namespace = name.getNamespaceURI(); // Note a String

Check if name is global:

name.isGlobal(); // true! name.getNamespaceURI() == null

Name comparison:

Name name1 = new Name( "gopher://localhost/example", "name" );
Name name2 = new Name( "gopher://localhost", "example/name" );

name1.equals( name2 ); // true they both represent gopher://localhost/example/name

Validation

Validating a feature:

for (PropertyDescriptor property : feature.getType().getAttributes() )) {
   Object value = feature.getAttribute( property.getName() );

   Types.validate( property, value );
}

Checking Super Types by Hand:

SimpleFeature feature = ...;

for (PropertyDescriptor property : feature.getType().getAttributes() )) {
  PropertyType propertyType = property.getType();
  Object value = feature.getAttribute( property.getName() );

  if( value == null ){
     //check nillability
     if ( property.isNillable() ){
        continue;
     }
     else {
        throw new Exception( "value can not be null" );
     }
  }
  //check the type
  if ( type.getBinding().isAssignableFrom( value.getClass() ) ) {
    throw new Exception( "value not same type as binding" );
  }
  // check restrictions for this propertyType and all super types
  for(PropertyType type=propertyType; type !=null; type=propertyType.getSuper() ){
     for( Filter valid : type.getRestrictions() ){
          if( !valid.evaulate( value ) ){
              throw new Exception(
                  "Not a valid "+type.getName()+" values must be:"+valid
               );
          }
     }
  }
}