Index: /trunk/src/org/openstreetmap/josm/actions/OpenFileAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/OpenFileAction.java	(revision 15783)
+++ /trunk/src/org/openstreetmap/josm/actions/OpenFileAction.java	(revision 15784)
@@ -25,5 +25,4 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
 
 import javax.swing.JOptionPane;
@@ -39,4 +38,5 @@
 import org.openstreetmap.josm.gui.io.importexport.AllFormatsImporter;
 import org.openstreetmap.josm.gui.io.importexport.FileImporter;
+import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.gui.widgets.AbstractFileChooser;
 import org.openstreetmap.josm.io.OsmTransferException;
@@ -331,6 +331,8 @@
                             }
                         }
-                    } catch (IOException | PatternSyntaxException | IllegalStateException | IndexOutOfBoundsException e) {
+                    } catch (IOException | RuntimeException | LinkageError e) {
                         Logging.error(e);
+                        GuiHelper.runInEDT(
+                                () -> new Notification(Utils.getRootCause(e).getMessage()).setIcon(JOptionPane.ERROR_MESSAGE).show());
                     }
                 }
Index: /trunk/src/org/openstreetmap/josm/actions/OpenLocationAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/OpenLocationAction.java	(revision 15783)
+++ /trunk/src/org/openstreetmap/josm/actions/OpenLocationAction.java	(revision 15784)
@@ -28,7 +28,5 @@
 import org.openstreetmap.josm.actions.downloadtasks.DownloadNotesUrlBoundsTask;
 import org.openstreetmap.josm.actions.downloadtasks.DownloadNotesUrlIdTask;
-import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmChangeCompressedTask;
 import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmChangeTask;
-import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmCompressedTask;
 import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmIdTask;
 import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
@@ -97,6 +95,4 @@
         addDownloadTaskClass(DownloadOsmUrlTask.class);
         addDownloadTaskClass(DownloadOsmIdTask.class);
-        addDownloadTaskClass(DownloadOsmCompressedTask.class);
-        addDownloadTaskClass(DownloadOsmChangeCompressedTask.class);
         addDownloadTaskClass(DownloadSessionTask.class);
         addDownloadTaskClass(DownloadNotesUrlBoundsTask.class);
Index: /trunk/src/org/openstreetmap/josm/actions/downloadtasks/AbstractDownloadTask.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/downloadtasks/AbstractDownloadTask.java	(revision 15783)
+++ /trunk/src/org/openstreetmap/josm/actions/downloadtasks/AbstractDownloadTask.java	(revision 15784)
@@ -3,7 +3,9 @@
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import org.openstreetmap.josm.data.ProjectionBounds;
+import org.openstreetmap.josm.io.UrlPattern;
 import org.openstreetmap.josm.io.XmlWriter;
 
@@ -57,4 +59,9 @@
     public void setFailed(boolean failed) {
         this.failed = failed;
+    }
+
+    protected static <T extends Enum<T> & UrlPattern> String[] patterns(Class<T> urlPatternEnum) {
+        // Do not use a method reference until we switch to Java 11, as we face JDK-8141508 with Java 8
+        return Arrays.stream(urlPatternEnum.getEnumConstants()).map(/* JDK-8141508 */ t -> t.pattern()).toArray(String[]::new);
     }
 
@@ -116,12 +123,5 @@
      */
     public boolean acceptsUrl(String url) {
-        if (url == null)
-            return false;
-        for (String p: getPatterns()) {
-            if (url.matches(p)) {
-                return true;
-            }
-        }
-        return false;
+        return url != null && Arrays.stream(getPatterns()).anyMatch(url::matches);
     }
 
Index: /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGeoJsonTask.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGeoJsonTask.java	(revision 15783)
+++ /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGeoJsonTask.java	(revision 15784)
@@ -12,5 +12,7 @@
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.Compression;
 import org.openstreetmap.josm.io.GeoJSONServerReader;
+import org.openstreetmap.josm.io.UrlPatterns.GeoJsonUrlPattern;
 import org.openstreetmap.josm.tools.Utils;
 
