4

As you know, the geometry column name of schema for saving into a shapefile must be "the_geom". I have a SimpleFeatureCollection with a schema, geometry name of which is not "the_geom"; It is "geometry". I want to save this collection into an esri shapefile. But I loose geoemetries when storing.

Attribute table before save:

|  FeatureIdentifier  | name | people |     geometry     |
----------------------------------------------------------
| jahan_0             | ali  | 23     | POINT(67.0 35.0) |
| jahan_1             | gh   | 245    | POINT(67.2 34.4) |
 ---------------------------------------------------------

Attribute table after reading shapefile:

|  FeatureIdentifier  | the_geom | name | people |
--------------------------------------------------
| mesal_0             |          | ali  | 23     |
| mesal_1             |          | gh   | 245    | 
 -------------------------------------------------

How can I save my feature collection into shapefile without loosing geometries? The problem is on storing. I tested the saved shp file by QGIS and saw geometries lost.


more code on saving shapefile:

DataStore dataStore = ...; // shapefile data store
// My FeatureCollection containing two features
SimpleFeatureCollection collection = ...; 
dataStore.createSchema(schema);
String typeName = dataStore.getTypeNames()[0];
SimpleFeatureSource fs = dataStore.getFeatureSource(typeName);
MyUtil.saveToFeatureStore(collection,(FeatureStore) fs);

MyUtil.java:

public class MyUtil{
  public static void saveToFeatureStore(SimpleFeatureCollection collection, FeatureStore featureStore){
    Transaction tx = new DefaultTransaction("create");
    featureStore.setTransaction(tx);
    try{
      featureStore.addFeatures(collection);
      tx.commit();
    } catch(Exception ex){
      tx.rollback();
    } finally{
      tx.close();
    }
  }
}

My problem is: How to save features into shapefile by GeoTools. There is no question about storing features by GeoTools at this site.

1

1 Answer 1

3

As you surmise you need to change the schema. As schema are immutable you need to copy the existing schema into a new one changing the name of the geometry attribute.

You will need something like:

public boolean writeFeatures(
        FeatureCollection<SimpleFeatureType, SimpleFeature> features) {

    if (shpDataStore == null) {
        throw new IllegalStateException(
                "Datastore can not be null when writing");
    }
    SimpleFeatureType schema = features.getSchema();
    GeometryDescriptor geom = schema
            .getGeometryDescriptor();

    try {

        /*
         * Write the features to the shapefile
         */
        Transaction transaction = new DefaultTransaction(
                "create");

        String typeName = shpDataStore.getTypeNames()[0];
        SimpleFeatureSource featureSource = shpDataStore
                .getFeatureSource(typeName);

        /*
         * The Shapefile format has a couple limitations: - "the_geom" is always
         * first, and used for the geometry attribute name - "the_geom" must be of
         * type Point, MultiPoint, MuiltiLineString, MultiPolygon - Attribute
         * names are limited in length - Not all data types are supported (example
         * Timestamp represented as Date)
         *
         * Because of this we have to rename the geometry element and then rebuild
         * the features to make sure that it is the first attribute.
         */

        List<AttributeDescriptor> attributes = schema
                .getAttributeDescriptors();
        GeometryType geomType = null;
        List<AttributeDescriptor> attribs = new ArrayList<AttributeDescriptor>();
        for (AttributeDescriptor attrib : attributes) {
            AttributeType type = attrib.getType();
            if (type instanceof GeometryType) {
                geomType = (GeometryType) type;

            } else {
                attribs.add(attrib);
            }
        }

        GeometryTypeImpl gt = new GeometryTypeImpl(
                new NameImpl("the_geom"), geomType.getBinding(),
                geomType.getCoordinateReferenceSystem(),
                geomType.isIdentified(), geomType.isAbstract(),
                geomType.getRestrictions(), geomType.getSuper(),
                geomType.getDescription());

        GeometryDescriptor geomDesc = new GeometryDescriptorImpl(
                gt, new NameImpl("the_geom"),
                geom.getMinOccurs(), geom.getMaxOccurs(),
                geom.isNillable(), geom.getDefaultValue());

        attribs.add(0, geomDesc);

        SimpleFeatureType shpType = new SimpleFeatureTypeImpl(
                schema.getName(), attribs, geomDesc,
                schema.isAbstract(), schema.getRestrictions(),
                schema.getSuper(), schema.getDescription());


        shpDataStore.createSchema(shpType);

        if (featureSource instanceof SimpleFeatureStore) {
            SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;

            List<SimpleFeature> feats = new ArrayList<SimpleFeature>();

            FeatureIterator<SimpleFeature> features2 = features
                    .features();
            while (features2.hasNext()) {
                SimpleFeature f = features2.next();
                SimpleFeature reType = SimpleFeatureBuilder
                        .build(shpType, f.getAttributes(), "");

                feats.add(reType);
            }
            features2.close();
            SimpleFeatureCollection collection = new ListFeatureCollection(
                    shpType, feats);

            featureStore.setTransaction(transaction);
            try {
                List<FeatureId> ids = featureStore
                        .addFeatures(collection);
                transaction.commit();
            } catch (Exception problem) {
                problem.printStackTrace();
                transaction.rollback();
            } finally {
                transaction.close();
            }
            shpDataStore.dispose();
            return true;
        } else {
            shpDataStore.dispose();
            System.err.println("ShapefileStore not writable");
            return false;
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return false;
}

There is a full working example at https://github.com/ianturton/geotools-cookbook/tree/master/modules/output/src/main/java/org/ianturton/cookbook/output (including the pom file to sort out the dependencies)

4
  • Thanks iant. Do you confirm this question is not duplicate ?
    – Dariush
    Commented Aug 10, 2015 at 14:57
  • it's sort of a duplicate of stackoverflow.com/questions/26935862/… which is where I copied my answer from. But it's distinct enough that I'll leave it open
    – Ian Turton
    Commented Aug 10, 2015 at 14:59
  • GeoTools should have some utilities performing these tasks. A function like prepareSchemaForShapefile
    – Dariush
    Commented Aug 10, 2015 at 15:00
  • why? It's just one broken format that we'd all like to drop. Feel free to add a PR though
    – Ian Turton
    Commented Aug 10, 2015 at 15:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.