Index: applications/editors/josm/plugins/geotools/README
===================================================================
--- applications/editors/josm/plugins/geotools/README	(revision 36023)
+++ applications/editors/josm/plugins/geotools/README	(revision 36024)
@@ -4,4 +4,4 @@
     * Licensed under GPL v3 (see LICENSE)
 
-The current embedded version of GeoTools is 26.2.
+The current embedded version of GeoTools is 27.1.
 
Index: applications/editors/josm/plugins/geotools/ivy.xml
===================================================================
--- applications/editors/josm/plugins/geotools/ivy.xml	(revision 36023)
+++ applications/editors/josm/plugins/geotools/ivy.xml	(revision 36024)
@@ -14,4 +14,5 @@
         <dependency org="org.geotools" name="gt-referencing" rev="${gt.version}" conf="default->default"/>
         <dependency org="org.geotools" name="gt-shapefile" rev="${gt.version}" conf="default->default"/>
+        <dependency org="org.geotools" name="gt-geopkg" rev="${gt.version}" conf="default->default"/>
         <!-- Dependencies that were not needed in 22.0 (according to lib in svn) -->
         <exclude org="org.geotools" module="gt-imagemosaic"/>
Index: applications/editors/josm/plugins/geotools/ivy_settings.xml
===================================================================
--- applications/editors/josm/plugins/geotools/ivy_settings.xml	(revision 36023)
+++ applications/editors/josm/plugins/geotools/ivy_settings.xml	(revision 36024)
@@ -2,5 +2,5 @@
 <ivysettings>
   <!-- When geotools is updated, run `ant merge-geotools-services` -->
-  <property name="gt.version" value="27.0"/>
+  <property name="gt.version" value="27.1"/>
   <settings defaultResolver="ordered-resolvers"/>
   <resolvers>
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/OdPlugin.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/OdPlugin.java	(revision 36023)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/OdPlugin.java	(revision 36024)
@@ -41,4 +41,5 @@
 import org.openstreetmap.josm.plugins.opendata.core.io.geographic.MifTabImporter;
 import org.openstreetmap.josm.plugins.opendata.core.io.geographic.ShpImporter;
+import org.openstreetmap.josm.plugins.opendata.core.io.geographic.geopackage.GeoPackageImporter;
 import org.openstreetmap.josm.plugins.opendata.core.io.session.OpenDataSessionExporter;
 import org.openstreetmap.josm.plugins.opendata.core.io.session.OpenDataSessionImporter;
@@ -67,11 +68,19 @@
     private OdDialog dialog;
 