@@ -22,10 +24,7 @@
 public class DownloadGeoJsonTask extends DownloadOsmTask {
 
-    private static final String PATTERN_COMPRESS = "https?://.*/(.*\\.(json|geojson)(\\.(gz|xz|bz2?|zip))?)";
-    private static final String PATTERN_FORMAT_GEOJSON = "https?://.*format=geojson.*";
-
     @Override
     public String[] getPatterns() {
-        return new String[]{PATTERN_COMPRESS, PATTERN_FORMAT_GEOJSON};
+        return patterns(GeoJsonUrlPattern.class);
     }
 
@@ -51,5 +50,5 @@
 
         InternalDownloadTask(DownloadParams settings, String url, ProgressMonitor progressMonitor) {
-            super(settings, new GeoJSONServerReader(url), progressMonitor);
+            super(settings, new GeoJSONServerReader(url), progressMonitor, true, Compression.byExtension(url));
             this.url = url;
         }
Index: /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java	(revision 15783)
+++ /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java	(revision 15784)
@@ -6,9 +6,8 @@
 import java.io.IOException;
 import java.net.URL;
-import java.util.Arrays;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.concurrent.Future;
 import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 import java.util.stream.Stream;
 
@@ -30,9 +29,8 @@
 import org.openstreetmap.josm.io.BoundingBoxDownloader;
 import org.openstreetmap.josm.io.OsmServerLocationReader;
-import org.openstreetmap.josm.io.OsmServerLocationReader.GpxUrlPattern;
 import org.openstreetmap.josm.io.OsmServerReader;
 import org.openstreetmap.josm.io.OsmTransferException;
+import org.openstreetmap.josm.io.UrlPatterns.GpxUrlPattern;
 import org.openstreetmap.josm.spi.preferences.Config;
-import org.openstreetmap.josm.tools.CheckParameterUtil;
 import org.openstreetmap.josm.tools.Utils;
 import org.xml.sax.SAXException;
@@ -50,5 +48,5 @@
     @Override
     public String[] getPatterns() {
-        return Arrays.stream(GpxUrlPattern.values()).map(GpxUrlPattern::pattern).toArray(String[]::new);
+        return patterns(GpxUrlPattern.class);
     }
 
@@ -69,8 +67,7 @@
     @Override
     public Future<?> loadUrl(DownloadParams settings, String url, ProgressMonitor progressMonitor) {
-        CheckParameterUtil.ensureParameterNotNull(url, "url");
-        this.url = url;
+        this.url = Objects.requireNonNull(url);
         final Optional<String> mappedUrl = Stream.of(GpxUrlPattern.USER_TRACE_ID, GpxUrlPattern.EDIT_TRACE_ID)
-                .map(p -> Pattern.compile(p.pattern()).matcher(url))
+                .map(p -> p.matcher(url))
                 .filter(Matcher::matches)
                 .map(m -> "https://www.openstreetmap.org/trace/" + m.group(2) + "/data")
@@ -81,5 +78,5 @@
         if (Stream.of(GpxUrlPattern.TRACE_ID, GpxUrlPattern.EXTERNAL_GPX_SCRIPT,
                       GpxUrlPattern.EXTERNAL_GPX_FILE, GpxUrlPattern.TASKING_MANAGER)
-                .anyMatch(p -> url.matches(p.pattern()))) {
+                .anyMatch(p -> p.matches(url))) {
             downloadTask = new DownloadTask(settings,
                     new OsmServerLocationReader(url), progressMonitor);
@@ -88,5 +85,5 @@
             return MainApplication.worker.submit(downloadTask);
 
-        } else if (url.matches(GpxUrlPattern.TRACKPOINTS_BBOX.pattern())) {
+        } else if (GpxUrlPattern.TRACKPOINTS_BBOX.matches(url)) {
             String[] table = url.split("\\?|=|&");
             for (int i = 0; i < table.length; i++) {
@@ -153,5 +150,5 @@
         private String getLayerName() {
             // Extract .gpx filename from URL to set the new layer name
-            final Matcher matcher = url != null ? Pattern.compile(GpxUrlPattern.EXTERNAL_GPX_FILE.pattern()).matcher(url) : null;
+            final Matcher matcher = url != null ? GpxUrlPattern.EXTERNAL_GPX_FILE.matcher(url) : null;
             final String newLayerName = matcher != null && matcher.matches() ? matcher.group(1) : null;
             final String metadataName = rawData != null ? rawData.getString(GpxConstants.META_NAME) : null;
Index: /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadNotesTask.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadNotesTask.java	(revision 15783)
+++ /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadNotesTask.java	(revision 15784)
@@ -7,5 +7,4 @@
 import java.io.IOException;
 import java.net.URL;
-import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.Future;
@@ -29,7 +28,7 @@
 import org.openstreetmap.josm.io.OsmApi;
 import org.openstreetmap.josm.io.OsmServerLocationReader;
-import org.openstreetmap.josm.io.OsmServerLocationReader.NoteUrlPattern;
 import org.openstreetmap.josm.io.OsmServerReader;
 import org.openstreetmap.josm.io.OsmTransferException;
+import org.openstreetmap.josm.io.UrlPatterns.NoteUrlPattern;
 import org.openstreetmap.josm.tools.Logging;
 import org.xml.sax.SAXException;
@@ -107,5 +106,5 @@
     @Override
     public String[] getPatterns() {
-        return Arrays.stream(NoteUrlPattern.values()).map(NoteUrlPattern::pattern).toArray(String[]::new);
+        return patterns(NoteUrlPattern.class);
     }
 
Index: unk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmChangeCompressedTask.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmChangeCompressedTask.java	(revision 15783)
+++ 	(revision )
@@ -1,53 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.actions.downloadtasks;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.util.concurrent.Future;
-
-import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.gui.MainApplication;
-import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.openstreetmap.josm.io.Compression;
-import org.openstreetmap.josm.io.OsmServerLocationReader;
-import org.openstreetmap.josm.io.OsmTransferException;
-
-/**
- * Task allowing to download compressed OSM-Change files (gzip, xz and bzip2)
- * @since 5361
- */
-public class DownloadOsmChangeCompressedTask extends DownloadOsmChangeTask {
-
-    private static final String PATTERN_COMPRESS = "https?://.*/(.*\\.osc.(gz|xz|bz2?|zip))";
-
-    @Override
-    public String[] getPatterns() {
-        return new String[]{PATTERN_COMPRESS};
-    }
-
-    @Override
-    public String getTitle() {
-        return tr("Download Compressed OSM Change");
-    }
-
-    /**
-     * Loads a given URL
-     * @param settings download settings
-     * @param url The URL as String
-     * @param progressMonitor progress monitor for user interaction
-     */
-    @Override
-    public Future<?> loadUrl(DownloadParams settings, final String url, ProgressMonitor progressMonitor) {
-        downloadTask = new DownloadTask(settings, new OsmServerLocationReader(url), progressMonitor) {
-            @Override
-            protected DataSet parseDataSet() throws OsmTransferException {
-                ProgressMonitor subTaskMonitor = progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false);
-                return reader.parseOsmChange(subTaskMonitor, Compression.byExtension(url));
-            }
-        };
-        currentBounds = null;
-        // Extract .osc.gz/xz/bz/bz2/zip filename from URL to set the new layer name
-        extractOsmFilename(settings, PATTERN_COMPRESS, url);
-        return MainApplication.worker.submit(downloadTask);
-    }
-}
Index: /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmChangeTask.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmChangeTask.java	(revision 15783)
+++ /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmChangeTask.java	(revision 15784)
@@ -4,4 +4,5 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.util.Arrays;
 import java.util.Date;
 import java.util.HashMap;
@@ -12,5 +13,4 @@
 import java.util.concurrent.RejectedExecutionException;
 import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import org.openstreetmap.josm.data.Bounds;
@@ -34,8 +34,10 @@
 import org.openstreetmap.josm.gui.history.HistoryLoadTask;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.Compression;
 import org.openstreetmap.josm.io.OsmApi;
 import org.openstreetmap.josm.io.OsmServerLocationReader;
 import org.openstreetmap.josm.io.OsmServerReader;
 import org.openstreetmap.josm.io.OsmTransferException;
+import org.openstreetmap.josm.io.UrlPatterns.OsmChangeUrlPattern;
 import org.openstreetmap.josm.tools.Logging;
 
@@ -46,12 +48,7 @@
 public class DownloadOsmChangeTask extends DownloadOsmTask {
 
-    private static final String OSM_WEBSITE_PATTERN = "https?://www\\.(osm|openstreetmap)\\.org/changeset/(\\p{Digit}+).*";
-
     @Override
     public String[] getPatterns() {
-        return new String[]{"https?://.*/api/0.6/changeset/\\p{Digit}+/download", // OSM API 0.6 changesets
-            OSM_WEBSITE_PATTERN, // OSM changesets
-            "https?://.*/.*\\.osc" // Remote .osc files
-        };
+        return patterns(OsmChangeUrlPattern.class);
     }
 
@@ -67,12 +64,16 @@
 
     @Override
-    public Future<?> loadUrl(DownloadParams settings, String url, ProgressMonitor progressMonitor) {
-        final Matcher matcher = Pattern.compile(OSM_WEBSITE_PATTERN).matcher(url);
+    public Future<?> loadUrl(DownloadParams settings, final String url, ProgressMonitor progressMonitor) {
+        OsmChangeUrlPattern urlPattern = Arrays.stream(OsmChangeUrlPattern.values()).filter(p -> p.matches(url)).findFirst()
+                .orElseThrow(() -> new IllegalArgumentException("URL does not match any OSM URL pattern: " + url));
+        String newUrl = url;
+        final Matcher matcher = OsmChangeUrlPattern.OSM_WEBSITE.matcher(url);
         if (matcher.matches()) {
-            url = OsmApi.getOsmApi().getBaseUrl() + "changeset/" + Long.parseLong(matcher.group(2)) + "/download";
-        }
-        downloadTask = new DownloadTask(settings, new OsmServerLocationReader(url), progressMonitor);
+            newUrl = OsmApi.getOsmApi().getBaseUrl() + "changeset/" + Long.parseLong(matcher.group(2)) + "/download";
+        }
+        downloadTask = new DownloadTask(settings, new OsmServerLocationReader(newUrl), progressMonitor, true,
+                Compression.byExtension(newUrl));
         // Extract .osc filename from URL to set the new layer name
-        extractOsmFilename(settings, "https?://.*/(.*\\.osc)", url);
+        extractOsmFilename(settings, urlPattern.pattern(), newUrl);
         return MainApplication.worker.submit(downloadTask);
     }
@@ -88,12 +89,16 @@
          * @param reader OSM data reader
          * @param progressMonitor progress monitor
+         * @param zoomAfterDownload If true, the map view will zoom to download area after download
+         * @param compression compression to use
          */
-        public DownloadTask(DownloadParams settings, OsmServerReader reader, ProgressMonitor progressMonitor) {
-            super(settings, reader, progressMonitor);
+        public DownloadTask(DownloadParams settings, OsmServerReader reader, ProgressMonitor progressMonitor,
+                boolean zoomAfterDownload, Compression compression) {
+            super(settings, reader, progressMonitor, zoomAfterDownload, compression);
         }
 
         @Override
         protected DataSet parseDataSet() throws OsmTransferException {
-            return reader.parseOsmChange(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
+            return reader.parseOsmChange(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false),
+                    compression);
         }
 
Index: unk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmCompressedTask.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmCompressedTask.java	(revision 15783)
+++ 	(revision )
@@ -1,59 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.actions.downloadtasks;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.util.concurrent.Future;
-
-import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.gui.MainApplication;
-import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.openstreetmap.josm.io.Compression;
-import org.openstreetmap.josm.io.OsmServerLocationReader;
-import org.openstreetmap.josm.io.OsmTransferException;
-
-/**
- * Task allowing to download compressed OSM files (gzip, xz and bzip2)
- * @since 5317
- */
-public class DownloadOsmCompressedTask extends DownloadOsmTask {
-
-    private static final String PATTERN_COMPRESS = "https?://.*/(.*\\.osm\\.(gz|xz|bz2?|zip))";
-
-    @Override
-    public String[] getPatterns() {
-        return new String[]{PATTERN_COMPRESS};
-    }
-
-    @Override
-    public String getTitle() {
-        return tr("Download Compressed OSM");
-    }
-
-    @Override
-    public Future<?> download(DownloadParams settings, Bounds downloadArea, ProgressMonitor progressMonitor) {
-        return null;
-    }
-
-    /**
-     * Loads a given URL
-     * @param settings download settings
-     * @param url The URL as String
-     * @param progressMonitor progress monitor for user interaction
-     */
-    @Override
-    public Future<?> loadUrl(DownloadParams settings, final String url, ProgressMonitor progressMonitor) {
-        downloadTask = new DownloadTask(settings, new OsmServerLocationReader(url), progressMonitor) {
-            @Override
-            protected DataSet parseDataSet() throws OsmTransferException {
-                ProgressMonitor subTaskMonitor = progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false);
-                return reader.parseOsm(subTaskMonitor, Compression.byExtension(url));
-            }
-        };
-        currentBounds = null;
-        // Extract .osm.gz/bz/bz2/zip filename from URL to set the new layer name
-        extractOsmFilename(settings, PATTERN_COMPRESS, url);
-        return MainApplication.worker.submit(downloadTask);
-    }
-}
Index: /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java	(revision 15783)
+++ /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java	(revision 15784)
@@ -38,10 +38,11 @@
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.io.BoundingBoxDownloader;
+import org.openstreetmap.josm.io.Compression;
 import org.openstreetmap.josm.io.OsmServerLocationReader;
-import org.openstreetmap.josm.io.OsmServerLocationReader.OsmUrlPattern;
 import org.openstreetmap.josm.io.OsmServerReader;
 import org.openstreetmap.josm.io.OsmTransferCanceledException;
 import org.openstreetmap.josm.io.OsmTransferException;
 import org.openstreetmap.josm.io.OverpassDownloadReader;
+import org.openstreetmap.josm.io.UrlPatterns.OsmUrlPattern;
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.Utils;
@@ -72,5 +73,5 @@
     public String[] getPatterns() {
         if (this.getClass() == DownloadOsmTask.class) {
-            return Arrays.stream(OsmUrlPattern.values()).map(OsmUrlPattern::pattern).toArray(String[]::new);
+            return patterns(OsmUrlPattern.class);
         } else {
             return super.getPatterns();
@@ -158,8 +159,10 @@
     public Future<?> loadUrl(DownloadParams settings, String url, ProgressMonitor progressMonitor) {
         String newUrl = modifyUrlBeforeLoad(url);
-        downloadTask = new DownloadTask(settings, getOsmServerReader(newUrl), progressMonitor);
+        OsmUrlPattern urlPattern = Arrays.stream(OsmUrlPattern.values()).filter(p -> p.matches(newUrl)).findFirst()
+                .orElseThrow(() -> new IllegalArgumentException("URL does not match any OSM URL pattern: " + newUrl));
+        downloadTask = new DownloadTask(settings, getOsmServerReader(newUrl), progressMonitor, true, Compression.byExtension(newUrl));
         currentBounds = null;
         // Extract .osm filename from URL to set the new layer name
-        extractOsmFilename(settings, "https?://.*/(.*\\.osm)", newUrl);
+        extractOsmFilename(settings, urlPattern.pattern(), newUrl);
         return MainApplication.worker.submit(downloadTask);
     }
@@ -413,4 +416,5 @@
     protected class DownloadTask extends AbstractInternalTask {
         protected final OsmServerReader reader;
+        protected final Compression compression;
 
         /**
@@ -434,10 +438,28 @@
          */
         public DownloadTask(DownloadParams settings, OsmServerReader reader, ProgressMonitor progressMonitor, boolean zoomAfterDownload) {
+            this(settings, reader, progressMonitor, zoomAfterDownload, Compression.NONE);
+        }
+
+        /**
+         * Constructs a new {@code DownloadTask}.
+         * @param settings download settings
+         * @param reader OSM data reader
+         * @param progressMonitor progress monitor
+         * @param zoomAfterDownload If true, the map view will zoom to download area after download
+         * @param compression compression to use
+         * @since 15784
+         */
+        public DownloadTask(DownloadParams settings, OsmServerReader reader, ProgressMonitor progressMonitor, boolean zoomAfterDownload,
+                Compression compression) {
             super(settings, tr("Downloading data"), progressMonitor, false, zoomAfterDownload);
-            this.reader = reader;
+            this.reader = Objects.requireNonNull(reader);
+            this.compression = compression;
         }
 
         protected DataSet parseDataSet() throws OsmTransferException {
-            return reader.parseOsm(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
+            ProgressMonitor subTaskMonitor = progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false);
+            // Don't call parseOsm signature with compression if not needed, too many implementations to update before to avoid side effects
+            return compression != null && compression != Compression.NONE ?
+                    reader.parseOsm(subTaskMonitor, compression) : reader.parseOsm(subTaskMonitor);
         }
 
@@ -500,17 +522,12 @@
     @Override
     public String getConfirmationMessage(URL url) {
-        if (url != null) {
-            String urlString = url.toExternalForm();
-            if (urlString.matches(OsmUrlPattern.OSM_API_URL.pattern())) {
-                // TODO: proper i18n after stabilization
-                Collection<String> items = new ArrayList<>();
-                items.add(tr("OSM Server URL:") + ' ' + url.getHost());
-                items.add(tr("Command")+": "+url.getPath());
-                if (url.getQuery() != null) {
-                    items.add(tr("Request details: {0}", url.getQuery().replaceAll(",\\s*", ", ")));
-                }
-                return Utils.joinAsHtmlUnorderedList(items);
-            }
-            // TODO: other APIs
+        if (OsmUrlPattern.OSM_API_URL.matches(url)) {
+            Collection<String> items = new ArrayList<>();
+            items.add(tr("OSM Server URL:") + ' ' + url.getHost());
+            items.add(tr("Command")+": "+url.getPath());
+            if (url.getQuery() != null) {
+                items.add(tr("Request details: {0}", url.getQuery().replaceAll(",\\s*", ", ")));
+            }
+            return Utils.joinAsHtmlUnorderedList(items);
         }
         return null;
Index: /trunk/src/org/openstreetmap/josm/io/GeoJSONServerReader.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/GeoJSONServerReader.java	(revision 15783)
+++ /trunk/src/org/openstreetmap/josm/io/GeoJSONServerReader.java	(revision 15784)
@@ -5,9 +5,9 @@
 
 import java.io.IOException;
-import java.util.Objects;
+import java.io.InputStream;
 
 import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.gui.io.importexport.GeoJSONImporter;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.xml.sax.SAXException;
 
 /**
@@ -16,7 +16,5 @@
  * @since 15424
  */
-public class GeoJSONServerReader extends OsmServerReader {
-
-    private final String url;
+public class GeoJSONServerReader extends OsmServerLocationReader {
 
     /**
@@ -25,17 +23,32 @@
      */
     public GeoJSONServerReader(String url) {
-        this.url = Objects.requireNonNull(url);
+        super(url);
+    }
+
+    protected class GeoJsonParser extends Parser<DataSet> {
+        protected GeoJsonParser(ProgressMonitor progressMonitor, Compression compression) {
+            super(progressMonitor, compression);
+        }
+
+        @Override
+        public DataSet parse() throws OsmTransferException, IllegalDataException, IOException, SAXException {
+            in = getInputStreamRaw(url, progressMonitor.createSubTaskMonitor(9, false));
+            if (in == null)
+                return null;
+            progressMonitor.subTask(tr("Downloading OSM data..."));
+            InputStream uncompressedInputStream = compression.getUncompressedInputStream(in); // NOPMD
+            ProgressMonitor subTaskMonitor = progressMonitor.createSubTaskMonitor(1, false);
+            return GeoJSONReader.parseDataSet(uncompressedInputStream, subTaskMonitor);
+        }
     }
 
     @Override
     public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
-        try {
-            progressMonitor.beginTask(tr("Contacting Server..."), 10);
-            return new GeoJSONImporter().parseDataSet(url);
-        } catch (IOException | IllegalDataException e) {
-            throw new OsmTransferException(e);
-        } finally {
-            progressMonitor.finishTask();
-        }
+        return parseOsm(progressMonitor, Compression.NONE);
+    }
+
+    @Override
+    public DataSet parseOsm(ProgressMonitor progressMonitor, Compression compression) throws OsmTransferException {
+        return doParse(new GeoJsonParser(progressMonitor, compression), progressMonitor);
     }
 }
Index: /trunk/src/org/openstreetmap/josm/io/OsmServerLocationReader.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/OsmServerLocationReader.java	(revision 15783)
+++ /trunk/src/org/openstreetmap/josm/io/OsmServerLocationReader.java	(revision 15784)
@@ -13,4 +13,5 @@
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.UrlPatterns.GpxUrlPattern;
 import org.openstreetmap.josm.tools.Utils;
 import org.xml.sax.SAXException;
@@ -21,92 +22,4 @@
  */
 public class OsmServerLocationReader extends OsmServerReader {
-
-    // CHECKSTYLE.OFF: MethodParamPad
-    // CHECKSTYLE.OFF: SingleSpaceSeparator
-
-    /**
-     * Patterns for OSM data download URLs.
-     * @since 12679
-     */
-    public enum OsmUrlPattern {
-        OSM_API_URL           ("https?://.*/api/0.6/(map|nodes?|ways?|relations?|\\*).*"),
-        OVERPASS_API_URL      ("https?://.*/interpreter\\?data=.*"),
-        OVERPASS_API_XAPI_URL ("https?://.*/xapi(\\?.*\\[@meta\\]|_meta\\?).*"),
-        EXTERNAL_OSM_FILE     ("https?://.*/.*\\.osm");
-
-        private final String urlPattern;
-
-        OsmUrlPattern(String urlPattern) {
-            this.urlPattern = urlPattern;
-        }
-
-        /**
-         * Returns the URL pattern.
-         * @return the URL pattern
-         */
-        public String pattern() {
-            return urlPattern;
-        }
-    }
-
-    /**
-     * Patterns for GPX download URLs.
-     * @since 12679
-     */
-    public enum GpxUrlPattern {
-        TRACE_ID     ("https?://.*(osm|openstreetmap).org/trace/\\p{Digit}+/data"),
-        USER_TRACE_ID("https?://.*(osm|openstreetmap).org/user/[^/]+/traces/(\\p{Digit}+)"),
-        EDIT_TRACE_ID("https?://.*(osm|openstreetmap).org/edit/?\\?gpx=(\\p{Digit}+)(#.*)?"),
-
-        TRACKPOINTS_BBOX("https?://.*/api/0.6/trackpoints\\?bbox=.*,.*,.*,.*"),
-        TASKING_MANAGER("https?://.*/api/v\\p{Digit}+/projects?/\\p{Digit}+/(tasks_as_gpx?.*|tasks/queries/gpx/\\?tasks=.*)"),
-
-        /** External GPX script */
-        EXTERNAL_GPX_SCRIPT("https?://.*exportgpx.*"),
-        /** External GPX file */
-        EXTERNAL_GPX_FILE  ("https?://.*/(.*\\.gpx)");
-
-        private final String urlPattern;
-
-        GpxUrlPattern(String urlPattern) {
-            this.urlPattern = urlPattern;
-        }
-
-        /**
-         * Returns the URL pattern.
-         * @return the URL pattern
-         */
-        public String pattern() {
-            return urlPattern;
-        }
-    }
-
-    /**
-     * Patterns for Note download URLs.
-     * @since 12679
-     */
-    public enum NoteUrlPattern {
-        /** URL of OSM API Notes endpoint */
-        API_URL  ("https?://.*/api/0.6/notes.*"),
-        /** URL of OSM API Notes compressed dump file */
-        DUMP_FILE("https?://.*/(.*\\.osn(\\.(gz|xz|bz2?|zip))?)");
-
-        private final String urlPattern;
-
-        NoteUrlPattern(String urlPattern) {
-            this.urlPattern = urlPattern;
-        }
-
-        /**
-         * Returns the URL pattern.
-         * @return the URL pattern
-         */
-        public String pattern() {
-            return urlPattern;
-        }
-    }
-
-    // CHECKSTYLE.ON: SingleSpaceSeparator
-    // CHECKSTYLE.ON: MethodParamPad
 
     protected final String url;
@@ -250,5 +163,5 @@
             gpxParsedProperly = reader.parse(false);
             GpxData result = reader.getGpxData();
-            result.fromServer = isGpxFromServer(url);
+            result.fromServer = GpxUrlPattern.isGpxFromServer(url);
             return result;
         }
@@ -272,14 +185,3 @@
         }
     }
-
-    /**
-     * Determines if the given URL denotes an OSM gpx-related API call.
-     * @param url The url to check
-     * @return true if the url matches "Trace ID" API call or "Trackpoints bbox" API call, false otherwise
-     * @see GpxData#fromServer
-     * @since 12679
-     */
-    public static final boolean isGpxFromServer(String url) {
-        return url != null && (url.matches(GpxUrlPattern.TRACE_ID.pattern()) || url.matches(GpxUrlPattern.TRACKPOINTS_BBOX.pattern()));
-    }
 }
Index: /trunk/src/org/openstreetmap/josm/io/OsmServerReader.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/OsmServerReader.java	(revision 15783)
+++ /trunk/src/org/openstreetmap/josm/io/OsmServerReader.java	(revision 15784)
@@ -261,5 +261,5 @@
      */
     public DataSet parseOsm(ProgressMonitor progressMonitor, Compression compression) throws OsmTransferException {
-        return null;
+        throw new UnsupportedOperationException();
     }
 
@@ -283,5 +283,5 @@
      */
     public DataSet parseOsmChange(ProgressMonitor progressMonitor, Compression compression) throws OsmTransferException {
-        return null;
+        throw new UnsupportedOperationException();
     }
 
@@ -305,5 +305,5 @@
      */
     public GpxData parseRawGps(ProgressMonitor progressMonitor, Compression compression) throws OsmTransferException {
-        return null;
+        throw new UnsupportedOperationException();
     }
 
@@ -372,5 +372,5 @@
      */
     public List<Note> parseRawNotes(ProgressMonitor progressMonitor, Compression compression) throws OsmTransferException {
-        return null;
+        throw new UnsupportedOperationException();
     }
 
Index: /trunk/src/org/openstreetmap/josm/io/UrlPattern.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/UrlPattern.java	(revision 15784)
+++ /trunk/src/org/openstreetmap/josm/io/UrlPattern.java	(revision 15784)
@@ -0,0 +1,45 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io;
+
+import java.net.URL;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Download URL pattern.
+ * @since 15784
+ */
+public interface UrlPattern {
+    /**
+     * Returns the URL pattern.
+     * @return the URL pattern
+     */
+    String pattern();
+
+    /**
+     * Creates a matcher that will match the given input against this pattern.
+     * @param input The character sequence to be matched
+     * @return A new matcher for this pattern
+     */
+    default Matcher matcher(String input) {
+        return Pattern.compile(pattern()).matcher(input);
+    }
+
+    /**
+     * Attempts to match the given input against the pattern.
+     * @param input The character sequence to be matched
+     * @return {@code true} if the given input matches this pattern
+     */
+    default boolean matches(String input) {
+        return input != null && matcher(input).matches();
+    }
+
+    /**
+     * Attempts to match the given URL external form against the pattern.
+     * @param url URL to be matched
+     * @return {@code true} if the given URL matches this pattern
+     */
+    default boolean matches(URL url) {
+        return url != null && matches(url.toExternalForm());
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/io/UrlPatterns.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/UrlPatterns.java	(revision 15784)
+++ /trunk/src/org/openstreetmap/josm/io/UrlPatterns.java	(revision 15784)
@@ -0,0 +1,161 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io;
+
+import org.openstreetmap.josm.data.gpx.GpxData;
+
+/**
+ * Collection of {@link UrlPattern}s.
+ * @since 15784
+ */
+public final class UrlPatterns {
+
+    private static final String HTTPS = "https?://";
+    private static final String COMPRESSED = "(gz|xz|bz2?|zip)";
+
+    private UrlPatterns() {
+        // Hide public constructor
+    }
+
+    // CHECKSTYLE.OFF: MethodParamPad
+    // CHECKSTYLE.OFF: SingleSpaceSeparator
+
+    /**
+     * Patterns for Geojson download URLs.
+     */
+    public enum GeoJsonUrlPattern implements UrlPattern {
+        /** URL of remote geojson files, optionally compressed */
+        COMPRESSED_FILE(".*/(.*\\.(json|geojson)(\\."+COMPRESSED+")?)"),
+        /** URL of generic service providing geojson as output format */
+        FORMAT_GEOJSON (".*format=geojson.*");
+
+        private final String urlPattern;
+
+        GeoJsonUrlPattern(String urlPattern) {
+            this.urlPattern = HTTPS + urlPattern;
+        }
+
+        @Override
+        public String pattern() {
+            return urlPattern;
+        }
+    }
+
+    /**
+     * Patterns for GPX download URLs.
+     */
+    public enum GpxUrlPattern implements UrlPattern {
+        /** URL of identified GPX trace on OpenStreetMap website */
+        TRACE_ID     (".*(osm|openstreetmap).org/trace/\\p{Digit}+/data"),
+        /** URL of identified GPX trace belonging to any user on OpenStreetMap website */
+        USER_TRACE_ID(".*(osm|openstreetmap).org/user/[^/]+/traces/(\\p{Digit}+)"),
+        /** URL of the edit link from the OpenStreetMap trace page */
+        EDIT_TRACE_ID(".*(osm|openstreetmap).org/edit/?\\?gpx=(\\p{Digit}+)(#.*)?"),
+
+        /** URL of OSM API trackpoints endpoint */
+        TRACKPOINTS_BBOX(".*/api/0.6/trackpoints\\?bbox=.*,.*,.*,.*"),
+        /** URL of HOT Tasking Manager (TM) */
+        TASKING_MANAGER(".*/api/v\\p{Digit}+/projects?/\\p{Digit}+/(tasks_as_gpx?.*|tasks/queries/gpx/\\?tasks=.*)"),
+
+        /** External GPX script */
+        EXTERNAL_GPX_SCRIPT(".*exportgpx.*"),
+        /** External GPX file */
+        EXTERNAL_GPX_FILE  (".*/(.*\\.gpx)");
+
+        private final String urlPattern;
+
+        GpxUrlPattern(String urlPattern) {
+            this.urlPattern = HTTPS + urlPattern;
+        }
+
+        @Override
+        public String pattern() {
+            return urlPattern;
+        }
+
+        /**
+         * Determines if the given URL denotes an OSM gpx-related API call.
+         * @param url The url to check
+         * @return true if the url matches "Trace ID" API call or "Trackpoints bbox" API call, false otherwise
+         * @see GpxData#fromServer
+         */
+        public static boolean isGpxFromServer(String url) {
+            return TRACE_ID.matches(url) || TRACKPOINTS_BBOX.matches(url);
+        }
+    }
+
+    /**
+     * Patterns for Note download URLs.
+     */
+    public enum NoteUrlPattern implements UrlPattern {
+        /** URL of OSM API Notes endpoint */
+        API_URL  (".*/api/0.6/notes.*"),
+        /** URL of OSM API Notes compressed dump file */
+        DUMP_FILE(".*/(.*\\.osn(\\."+COMPRESSED+")?)");
+
+        private final String urlPattern;
+
+        NoteUrlPattern(String urlPattern) {
+            this.urlPattern = HTTPS + urlPattern;
+        }
+
+        @Override
+        public String pattern() {
+            return urlPattern;
+        }
+    }
+
+    /**
+     * Patterns for OsmChange data download URLs.
+     */
+    public enum OsmChangeUrlPattern implements UrlPattern {
+        /** URL of OSM changeset on OpenStreetMap website */
+        OSM_WEBSITE             ("www\\.(osm|openstreetmap)\\.org/changeset/(\\p{Digit}+).*"),
+        /** URL of OSM API 0.6 changeset */
+        OSM_API                 (".*/api/0.6/changeset/\\p{Digit}+/download"),
+        /** URL of remote .osc file */
+        EXTERNAL_OSC_FILE       (".*/(.*\\.osc)"),
+        /** URL of remote compressed osc file */
+        EXTERNAL_COMPRESSED_FILE(".*/(.*\\.osc."+COMPRESSED+")");
+
+        private final String urlPattern;
+
+        OsmChangeUrlPattern(String urlPattern) {
+            this.urlPattern = HTTPS + urlPattern;
+        }
+
+        @Override
+        public String pattern() {
+            return urlPattern;
+        }
+    }
+
+    /**
+     * Patterns for OSM data download URLs.
+     */
+    public enum OsmUrlPattern implements UrlPattern {
+        /** URL of OSM API */
+        OSM_API_URL             (".*/api/0.6/(map|nodes?|ways?|relations?|\\*).*"),
+        /** URL of Overpass API */
+        OVERPASS_API_URL        (".*/interpreter\\?data=.*"),
+        /** URL of Overpass API (XAPI compatibility) */
+        OVERPASS_API_XAPI_URL   (".*/xapi(\\?.*\\[@meta\\]|_meta\\?).*"),
+        /** URL of remote .osm file */
+        EXTERNAL_OSM_FILE       (".*/(.*\\.osm)"),
+        /** URL of remote compressed osm file */
+        EXTERNAL_COMPRESSED_FILE(".*/(.*\\.osm\\."+COMPRESSED+")");
+
+        private final String urlPattern;
+
+        OsmUrlPattern(String urlPattern) {
+            this.urlPattern = HTTPS + urlPattern;
+        }
+
+        @Override
+        public String pattern() {
+            return urlPattern;
+        }
+    }
+
+    // CHECKSTYLE.ON: SingleSpaceSeparator
+    // CHECKSTYLE.ON: MethodParamPad
+}
Index: /trunk/test/unit/org/openstreetmap/josm/io/UrlPatternsTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/io/UrlPatternsTest.java	(revision 15784)
+++ /trunk/test/unit/org/openstreetmap/josm/io/UrlPatternsTest.java	(revision 15784)
@@ -0,0 +1,41 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.junit.Test;
+import org.openstreetmap.josm.TestUtils;
+
+/**
+ * Unit tests of {@link UrlPatterns}.
+ */
+public class UrlPatternsTest {
+
+    private static final List<Class<? extends Enum<?>>> patterns = Arrays.asList(
+            UrlPatterns.GeoJsonUrlPattern.class,
+            UrlPatterns.GpxUrlPattern.class,
+            UrlPatterns.NoteUrlPattern.class,
+            UrlPatterns.OsmChangeUrlPattern.class,
+            UrlPatterns.OsmUrlPattern.class);
+
+    /**
+     * Unit test of {@link UrlPatterns} enums.
+     */
+    @Test
+    public void testUrlPatternEnums() {
+        patterns.forEach(TestUtils::superficialEnumCodeCoverage);
+    }
+
+    /**
+     * Unit test of {@link UrlPatterns} syntax validity.
+     */
+    @Test
+    public void testUrlPatterns() {
+        assertTrue(patterns.stream().flatMap(c -> Arrays.stream(c.getEnumConstants())).map(t -> ((UrlPattern) t).pattern())
+                .map(Pattern::compile).count() > 0);
+    }
+}
