Index: trunk/src/org/openstreetmap/josm/data/StructUtils.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/StructUtils.java	(revision 16587)
+++ trunk/src/org/openstreetmap/josm/data/StructUtils.java	(revision 16589)
@@ -8,4 +8,5 @@
 import java.lang.reflect.Field;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -53,5 +54,5 @@
      * Indicates that a certain field should be considered in the conversion process. Otherwise it is ignored.
      *
-     * @see #serializeStruct(java.lang.Object, java.lang.Class)
+     * @see #serializeStruct
      * @see #deserializeStruct(java.util.Map, java.lang.Class)
      */
@@ -63,5 +64,5 @@
      * Indicates that a certain field should be written to the map, even if the value is the same as the default value.
      *
-     * @see #serializeStruct(java.lang.Object, java.lang.Class)
+     * @see #serializeStruct
      */
     @Retention(RetentionPolicy.RUNTIME) // keep annotation at runtime
@@ -128,4 +129,18 @@
 
     /**
+     * Options for {@link #serializeStruct}
+     */
+    public enum SerializeOptions {
+        /**
+         * Serialize {@code null} values
+         */
+        INCLUDE_NULL,
+        /**
+         * Serialize default values
+         */
+        INCLUDE_DEFAULT
+    }
+
+    /**
      * Convert an object to a String Map, by using field names and values as map key and value.
      *
@@ -141,7 +156,9 @@
      * @param struct the object to be converted
      * @param klass the class T
+     * @param options optional serialization options
      * @return the resulting map (same data content as <code>struct</code>)
      */
-    public static <T> HashMap<String, String> serializeStruct(T struct, Class<T> klass) {
+    public static <T> HashMap<String, String> serializeStruct(T struct, Class<T> klass, SerializeOptions... options) {
+        List<SerializeOptions> optionsList = Arrays.asList(options);
         T structPrototype;
         try {
@@ -160,7 +177,9 @@
                 Object fieldValue = f.get(struct);
                 Object defaultFieldValue = f.get(structPrototype);
-                if (fieldValue != null && (
-                        f.getAnnotation(WriteExplicitly.class) != null ||
-                        !Objects.equals(fieldValue, defaultFieldValue))) {
+                boolean serializeNull = optionsList.contains(SerializeOptions.INCLUDE_NULL) || fieldValue != null;
+                boolean serializeDefault = optionsList.contains(SerializeOptions.INCLUDE_DEFAULT)
+                        || f.getAnnotation(WriteExplicitly.class) != null
+                        || !Objects.equals(fieldValue, defaultFieldValue);
+                if (serializeNull && serializeDefault) {
                     String key = f.getName().replace('_', '-');
                     if (fieldValue instanceof Map) {
@@ -168,4 +187,6 @@
                     } else if (fieldValue instanceof MultiMap) {
                         hash.put(key, multiMapToJson((MultiMap<?, ?>) fieldValue));
+                    } else if (fieldValue == null) {
+                        hash.put(key, null);
                     } else {
                         hash.put(key, fieldValue.toString());
Index: trunk/src/org/openstreetmap/josm/io/remotecontrol/RemoteControl.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/remotecontrol/RemoteControl.java	(revision 16587)
+++ trunk/src/org/openstreetmap/josm/io/remotecontrol/RemoteControl.java	(revision 16589)
@@ -32,5 +32,5 @@
      */
     static final int protocolMajorVersion = 1;
-    static final int protocolMinorVersion = 9;
+    static final int protocolMinorVersion = 10;
 
     /**
Index: trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/ImageryHandler.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/ImageryHandler.java	(revision 16587)
+++ trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/ImageryHandler.java	(revision 16589)
@@ -6,11 +6,13 @@
 import java.util.Arrays;
 
+import org.openstreetmap.josm.data.StructUtils;
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
+import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryPreferenceEntry;
 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
-import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.layer.ImageryLayer;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.Utils;
@@ -40,5 +42,7 @@
     @Override
     public String[] getOptionalParams() {
-        return new String[] {"title", "type", "cookies", "min_zoom", "max_zoom"};
+        return StructUtils.serializeStruct(new ImageryPreferenceEntry(), ImageryPreferenceEntry.class,
+                StructUtils.SerializeOptions.INCLUDE_NULL, StructUtils.SerializeOptions.INCLUDE_DEFAULT
+        ).keySet().toArray(new String[0]);
     }
 
@@ -48,43 +52,9 @@
     }
 
-    protected static ImageryInfo findBingEntry() {
-        return ImageryLayerInfo.instance.getDefaultLayers().stream()
-                .filter(i -> ImageryType.BING == i.getImageryType())
-                .findFirst().orElse(null);
-    }
-
     protected ImageryInfo buildImageryInfo() {
-        String url = args.get("url");
-        String title = args.get("title");
-        String type = args.get("type");
-        final ImageryInfo bing = ImageryType.BING.getTypeString().equals(type) ? findBingEntry() : null;
-        if ((title == null || title.isEmpty()) && bing != null) {
-            title = bing.getName();
-        }
-        if (title == null || title.isEmpty()) {
-            title = tr("Remote imagery");
-        }
-        String cookies = args.get("cookies");
-        final ImageryInfo imgInfo = new ImageryInfo(title, url, type, null, cookies);
-        if (bing != null) {
-            imgInfo.setIcon(bing.getIcon());
-        }
-        String minZoom = args.get("min_zoom");
-        if (minZoom != null && !minZoom.isEmpty()) {
-            try {
-                imgInfo.setDefaultMinZoom(Integer.parseInt(minZoom));
-            } catch (NumberFormatException e) {
-                Logging.error(e);
-            }
-        }
-        String maxZoom = args.get("max_zoom");
-        if (maxZoom != null && !maxZoom.isEmpty()) {
-            try {
-                imgInfo.setDefaultMaxZoom(Integer.parseInt(maxZoom));
-            } catch (NumberFormatException e) {
-                Logging.error(e);
-            }
-        }
-        return imgInfo;
+        args.computeIfAbsent("type", ignore -> ImageryType.WMS.getDefault().getTypeString());
+        args.computeIfAbsent("name", ignore -> args.getOrDefault("title", tr("Remote imagery")));
+        ImageryPreferenceEntry imageryPreferenceEntry = StructUtils.deserializeStruct(args, ImageryPreferenceEntry.class);
+        return new ImageryInfo(imageryPreferenceEntry);
     }
 
@@ -111,9 +81,8 @@
     @Override
     protected void validateRequest() throws RequestHandlerBadRequestException {
-        String url = args != null ? args.get("url") : null;
-        String type = args != null ? args.get("type") : null;
-        String cookies = args != null ? args.get("cookies") : null;
         try {
-            ImageryLayer.create(new ImageryInfo(null, url, type, null, cookies));
+            CheckParameterUtil.ensureParameterNotNull(args);
+            CheckParameterUtil.ensureParameterNotNull(args.get("url"));
+            ImageryLayer.create(buildImageryInfo());
         } catch (IllegalArgumentException e) {
             throw new RequestHandlerBadRequestException(e.getMessage(), e);