-    public final List<AbstractImporter> importers = Arrays.asList(new AbstractImporter[] {
-            new CsvImporter(), new OdsImporter(), new XlsImporter(), // Tabular file formats
-            new KmlKmzImporter(), new ShpImporter(), new MifTabImporter(), new GmlImporter(), // Geographic file formats
-            new ZipImporter(), // Zip archive containing any of the others
-            new SevenZipImporter(), // 7Zip archive containing any of the others
-            xmlImporter // Generic importer for XML files (currently used for Neptune files)
-    });
+    /**
+     * The importers that will get registered for use by file import
+     */
+    public final List<AbstractImporter> importers = Arrays.asList(
+            // Tabular file formats
+            new CsvImporter(), new OdsImporter(), new XlsImporter(),
+            // Geographic file formats
+            new KmlKmzImporter(), new ShpImporter(), new MifTabImporter(), new GeoPackageImporter(), new GmlImporter(),
+            // Zip archive containing any of the others
+            new ZipImporter(),
+            // 7Zip archive containing any of the others
+            new SevenZipImporter(),
+            // Generic importer for XML files (currently used for Neptune files)
+            xmlImporter
+    );
 
     public OdPlugin(PluginInformation info) {
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/OdConstants.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/OdConstants.java	(revision 36023)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/OdConstants.java	(revision 36024)
@@ -92,4 +92,5 @@
     public static final String JSON_EXT = "json";
     public static final String GEOJSON_EXT = "geojson";
+    public static final String GEOPACKAGE_EXT = "gpkg";
 
     /**
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/AbstractDataSetHandler.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/AbstractDataSetHandler.java	(revision 36023)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/AbstractDataSetHandler.java	(revision 36024)
@@ -29,4 +29,6 @@
 import org.openstreetmap.josm.plugins.opendata.core.io.geographic.MifHandler;
 import org.openstreetmap.josm.plugins.opendata.core.io.geographic.ShpHandler;
+import org.openstreetmap.josm.plugins.opendata.core.io.geographic.geopackage.DefaultGeoPackageHandler;
+import org.openstreetmap.josm.plugins.opendata.core.io.geographic.geopackage.GeoPackageHandler;
 import org.openstreetmap.josm.plugins.opendata.core.io.tabular.CsvHandler;
 import org.openstreetmap.josm.plugins.opendata.core.io.tabular.DefaultCsvHandler;
@@ -83,4 +85,5 @@
         setCsvHandler(new DefaultCsvHandler());
         setGmlHandler(new DefaultGmlHandler());
+        setGeoPackageHandler(new DefaultGeoPackageHandler());
     }
 
@@ -161,4 +164,8 @@
     protected final boolean acceptsCsvXlsFilename(String filename, String ... expected) {
         return acceptsFilename(filename, expected, OdConstants.CSV_EXT, OdConstants.XLS_EXT);
+    }
+
+    protected final boolean acceptsGpkgFilename(String filename, String... expected) {
+        return acceptsFilename(filename, expected, OdConstants.GEOPACKAGE_EXT);
     }
 
@@ -480,4 +487,16 @@
     }
 
+    // ------------ GeoPackage handling ------------
+
+    private GeoPackageHandler geoPackageHandler;
+
+    public final void setGeoPackageHandler(GeoPackageHandler handler) {
+        this.geoPackageHandler = handler;
+    }
+
+    public final GeoPackageHandler getGeoPackageHandler() {
+        return this.geoPackageHandler;
+    }
+
     // ------------ Archive handling ------------
 
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/fr/FrenchShpHandler.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/fr/FrenchShpHandler.java	(revision 36023)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/fr/FrenchShpHandler.java	(revision 36024)
@@ -6,5 +6,4 @@
 import org.geotools.referencing.operation.projection.MapProjection.AbstractProvider;
 import org.opengis.referencing.FactoryException;
-import org.opengis.referencing.NoSuchAuthorityCodeException;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.crs.ProjectedCRS;
@@ -12,12 +11,16 @@
 import org.opengis.referencing.operation.MathTransform;
 import org.openstreetmap.josm.plugins.opendata.core.io.geographic.DefaultShpHandler;
+import org.openstreetmap.josm.plugins.opendata.core.io.geographic.GeotoolsHandler;
 
+/**
+ * A handler for french-specific shapefiles
+ */
 public class FrenchShpHandler extends DefaultShpHandler {
 
     @Override
-    public CoordinateReferenceSystem getCrsFor(String crsName) throws NoSuchAuthorityCodeException, FactoryException {
-        if (crsName.equalsIgnoreCase("RGM04")) {
+    public CoordinateReferenceSystem getCrsFor(String crsName) throws FactoryException {
+        if ("RGM04".equalsIgnoreCase(crsName)) {
             return CRS.decode("EPSG:4471");
-        } else if (crsName.equalsIgnoreCase("RGFG95_UTM_Zone_22N")) {
+        } else if ("RGFG95_UTM_Zone_22N".equalsIgnoreCase(crsName)) {
             return CRS.decode("EPSG:2972");
         } else {
@@ -29,18 +32,16 @@
     public MathTransform findMathTransform(CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem targetCRS, boolean lenient)
             throws FactoryException {
-        if (sourceCRS.getName().getCode().equalsIgnoreCase("Lambert I Nord")) {
-            if (sourceCRS instanceof ProjectedCRS) {
-                GeodeticDatum datum = ((ProjectedCRS) sourceCRS).getDatum();
-                if (datum.getPrimeMeridian().getGreenwichLongitude() > 0.0
-                        && ((ProjectedCRS) sourceCRS).getConversionFromBase().getMathTransform() instanceof LambertConformal2SP) {
-                    LambertConformal2SP lambert = (LambertConformal2SP) ((ProjectedCRS) sourceCRS).getConversionFromBase().getMathTransform();
-                    Double falseNorthing = get(lambert.getParameterValues(), AbstractProvider.FALSE_NORTHING);
-                    Double centralmeridian = get(lambert.getParameterValues(), AbstractProvider.CENTRAL_MERIDIAN);
-                    if (centralmeridian.equals(0.0)) {
-                        if (falseNorthing.equals(200000.0)) {
-                            return CRS.findMathTransform(CRS.decode("EPSG:27561"), targetCRS, lenient);
-                        } else if (falseNorthing.equals(1200000.0)) {
-                            return CRS.findMathTransform(CRS.decode("EPSG:27571"), targetCRS, lenient);
-                        }
+        if ("Lambert I Nord".equalsIgnoreCase(sourceCRS.getName().getCode()) && sourceCRS instanceof ProjectedCRS) {
+            GeodeticDatum datum = ((ProjectedCRS) sourceCRS).getDatum();
+            if (datum.getPrimeMeridian().getGreenwichLongitude() > 0.0
+                    && ((ProjectedCRS) sourceCRS).getConversionFromBase().getMathTransform() instanceof LambertConformal2SP) {
+                LambertConformal2SP lambert = (LambertConformal2SP) ((ProjectedCRS) sourceCRS).getConversionFromBase().getMathTransform();
+                Double falseNorthing = GeotoolsHandler.get(lambert.getParameterValues(), AbstractProvider.FALSE_NORTHING);
+                Double centralmeridian = GeotoolsHandler.get(lambert.getParameterValues(), AbstractProvider.CENTRAL_MERIDIAN);
+                if (centralmeridian.equals(0.0)) {
+                    if (falseNorthing.equals(200000.0)) {
+                        return CRS.findMathTransform(CRS.decode("EPSG:27561"), targetCRS, lenient);
+                    } else if (falseNorthing.equals(1200000.0)) {
+                        return CRS.findMathTransform(CRS.decode("EPSG:27571"), targetCRS, lenient);
                     }
                 }
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/DefaultShpHandler.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/DefaultShpHandler.java	(revision 36023)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/DefaultShpHandler.java	(revision 36024)
@@ -3,129 +3,19 @@
 
 import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Set;
 
-import org.geotools.referencing.CRS;
-import org.geotools.referencing.crs.AbstractDerivedCRS;
-import org.geotools.referencing.datum.DefaultEllipsoid;
-import org.geotools.referencing.operation.projection.LambertConformal;
-import org.geotools.referencing.operation.projection.LambertConformal1SP;
-import org.geotools.referencing.operation.projection.LambertConformal2SP;
-import org.geotools.referencing.operation.projection.MapProjection.AbstractProvider;
-import org.opengis.parameter.ParameterDescriptor;
-import org.opengis.parameter.ParameterValueGroup;
-import org.opengis.referencing.FactoryException;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.opengis.referencing.datum.GeodeticDatum;
-import org.opengis.referencing.operation.MathTransform;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.projection.AbstractProjection;
-import org.openstreetmap.josm.data.projection.Ellipsoid;
-import org.openstreetmap.josm.data.projection.Projection;
-import org.openstreetmap.josm.data.projection.proj.LambertConformalConic;
-import org.openstreetmap.josm.data.projection.proj.LambertConformalConic.Parameters;
-import org.openstreetmap.josm.data.projection.proj.LambertConformalConic.Parameters1SP;
-import org.openstreetmap.josm.data.projection.proj.LambertConformalConic.Parameters2SP;
-import org.openstreetmap.josm.gui.preferences.projection.ProjectionChoice;
-import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
-import org.openstreetmap.josm.plugins.opendata.core.OdConstants;
-import org.openstreetmap.josm.spi.preferences.Config;
-import org.openstreetmap.josm.tools.Logging;
-import org.openstreetmap.josm.tools.Pair;
 
-public class DefaultShpHandler extends DefaultGeographicHandler implements ShpHandler {
+/**
+ * The default shapefile handler
+ */
+public class DefaultShpHandler extends DefaultGeographicHandler implements ShpHandler, GeotoolsHandler {
 
-    private static final List<Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid>>
-    ellipsoids = new ArrayList<>();
-    static {
-        ellipsoids.add(new Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid>(DefaultEllipsoid.GRS80, Ellipsoid.GRS80));
-        ellipsoids.add(new Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid>(DefaultEllipsoid.WGS84, Ellipsoid.WGS84));
-    }
-
-    protected static final Double get(ParameterValueGroup values, ParameterDescriptor<?> desc) {
-        return (Double) values.parameter(desc.getName().getCode()).getValue();
-    }
-
-    private static boolean equals(Double a, Double b) {
-        boolean res = Math.abs(a - b) <= Config.getPref().getDouble(
-                OdConstants.PREF_CRS_COMPARISON_TOLERANCE, OdConstants.DEFAULT_CRS_COMPARISON_TOLERANCE);
-        if (Config.getPref().getBoolean(OdConstants.PREF_CRS_COMPARISON_DEBUG, false)) {
-            Logging.debug("Comparing "+a+" and "+b+" -> "+res);
-        }
-        return res;
-    }
-
-    private Charset dbfCharset = null;
-
-    @Override
-    public MathTransform findMathTransform(CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem targetCRS, boolean lenient)
-            throws FactoryException {
-        if (getCrsFor(sourceCRS.getName().getCode()) != null) {
-            return CRS.findMathTransform(getCrsFor(sourceCRS.getName().getCode()), targetCRS, lenient);
-        } else if (sourceCRS instanceof AbstractDerivedCRS && sourceCRS.getName().getCode().equalsIgnoreCase("Lambert_Conformal_Conic")) {
-            List<MathTransform> result = new ArrayList<>();
-            AbstractDerivedCRS crs = (AbstractDerivedCRS) sourceCRS;
-            MathTransform transform = crs.getConversionFromBase().getMathTransform();
-            if (transform instanceof LambertConformal && crs.getDatum() instanceof GeodeticDatum) {
-                LambertConformal lambert = (LambertConformal) transform;
-                GeodeticDatum geo = (GeodeticDatum) crs.getDatum();
-                for (ProjectionChoice choice : ProjectionPreference.getProjectionChoices()) {
-                    Projection p = choice.getProjection();
-                    if (p instanceof AbstractProjection) {
-                        AbstractProjection ap = (AbstractProjection) p;
-                        if (ap.getProj() instanceof LambertConformalConic) {
-                            for (Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid> pair : ellipsoids) {
-                                if (pair.a.equals(geo.getEllipsoid()) && pair.b.equals(ap.getEllipsoid())) {
-                                    boolean ok = true;
-                                    ParameterValueGroup values = lambert.getParameterValues();
-                                    Parameters params = ((LambertConformalConic) ap.getProj()).getParameters();
-
-                                    ok = ok ? equals(get(values, AbstractProvider.LATITUDE_OF_ORIGIN), params.latitudeOrigin) : ok;
-                                    ok = ok ? equals(get(values, AbstractProvider.CENTRAL_MERIDIAN), ap.getCentralMeridian()) : ok;
-                                    ok = ok ? equals(get(values, AbstractProvider.SCALE_FACTOR), ap.getScaleFactor()) : ok;
-                                    ok = ok ? equals(get(values, AbstractProvider.FALSE_EASTING), ap.getFalseEasting()) : ok;
-                                    ok = ok ? equals(get(values, AbstractProvider.FALSE_NORTHING), ap.getFalseNorthing()) : ok;
-
-                                    if (lambert instanceof LambertConformal2SP && params instanceof Parameters2SP) {
-                                        Parameters2SP param = (Parameters2SP) params;
-                                        ok = ok ? equals(Math.min(get(values, AbstractProvider.STANDARD_PARALLEL_1),
-                                                get(values, AbstractProvider.STANDARD_PARALLEL_2)),
-                                                Math.min(param.standardParallel1, param.standardParallel2)) : ok;
-                                        ok = ok ? equals(Math.max(get(values, AbstractProvider.STANDARD_PARALLEL_1),
-                                                get(values, AbstractProvider.STANDARD_PARALLEL_2)),
-                                                Math.max(param.standardParallel1, param.standardParallel2)) : ok;
-
-                                    } else if (!(lambert instanceof LambertConformal1SP && params instanceof Parameters1SP)) {
-                                        ok = false;
-                                    }
-
-                                    if (ok) {
-                                        try {
-                                            result.add(CRS.findMathTransform(CRS.decode(p.toCode()), targetCRS, lenient));
-                                        } catch (FactoryException e) {
-                                            Logging.error(e.getMessage());
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-            if (!result.isEmpty()) {
-                if (result.size() > 1) {
-                    Logging.warn("Found multiple projections !"); // TODO: something
-                }
-                return result.get(0);
-            }
-        }
-        return null;
-    }
+    private Charset dbfCharset;
 
     @Override
     public void notifyFeatureParsed(Object feature, DataSet result, Set<OsmPrimitive> featurePrimitives) {
-        // To be overriden by modules handlers
+        // To be overridden by modules handlers
     }
 
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/GeographicReader.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/GeographicReader.java	(revision 36023)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/GeographicReader.java	(revision 36024)
@@ -72,5 +72,5 @@
 
 /**
- * Superclass of geographic format readers (currently GML and SHP).
+ * Superclass of geographic format readers (currently GML, GPKG, and SHP).
  */
 public abstract class GeographicReader extends AbstractReader {
@@ -106,4 +106,8 @@
     protected DataSet doParseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
         return null;
+    }
+
+    public GeographicHandler getHandler() {
+        return this.handler;
     }
 
@@ -344,4 +348,12 @@
     }
 
+    /**
+     * Find the math transform for the CRS used by this reader
+     * @param parent The parent component, used for showing dialogs
+     * @param findSimiliarCrs {@code true} if we don't need to find the exact CRS
+     * @throws FactoryException See {@link CRS#findMathTransform}, {@link org.opengis.referencing.AuthorityFactory#getAuthorityCodes}
+     * @throws UserCancelException If the user cancelled in one of the message dialogs
+     * @throws GeoMathTransformException If no transform could be found
+     */
     protected void findMathTransform(Component parent, boolean findSimiliarCrs)
             throws FactoryException, UserCancelException, GeoMathTransformException {
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/ShpReader.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/ShpReader.java	(revision 36023)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/ShpReader.java	(revision 36024)
@@ -4,6 +4,4 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.Component;
-import java.awt.GraphicsEnvironment;
 import java.io.BufferedReader;
 import java.io.File;
@@ -17,7 +15,5 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.text.SimpleDateFormat;
 import java.util.Arrays;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -25,36 +21,16 @@
 import java.util.Set;
 
-import javax.swing.JOptionPane;
-
 import org.geotools.data.DataStore;
-import org.geotools.data.FeatureSource;
 import org.geotools.data.shapefile.ShapefileDataStoreFactory;
-import org.geotools.feature.FeatureCollection;
-import org.geotools.feature.FeatureIterator;
-import org.locationtech.jts.geom.Geometry;
-import org.locationtech.jts.geom.GeometryCollection;
-import org.locationtech.jts.geom.LineString;
 import org.locationtech.jts.geom.Point;
-import org.locationtech.jts.geom.Polygon;
-import org.opengis.feature.Feature;
-import org.opengis.feature.GeometryAttribute;
-import org.opengis.feature.Property;
-import org.opengis.feature.type.GeometryDescriptor;
-import org.opengis.feature.type.Name;
 import org.opengis.geometry.MismatchedDimensionException;
-import org.opengis.referencing.FactoryException;
 import org.opengis.referencing.operation.TransformException;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Relation;
-import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler;
 import org.openstreetmap.josm.plugins.opendata.core.datasets.NationalHandlers;
 import org.openstreetmap.josm.tools.Logging;
-import org.openstreetmap.josm.tools.UserCancelException;
 
 /**
@@ -83,105 +59,4 @@
             throw new IOException(t);
         }
-    }
-
-    private void parseFeature(Feature feature, final Component parent) throws UserCancelException, GeoMathTransformException,
-    FactoryException, GeoCrsException, MismatchedDimensionException, TransformException {
-        featurePrimitives.clear();
-        GeometryAttribute geometry = feature.getDefaultGeometryProperty();
-        if (geometry != null) {
-
-            GeometryDescriptor desc = geometry.getDescriptor();
-
-            if (crs == null) {
-                if (desc != null && desc.getCoordinateReferenceSystem() != null) {
-                    crs = desc.getCoordinateReferenceSystem();
-                } else if (!GraphicsEnvironment.isHeadless()) {
-                    GuiHelper.runInEDTAndWait(() -> {
-                        if (0 == JOptionPane.showConfirmDialog(
-                                parent,
-                                tr("Unable to detect Coordinate Reference System.\nWould you like to fallback to ESPG:4326 (WGS 84) ?"),
-                                tr("Warning: CRS not found"),
-                                JOptionPane.YES_NO_CANCEL_OPTION
-                                )) {
-                            crs = wgs84;
-                        }
-                    });
-                } else {
-                    // Always use WGS84 in headless mode (used for unit tests only)
-                    crs = wgs84;
-                }
-                if (crs != null) {
-                    findMathTransform(parent, true);
-                } else {
-                    throw new GeoCrsException(tr("Unable to detect CRS !"));
-                }
-            }
-
-            Object geomObject = geometry.getValue();
-            if (geomObject instanceof Point) {  // TODO: Support LineString and Polygon.
-                // Sure you could have a Set of 1 object and join these 2 branches of
-                // code, but I feel there would be a performance hit.
-                OsmPrimitive primitive = createOrGetEmptyNode((Point) geomObject);
-                readNonGeometricAttributes(feature, primitive);
-            } else if (geomObject instanceof GeometryCollection) { // Deals with both MultiLineString and MultiPolygon
-                Set<OsmPrimitive> primitives = processGeometryCollection((GeometryCollection) geomObject);
-                for (OsmPrimitive prim : primitives) {
-                    readNonGeometricAttributes(feature, prim);
-                }
-            } else {
-                // Debug unknown geometry
-                Logging.debug("\ttype: "+geometry.getType());
-                Logging.debug("\tbounds: "+geometry.getBounds());
-                Logging.debug("\tdescriptor: "+desc);
-                Logging.debug("\tname: "+geometry.getName());
-                Logging.debug("\tvalue: "+geomObject);
-                Logging.debug("\tid: "+geometry.getIdentifier());
-                Logging.debug("-------------------------------------------------------------");
-            }
-        }
-    }
-
-    protected Set<OsmPrimitive> processGeometryCollection(GeometryCollection gc) throws TransformException {
-        // A feture may be a collection.  This set holds the items of the collection.
-        Set<OsmPrimitive> primitives = new HashSet<>();
-        int nGeometries = gc.getNumGeometries();
-        if (nGeometries < 1) {
-            Logging.error("empty geometry collection found");
-        } else {
-            // Create the primitive "op" and add it to the set of primitives.
-            for (int i = 0; i < nGeometries; i++) {
-                OsmPrimitive op = null;
-                Geometry g = gc.getGeometryN(i);
-                if (g instanceof Polygon) {
-                    // TODO: Split this section between Polygon and MultiPolygon.
-                    Relation r = (Relation) op;
-                    Polygon p = (Polygon) g;
-                    // Do not create relation if there's only one polygon without interior ring
-                    // except if handler prefers it
-                    if (r == null && (nGeometries > 1 || p.getNumInteriorRing() > 0 ||
-                            (handler != null && handler.preferMultipolygonToSimpleWay()))) {
-                        r = createMultipolygon();
-                    }
-                    Way w = createOrGetWay(p.getExteriorRing());
-                    if (r != null) {
-                        addWayToMp(r, "outer", w);
-                        for (int j = 0; j < p.getNumInteriorRing(); j++) {
-                            addWayToMp(r, "inner", createOrGetWay(p.getInteriorRingN(j)));
-                        }
-                    }
-                    op = r != null ? r : w;
-                } else if (g instanceof LineString) {
-                    op = createOrGetWay((LineString) g);
-                } else if (g instanceof Point) {
-                    op = createOrGetNode((Point) g);
-                } else {
-                    Logging.error("unsupported geometry : "+g);
-                }
-                if (op != null) {
-                    primitives.add(op);
-                }
-            }
-        }
-        return primitives;
     }
 
@@ -232,43 +107,5 @@
                     throw new IOException(tr("Unable to find a data store for file {0}", file.getName()));
                 }
-
-                String[] typeNames = dataStore.getTypeNames();
-                String typeName = typeNames[0];
-
-                FeatureSource<?, ?> featureSource = dataStore.getFeatureSource(typeName);
-                FeatureCollection<?, ?> collection = featureSource.getFeatures();
-
-                if (instance != null) {
-                    instance.beginTask(tr("Loading shapefile ({0} features)", collection.size()), collection.size());
-                }
-
-                int n = 0;
-
-                Component parent = instance != null ? instance.getWindowParent() : MainApplication.getMainFrame();
-
-                try (FeatureIterator<?> iterator = collection.features()) {
-                    while (iterator.hasNext()) {
-                        n++;
-                        try {
-                            Feature feature = iterator.next();
-                            parseFeature(feature, parent);
-                            if (handler != null) {
-                                handler.notifyFeatureParsed(feature, ds, featurePrimitives);
-                            }
-                        } catch (UserCancelException e) {
-                            e.printStackTrace();
-                            return ds;
-                        }
-                        if (instance != null) {
-                            instance.worked(1);
-                            instance.setCustomText(n+"/"+collection.size());
-                        }
-                    }
-                } finally {
-                    nodes.clear();
-                    if (instance != null) {
-                        instance.setCustomText(null);
-                    }
-                }
+                new GeotoolsConverter(this, dataStore).convert(instance);
             }
         } catch (IOException e) {
@@ -280,27 +117,4 @@
         }
         return ds;
-    }
-
-    private static void readNonGeometricAttributes(Feature feature, OsmPrimitive primitive) {
-        try {
-            for (Property prop : feature.getProperties()) {
-                if (!(prop instanceof GeometryAttribute)) {
-                    Name name = prop.getName();
-                    Object value = prop.getValue();
-                    if (name != null && value != null) {
-                        String sName = name.toString();
-                        String sValue = value.toString();
-                        if (value instanceof Date) {
-                            sValue = new SimpleDateFormat("yyyy-MM-dd").format(value);
-                        }
-                        if (!sName.isEmpty() && !sValue.isEmpty()) {
-                            primitive.put(sName, sValue);
-                        }
-                    }
-                }
-            }
-        } catch (Exception e) {
-            Logging.error(e);
-        }
     }
 
