2

I'm using Geotools 14.0 for Java and I'm trying to generate shapefile based on data from GeoJSON. Here is my code:

try {
        String url = "geojson.json";
        File geojson = new File(url);

        File shpFile = new File("test.shp");
        ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();

        Map<String, Serializable> params = new HashMap<String, Serializable>();
        params.put("url", shpFile.toURI().toURL());
        params.put("create spatial index", Boolean.TRUE);

        ShapefileDataStore shpDataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);

        InputStream in = new FileInputStream(geojson);
        int decimals = 15;
        GeometryJSON gjson = new GeometryJSON(decimals);
        FeatureJSON fjson = new FeatureJSON(gjson);

        FeatureCollection<SimpleFeatureType, SimpleFeature> fc = fjson.readFeatureCollection(in);

        SimpleFeatureType type = (SimpleFeatureType) fc.getSchema();

        shpDataStore.createSchema(type);
        Transaction transaction = new DefaultTransaction("create");

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

        SimpleFeatureSource featureSource = shpDataStore.getFeatureSource(typeName);

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

            featureStore.setTransaction(transaction);
            try {

                featureStore.addFeatures(fc);
                for(Object c : featureStore.getFeatures().toArray()){
                    System.out.println("C: " + ((SimpleFeatureImpl)c).toString());
                }
                transaction.commit();                    
            } catch (Exception ex) {
                ex.printStackTrace();
                transaction.rollback();

            } finally {
                transaction.close();
            }
        } else {
            System.out.println(typeName + " does not support read/write access");
        }
    } catch (Exception e) {
        return "Exception " + e.getLocalizedMessage();
    }

And after this, i get test.shp file but it does not contain any geometry data. If I convert it back to geojson I get this:

{   "type": "Feature",   "properties": {   },   "id": "test.1" }

And this is my original geojson file (geojson.json):

{
  "type": "FeatureCollection",
  "features": [
    {
      "properties": {
        "version": 0
      },
      "id": "1",
      "type": "Feature",
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              1868732.467515988,
              6594375.3042187244
            ],
            [
              1868732.467515988,
              5165920.1196253505
            ],
            [
              3297187.6521093622,
              5165920.1196253505
            ],
            [
              3297187.6521093622,
              6594375.3042187244
            ],
            [
              1868732.467515988,
              6594375.3042187244
            ]
          ]
        ]
      }
    }
  ]       }

Is there any way to do this in a proper way?

  • what happens if you rename your geometry to the_geom ? – Ian Turton Oct 6 '15 at 12:41
  • what do you mean? where could I rename it, in the geojson.json file or somewhere else? – Jasmin Oct 6 '15 at 13:01
  • in the json file – Ian Turton Oct 6 '15 at 13:01
  • I tried that and then I got null pointer exception on shpDataStore.createSchema(type); – Jasmin Oct 6 '15 at 13:04
  • OK I'll see if I can find time to test later – Ian Turton Oct 6 '15 at 13:04
4

Short answer: Your feature type doesn't match the Shapefile standard so the illegal bits get dropped by GeoTools. I have a utility class to fix this -

try {
        String url = "geojson.json";
        File geojson = new File(url);

        File shpFile = new File("test.shp");
        ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();

        Map<String, Serializable> params = new HashMap<String, Serializable>();
        params.put("url", shpFile.toURI().toURL());
        params.put("create spatial index", Boolean.TRUE);

        /*
         * ShapefileDataStore shpDataStore = (ShapefileDataStore)
         * dataStoreFactory.createNewDataStore(params);
         */
        InputStream in = new FileInputStream(geojson);
        int decimals = 15;
        GeometryJSON gjson = new GeometryJSON(decimals);
        FeatureJSON fjson = new FeatureJSON(gjson);

        FeatureCollection<SimpleFeatureType, SimpleFeature> fc = fjson.readFeatureCollection(in);
        fc.getSchema();

        WriteShapefile writer = new WriteShapefile(shpFile);
        writer.writeFeatures(fc);
    } catch (Exception e) {
        e.printStackTrace();

        // return "Exception " + e.getLocalizedMessage();
    }

Long answer: Shapefiles suck as a format! The first attribute in every feature must be the geometry and it must be called the_geom (hence my earlier suggestion to change the name of your geometry attribute). As featuretypes are immutable in GeoTools it is necessary to loop through the attributes and rename the geometry and then move it to first place while creating a new schema. DataUtilities.retype will reorder the attributes to match the new schema but as the geometry has changed name you have to copy the yourself. Then you can write the shapefile out as normal.

  • It works now. Thank you very much, I didn't know these things about attribute ordering - I had no idea that SHP is that strict about that. – Jasmin Oct 8 '15 at 8:31
  • Feel free to upvote the answer if it helped you – Ian Turton Oct 8 '15 at 8:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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