1

I am implementing a web service in Java which takes a GeoJSON file as input and converts it into a shapefile. My code looks something like this :-

@RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
      public String submit(@RequestParam("file") MultipartFile file, ModelMap modelMap) throws IOException {
          modelMap.addAttribute("file", file);
          File ew = convert(file);
//        String[] cmd = {"-t_srs", "CRS:84", "-f", "GeoJSON","[name].geojson","[name].shp"};
//        ogr2ogr.main(cmd);
          toShp(ew);
          return "fileUploadView"; // ignore this return statement
      }
      public File convert(MultipartFile file) throws IOException
      {    
          File convFile = new File("D:\\Gauravmmi\\0projects\\sample.GeoJSON");
          convFile.createNewFile(); 
          FileOutputStream fos = new FileOutputStream(convFile); 
          fos.write(file.getBytes());
          fos.close(); 
          return convFile;
      }

            public static void toShp(File geojson) throws IOException {     
                File shpFile = new File("D:\\Gauravmmi\\0projects\\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);
        /*
         * 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);
         */   
                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 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);

                        transaction.commit();

                    } catch (Exception ex) {
                        ex.printStackTrace();
                        transaction.rollback();

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


              }

And my sample GeoJSON looks something like this:-

  {
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {},
      "geometry": {   // no luck changing this to "the_geom"
        "type": "LineString",
        "coordinates": [
          [
            72.99316406249999,
            27.449790329784214
          ],
          [
            78.134765625,
            27.68352808378776
          ],
          [
            77.5634765625,
            26.15543796871355
          ],
          [
            83.8037109375,
            24.806681353851964
          ],
          [
            84.111328125,
            26.82407078047018
          ],
          [
            86.2646484375,
            25.045792240303445
          ],
          [
            86.17675781249999,
            22.998851594142913
          ],
          [
            82.001953125,
            19.80805412808859
          ],
          [
            77.82714843749999,
            19.062117883514652
          ],
          [
            76.1572265625,
            16.25686733062344
          ],
          [
            77.2119140625,
            13.539200668930816
          ],
          [
            75.3662109375,
            14.43468021529728
          ],
          [
            74.970703125,
            17.476432197195518
          ],
          [
            75.05859375,
            19.766703551716976
          ],
          [
            73.47656249999999,
            21.248422235627014
          ],
          [
            71.5869140625,
            22.59372606392931
          ],
          [
            71.89453125,
            24.086589258228027
          ],
          [
            72.8173828125,
            26.902476886279832
          ],
          [
            74.92675781249999,
            22.998851594142913
          ],
          [
            75.8056640625,
            25.085598897064752
          ],
          [
            71.7462158203125,
            27.415662034561
          ],
          [
            73.531494140625,
            28.134971934813155
          ],
          [
            73.0206298828125,
            27.42053815128712
          ],
          [
            74.619140625,
            27.761329874505233
          ],
          [
            74.59167480468749,
            27.49365405370312
          ]
        ]
      }
    }
  ]
}

When I am running the sample GeoJSON through the controller I am getting five files in output (test.dbf,test.fix,test.prj,test.shp.test.shx) where test.prj contains nothing. And so when I import this shapefile in QGIS I get nothing?

1 Answer 1

1

There are a number of issues in your code:

  1. You never set the projection of your features so test.prj will be empty. It would be better to use the gt-geojsondatastore module to handle the GeoJSON import as it takes care of this for you.

  2. The geometry attribute of a Shapefile must be called the_geom and you don't set this so QGis (and other GIS) can't find a geometry to be displayed.

Here is some code to do this:

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.geotools.data.DataStore;
import org.geotools.data.DataStoreFinder;
import org.geotools.data.DataUtilities;
import org.geotools.data.FileDataStore;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.data.collection.ListFeatureCollection;
import org.geotools.data.geojson.GeoJSONDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.data.simple.SimpleFeatureStore;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.NameImpl;
import org.geotools.feature.simple.SimpleFeatureTypeImpl;
import org.geotools.feature.type.GeometryDescriptorImpl;
import org.geotools.feature.type.GeometryTypeImpl;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.util.URLs;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.AttributeType;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.feature.type.GeometryType;

public class GeoJsonToShp {

  public static void main(String[] args) throws IOException {

    // open geojson

    URL url = URLs.fileToUrl(new File("/home/ian/Data/states/states.geojson"));
    HashMap<String, Object> params = new HashMap<>();
    params.put(GeoJSONDataStoreFactory.URLP.key, url);
    DataStore in = DataStoreFinder.getDataStore(params);
    if (in == null) {
      throw new IOException("couldn't open datastore from " + url);
    }
    SimpleFeatureCollection features = in.getFeatureSource(in.getTypeNames()[0]).getFeatures();

    // convert schema for shapefile
    SimpleFeatureType schema = features.getSchema();
    GeometryDescriptor geom = schema.getGeometryDescriptor();

    List<AttributeDescriptor> attributes = schema.getAttributeDescriptors();
    GeometryType geomType = null;
    List<AttributeDescriptor> attribs = new ArrayList<>();
    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(),
        DefaultGeographicCRS.WGS84, 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 outSchema = new SimpleFeatureTypeImpl(schema.getName(), attribs, geomDesc, schema.isAbstract(),
        schema.getRestrictions(), schema.getSuper(), schema.getDescription());

    // create output datastore

    File outFile = new File("output.shp");
    outFile.createNewFile();
    FileDataStore ds = FileDataStoreFinder.getDataStore(outFile);
    ds.createSchema(outSchema);
    SimpleFeatureSource featureSource = ds.getFeatureSource();
    if (featureSource instanceof SimpleFeatureStore) {
      SimpleFeatureCollection collection;
      List<SimpleFeature> feats = new ArrayList<>();
      // retype the features
      try (FeatureIterator<SimpleFeature> features2 = features.features()) {
        while (features2.hasNext()) {
          SimpleFeature f = features2.next();
          SimpleFeature reType = DataUtilities.reType(outSchema, f, true);

          reType.setAttribute(outSchema.getGeometryDescriptor().getName(),
              f.getAttribute(schema.getGeometryDescriptor().getName()));

          feats.add(reType);
        }
      }

      collection = new ListFeatureCollection(outSchema, feats);

      SimpleFeatureStore outStore = (SimpleFeatureStore) featureSource;

      outStore.addFeatures(collection);
      ds.dispose();
    } else {
      System.err.println("Unable to write to " + outFile);
    }
    in.dispose();
  }
}
9
  • unable to import import org.geotools.util.URLs and import org.geotools.data.geojson.GeoJSONDataStoreFactory, can you suggest something?
    – Gaurav
    Feb 7, 2019 at 8:57
  • for the datastore - <dependency> <groupId>org.geotools</groupId> <artifactId>gt-geojsondatastore</artifactId> <version>${geotools.version}</version> </dependency>
    – Ian Turton
    Feb 7, 2019 at 9:09
  • and for URLs - add gt-metadata but that should come with gt-main.
    – Ian Turton
    Feb 7, 2019 at 9:10
  • in case of URLs , it will be <dependency> <groupId>org.geotools</groupId> <artifactId>gt-metadata</artifactId> <version>16.2</version> </dependency> <dependency> <groupId>org.geotools</groupId> <artifactId>gt-main</artifactId> <version>16.2</version> </dependency> Is this right?
    – Gaurav
    Feb 7, 2019 at 9:18
  • For 16.2 you might need the older formulation which I can't recall - upgrade to 19 or 20
    – Ian Turton
    Feb 7, 2019 at 9:20

Your Answer

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

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