Index: /trunk/src/org/openstreetmap/josm/data/Preferences.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/Preferences.java	(revision 12850)
+++ /trunk/src/org/openstreetmap/josm/data/Preferences.java	(revision 12851)
@@ -12,5 +12,4 @@
 import java.io.PrintWriter;
 import java.io.Reader;
-import java.io.StringReader;
 import java.io.StringWriter;
 import java.lang.annotation.Retention;
@@ -25,10 +24,8 @@
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Objects;
 import java.util.Optional;
 import java.util.ResourceBundle;
@@ -43,13 +40,4 @@
 import java.util.stream.Stream;
 
-import javax.json.Json;
-import javax.json.JsonArray;
-import javax.json.JsonArrayBuilder;
-import javax.json.JsonObject;
-import javax.json.JsonObjectBuilder;
-import javax.json.JsonReader;
-import javax.json.JsonString;
-import javax.json.JsonValue;
-import javax.json.JsonWriter;
 import javax.swing.JOptionPane;
 import javax.xml.stream.XMLStreamException;
@@ -77,8 +65,6 @@
 import org.openstreetmap.josm.tools.ColorHelper;
 import org.openstreetmap.josm.tools.I18n;
-import org.openstreetmap.josm.tools.JosmRuntimeException;
 import org.openstreetmap.josm.tools.ListenerList;
 import org.openstreetmap.josm.tools.Logging;
-import org.openstreetmap.josm.tools.MultiMap;
 import org.openstreetmap.josm.tools.Utils;
 import org.xml.sax.SAXException;
@@ -1212,5 +1198,7 @@
      * @see #serializeStruct(java.lang.Object, java.lang.Class)
      * @see #deserializeStruct(java.util.Map, java.lang.Class)
-     */
+     * @deprecated use {@link StructUtils.StructEntry}
+     */
+    @Deprecated
     @Retention(RetentionPolicy.RUNTIME) // keep annotation at runtime
     public @interface pref { }
@@ -1221,5 +1209,7 @@
      *
      * @see #serializeStruct(java.lang.Object, java.lang.Class)
-     */
+     * @deprecated use {@link StructUtils.WriteExplicitly}
+     */
+    @Deprecated
     @Retention(RetentionPolicy.RUNTIME) // keep annotation at runtime
     public @interface writeExplicitly { }
@@ -1233,7 +1223,9 @@
      * @param klass The struct class
      * @return a list of objects of type T or an empty list if nothing was found
-     */
+     * @deprecated use {@link StructUtils#getListOfStructs(IPreferences, String, Class)}
+     */
+    @Deprecated
     public <T> List<T> getListOfStructs(String key, Class<T> klass) {
-        return Optional.ofNullable(getListOfStructs(key, null, klass)).orElseGet(Collections::emptyList);
+        return StructUtils.getListOfStructs(this, key, klass);
     }
 
@@ -1245,11 +1237,9 @@
      * @param klass The struct class
      * @return a list of objects of type T or {@code def} if nothing was found
-     */
+     * @deprecated use {@link StructUtils#getListOfStructs(IPreferences, String, Collection, Class)}
+     */
+    @Deprecated
     public <T> List<T> getListOfStructs(String key, Collection<T> def, Class<T> klass) {
-        List<Map<String, String>> prop =
-            getListOfMaps(key, def == null ? null : serializeListOfStructs(def, klass));
-        if (prop == null)
-            return def == null ? null : new ArrayList<>(def);
-        return prop.stream().map(p -> deserializeStruct(p, klass)).collect(Collectors.toList());
+        return StructUtils.getListOfStructs(this, key, def, klass);
     }
 
@@ -1269,95 +1259,9 @@
      * @param klass The struct class
      * @return true if something has changed
-     */
+     * @deprecated use {@link StructUtils#putListOfStructs(IPreferences, String, Collection, Class)}
+     */
+    @Deprecated
     public <T> boolean putListOfStructs(String key, Collection<T> val, Class<T> klass) {
-        return putListOfMaps(key, serializeListOfStructs(val, klass));
-    }
-
-    private static <T> List<Map<String, String>> serializeListOfStructs(Collection<T> l, Class<T> klass) {
-        if (l == null)
-            return null;
-        List<Map<String, String>> vals = new ArrayList<>();
-        for (T struct : l) {
-            if (struct != null) {
-                vals.add(serializeStruct(struct, klass));
-            }
-        }
-        return vals;
-    }
-
-    @SuppressWarnings("rawtypes")
-    private static String mapToJson(Map map) {
-        StringWriter stringWriter = new StringWriter();
-        try (JsonWriter writer = Json.createWriter(stringWriter)) {
-            JsonObjectBuilder object = Json.createObjectBuilder();
-            for (Object o: map.entrySet()) {
-                Entry e = (Entry) o;
-                Object evalue = e.getValue();
-                object.add(e.getKey().toString(), evalue.toString());
-            }
-            writer.writeObject(object.build());
-        }
-        return stringWriter.toString();
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    private static Map mapFromJson(String s) {
-        Map ret = null;
-        try (JsonReader reader = Json.createReader(new StringReader(s))) {
-            JsonObject object = reader.readObject();
-            ret = new HashMap(object.size());
-            for (Entry<String, JsonValue> e: object.entrySet()) {
-                JsonValue value = e.getValue();
-                if (value instanceof JsonString) {
-                    // in some cases, when JsonValue.toString() is called, then additional quotation marks are left in value
-                    ret.put(e.getKey(), ((JsonString) value).getString());
-                } else {
-                    ret.put(e.getKey(), e.getValue().toString());
-                }
-            }
-        }
-        return ret;
-    }
-
-    @SuppressWarnings("rawtypes")
-    private static String multiMapToJson(MultiMap map) {
-        StringWriter stringWriter = new StringWriter();
-        try (JsonWriter writer = Json.createWriter(stringWriter)) {
-            JsonObjectBuilder object = Json.createObjectBuilder();
-            for (Object o: map.entrySet()) {
-                Entry e = (Entry) o;
-                Set evalue = (Set) e.getValue();
-                JsonArrayBuilder a = Json.createArrayBuilder();
-                for (Object evo: evalue) {
-                    a.add(evo.toString());
-                }
-                object.add(e.getKey().toString(), a.build());
-            }
-            writer.writeObject(object.build());
-        }
-        return stringWriter.toString();
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    private static MultiMap multiMapFromJson(String s) {
-        MultiMap ret = null;
-        try (JsonReader reader = Json.createReader(new StringReader(s))) {
-            JsonObject object = reader.readObject();
-            ret = new MultiMap(object.size());
-            for (Entry<String, JsonValue> e: object.entrySet()) {
-                JsonValue value = e.getValue();
-                if (value instanceof JsonArray) {
-                    for (JsonString js: ((JsonArray) value).getValuesAs(JsonString.class)) {
-                        ret.put(e.getKey(), js.getString());
-                    }
-                } else if (value instanceof JsonString) {
-                    // in some cases, when JsonValue.toString() is called, then additional quotation marks are left in value
-                    ret.put(e.getKey(), ((JsonString) value).getString());
-                } else {
-                    ret.put(e.getKey(), e.getValue().toString());
-                }
-            }
-        }
-        return ret;
+        return StructUtils.putListOfStructs(this, key, val, klass);
     }
 
@@ -1377,37 +1281,9 @@
      * @param klass the class T
      * @return the resulting map (same data content as <code>struct</code>)
-     */
+     * @deprecated use {@link StructUtils#serializeStruct(java.lang.Object, java.lang.Class)}
+     */
+    @Deprecated
     public static <T> Map<String, String> serializeStruct(T struct, Class<T> klass) {
-        T structPrototype;
-        try {
-            structPrototype = klass.getConstructor().newInstance();
-        } catch (ReflectiveOperationException ex) {
-            throw new IllegalArgumentException(ex);
-        }
-
-        Map<String, String> hash = new LinkedHashMap<>();
-        for (Field f : klass.getDeclaredFields()) {
-            if (f.getAnnotation(pref.class) == null) {
-                continue;
-            }
-            Utils.setObjectsAccessible(f);
-            try {
-                Object fieldValue = f.get(struct);
-                Object defaultFieldValue = f.get(structPrototype);
-                if (fieldValue != null && (f.getAnnotation(writeExplicitly.class) != null || !Objects.equals(fieldValue, defaultFieldValue))) {
-                    String key = f.getName().replace('_', '-');
-                    if (fieldValue instanceof Map) {
-                        hash.put(key, mapToJson((Map<?, ?>) fieldValue));
-                    } else if (fieldValue instanceof MultiMap) {
-                        hash.put(key, multiMapToJson((MultiMap<?, ?>) fieldValue));
-                    } else {
-                        hash.put(key, fieldValue.toString());
-                    }
-                }
-            } catch (IllegalAccessException ex) {
-                throw new JosmRuntimeException(ex);
-            }
-        }
-        return hash;
+        return StructUtils.serializeStruct(struct, klass);
     }
 
@@ -1424,57 +1300,9 @@
      * @param klass the class T
      * @return an object of class T, initialized as described above
-     */
+     * @deprecated use {@link StructUtils#deserializeStruct(java.util.Map, java.lang.Class)}
+     */
+    @Deprecated
     public static <T> T deserializeStruct(Map<String, String> hash, Class<T> klass) {
-        T struct = null;
-        try {
-            struct = klass.getConstructor().newInstance();
-        } catch (ReflectiveOperationException ex) {
-            throw new IllegalArgumentException(ex);
-        }
-        for (Entry<String, String> keyValue : hash.entrySet()) {
-            Object value;
-            Field f;
-            try {
-                f = klass.getDeclaredField(keyValue.getKey().replace('-', '_'));
-            } catch (NoSuchFieldException ex) {
-                Logging.trace(ex);
-                continue;
-            }
-            if (f.getAnnotation(pref.class) == null) {
-                continue;
-            }
-            Utils.setObjectsAccessible(f);
-            if (f.getType() == Boolean.class || f.getType() == boolean.class) {
-                value = Boolean.valueOf(keyValue.getValue());
-            } else if (f.getType() == Integer.class || f.getType() == int.class) {
-                try {
-                    value = Integer.valueOf(keyValue.getValue());
-                } catch (NumberFormatException nfe) {
-                    continue;
-                }
-            } else if (f.getType() == Double.class || f.getType() == double.class) {
-                try {
-                    value = Double.valueOf(keyValue.getValue());
-                } catch (NumberFormatException nfe) {
-                    continue;
-                }
-            } else if (f.getType() == String.class) {
-                value = keyValue.getValue();
-            } else if (f.getType().isAssignableFrom(Map.class)) {
-                value = mapFromJson(keyValue.getValue());
-            } else if (f.getType().isAssignableFrom(MultiMap.class)) {
-                value = multiMapFromJson(keyValue.getValue());
-            } else
-                throw new JosmRuntimeException("unsupported preference primitive type");
-
-            try {
-                f.set(struct, value);
-            } catch (IllegalArgumentException ex) {
-                throw new AssertionError(ex);
-            } catch (IllegalAccessException ex) {
-                throw new JosmRuntimeException(ex);
-            }
-        }
-        return struct;
+        return StructUtils.deserializeStruct(hash, klass);
     }
 
Index: /trunk/src/org/openstreetmap/josm/data/StructUtils.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/StructUtils.java	(revision 12851)
+++ /trunk/src/org/openstreetmap/josm/data/StructUtils.java	(revision 12851)
@@ -0,0 +1,331 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonReader;
+import javax.json.JsonString;
+import javax.json.JsonValue;
+import javax.json.JsonWriter;
+
+import org.openstreetmap.josm.spi.preferences.IPreferences;
+import org.openstreetmap.josm.tools.JosmRuntimeException;
+import org.openstreetmap.josm.tools.Logging;
+import org.openstreetmap.josm.tools.MultiMap;
+import org.openstreetmap.josm.tools.Utils;
+
+/**
+ * Utility methods to convert struct-like classes to a string map and back.
+ *
+ * A "struct" is a class that has some fields annotated with {@link StructEntry}.
+ * Those fields will be respected when converting an object to a {@link Map} and
+ * back.
+ * @since 12851
+ */
+public final class StructUtils {
+
+    private StructUtils() {
+        // hide constructor
+    }
+
+    /**
+     * Annotation used for converting objects to String Maps and vice versa.
+     * 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 #deserializeStruct(java.util.Map, java.lang.Class)
+     */
+    @Retention(RetentionPolicy.RUNTIME) // keep annotation at runtime
+    public @interface StructEntry { }
+
+    /**
+     * Annotation used for converting objects to String Maps.
+     * 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)
+     */
+    @Retention(RetentionPolicy.RUNTIME) // keep annotation at runtime
+    public @interface WriteExplicitly { }
+
+    /**
+     * Get a list of hashes which are represented by a struct-like class.
+     * Possible properties are given by fields of the class klass that have the @pref annotation.
+     * Default constructor is used to initialize the struct objects, properties then override some of these default values.
+     * @param <T> klass type
+     * @param preferences preferences to look up the value
+     * @param key main preference key
+     * @param klass The struct class
+     * @return a list of objects of type T or an empty list if nothing was found
+     */
+    public static <T> List<T> getListOfStructs(IPreferences preferences, String key, Class<T> klass) {
+        return Optional.ofNullable(getListOfStructs(preferences, key, null, klass)).orElseGet(Collections::emptyList);
+    }
+
+    /**
+     * same as above, but returns def if nothing was found
+     * @param <T> klass type
+     * @param preferences preferences to look up the value
+     * @param key main preference key
+     * @param def default value
+     * @param klass The struct class
+     * @return a list of objects of type T or {@code def} if nothing was found
+     */
+    public static <T> List<T> getListOfStructs(IPreferences preferences, String key, Collection<T> def, Class<T> klass) {
+        List<Map<String, String>> prop =
+            preferences.getListOfMaps(key, def == null ? null : serializeListOfStructs(def, klass));
+        if (prop == null)
+            return def == null ? null : new ArrayList<>(def);
+        return prop.stream().map(p -> deserializeStruct(p, klass)).collect(Collectors.toList());
+    }
+
+    /**
+     * Convenience method that saves a MapListSetting which is provided as a collection of objects.
+     *
+     * Each object is converted to a <code>Map&lt;String, String&gt;</code> using the fields with {@link StructEntry} annotation.
+     * The field name is the key and the value will be converted to a string.
+     *
+     * Considers only fields that have the {@code @StructEntry} annotation.
+     * In addition it does not write fields with null values. (Thus they are cleared)
+     * Default values are given by the field values after default constructor has been called.
+     * Fields equal to the default value are not written unless the field has the {@link WriteExplicitly} annotation.
+     * @param <T> the class,
+     * @param preferences the preferences to save to
+     * @param key main preference key
+     * @param val the list that is supposed to be saved
+     * @param klass The struct class
+     * @return true if something has changed
+     */
+    public static <T> boolean putListOfStructs(IPreferences preferences, String key, Collection<T> val, Class<T> klass) {
+        return preferences.putListOfMaps(key, serializeListOfStructs(val, klass));
+    }
+
+    private static <T> List<Map<String, String>> serializeListOfStructs(Collection<T> l, Class<T> klass) {
+        if (l == null)
+            return null;
+        List<Map<String, String>> vals = new ArrayList<>();
+        for (T struct : l) {
+            if (struct != null) {
+                vals.add(serializeStruct(struct, klass));
+            }
+        }
+        return vals;
+    }
+
+    /**
+     * Convert an object to a String Map, by using field names and values as map key and value.
+     *
+     * The field value is converted to a String.
+     *
+     * Only fields with annotation {@link StructEntry} are taken into account.
+     *
+     * Fields will not be written to the map if the value is null or unchanged
+     * (compared to an object created with the no-arg-constructor).
+     * The {@link WriteExplicitly} annotation overrides this behavior, i.e. the default value will also be written.
+     *
+     * @param <T> the class of the object <code>struct</code>
+     * @param struct the object to be converted
+     * @param klass the class T
+     * @return the resulting map (same data content as <code>struct</code>)
+     */
+    @SuppressWarnings("deprecation")
+    public static <T> Map<String, String> serializeStruct(T struct, Class<T> klass) {
+        T structPrototype;
+        try {
+            structPrototype = klass.getConstructor().newInstance();
+        } catch (ReflectiveOperationException ex) {
+            throw new IllegalArgumentException(ex);
+        }
+
+        Map<String, String> hash = new LinkedHashMap<>();
+        for (Field f : klass.getDeclaredFields()) {
+            if (f.getAnnotation(Preferences.pref.class) == null && f.getAnnotation(StructEntry.class) == null) {
+                continue;
+            }
+            Utils.setObjectsAccessible(f);
+            try {
+                Object fieldValue = f.get(struct);
+                Object defaultFieldValue = f.get(structPrototype);
+                if (fieldValue != null && (
+                        f.getAnnotation(Preferences.writeExplicitly.class) != null ||
+                        f.getAnnotation(WriteExplicitly.class) != null ||
+                        !Objects.equals(fieldValue, defaultFieldValue))) {
+                    String key = f.getName().replace('_', '-');
+                    if (fieldValue instanceof Map) {
+                        hash.put(key, mapToJson((Map<?, ?>) fieldValue));
+                    } else if (fieldValue instanceof MultiMap) {
+                        hash.put(key, multiMapToJson((MultiMap<?, ?>) fieldValue));
+                    } else {
+                        hash.put(key, fieldValue.toString());
+                    }
+                }
+            } catch (IllegalAccessException ex) {
+                throw new JosmRuntimeException(ex);
+            }
+        }
+        return hash;
+    }
+
+    /**
+     * Converts a String-Map to an object of a certain class, by comparing map keys to field names of the class and assigning
+     * map values to the corresponding fields.
+     *
+     * The map value (a String) is converted to the field type. Supported types are: boolean, Boolean, int, Integer, double,
+     * Double, String, Map&lt;String, String&gt; and Map&lt;String, List&lt;String&gt;&gt;.
+     *
+     * Only fields with annotation {@link StructEntry} are taken into account.
+     * @param <T> the class
+     * @param hash the string map with initial values
+     * @param klass the class T
+     * @return an object of class T, initialized as described above
+     */
+    @SuppressWarnings("deprecation")
+    public static <T> T deserializeStruct(Map<String, String> hash, Class<T> klass) {
+        T struct = null;
+        try {
+            struct = klass.getConstructor().newInstance();
+        } catch (ReflectiveOperationException ex) {
+            throw new IllegalArgumentException(ex);
+        }
+        for (Map.Entry<String, String> keyValue : hash.entrySet()) {
+            Object value;
+            Field f;
+            try {
+                f = klass.getDeclaredField(keyValue.getKey().replace('-', '_'));
+            } catch (NoSuchFieldException ex) {
+                Logging.trace(ex);
+                continue;
+            }
+            if (f.getAnnotation(Preferences.pref.class) == null && f.getAnnotation(StructEntry.class) == null) {
+                continue;
+            }
+            Utils.setObjectsAccessible(f);
+            if (f.getType() == Boolean.class || f.getType() == boolean.class) {
+                value = Boolean.valueOf(keyValue.getValue());
+            } else if (f.getType() == Integer.class || f.getType() == int.class) {
+                try {
+                    value = Integer.valueOf(keyValue.getValue());
+                } catch (NumberFormatException nfe) {
+                    continue;
+                }
+            } else if (f.getType() == Double.class || f.getType() == double.class) {
+                try {
+                    value = Double.valueOf(keyValue.getValue());
+                } catch (NumberFormatException nfe) {
+                    continue;
+                }
+            } else if (f.getType() == String.class) {
+                value = keyValue.getValue();
+            } else if (f.getType().isAssignableFrom(Map.class)) {
+                value = mapFromJson(keyValue.getValue());
+            } else if (f.getType().isAssignableFrom(MultiMap.class)) {
+                value = multiMapFromJson(keyValue.getValue());
+            } else
+                throw new JosmRuntimeException("unsupported preference primitive type");
+
+            try {
+                f.set(struct, value);
+            } catch (IllegalArgumentException ex) {
+                throw new AssertionError(ex);
+            } catch (IllegalAccessException ex) {
+                throw new JosmRuntimeException(ex);
+            }
+        }
+        return struct;
+    }
+
+    @SuppressWarnings("rawtypes")
+    private static String mapToJson(Map map) {
+        StringWriter stringWriter = new StringWriter();
+        try (JsonWriter writer = Json.createWriter(stringWriter)) {
+            JsonObjectBuilder object = Json.createObjectBuilder();
+            for (Object o: map.entrySet()) {
+                Map.Entry e = (Map.Entry) o;
+                Object evalue = e.getValue();
+                object.add(e.getKey().toString(), evalue.toString());
+            }
+            writer.writeObject(object.build());
+        }
+        return stringWriter.toString();
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private static Map mapFromJson(String s) {
+        Map ret = null;
+        try (JsonReader reader = Json.createReader(new StringReader(s))) {
+            JsonObject object = reader.readObject();
+            ret = new HashMap(object.size());
+            for (Map.Entry<String, JsonValue> e: object.entrySet()) {
+                JsonValue value = e.getValue();
+                if (value instanceof JsonString) {
+                    // in some cases, when JsonValue.toString() is called, then additional quotation marks are left in value
+                    ret.put(e.getKey(), ((JsonString) value).getString());
+                } else {
+                    ret.put(e.getKey(), e.getValue().toString());
+                }
+            }
+        }
+        return ret;
+    }
+
+    @SuppressWarnings("rawtypes")
+    private static String multiMapToJson(MultiMap map) {
+        StringWriter stringWriter = new StringWriter();
+        try (JsonWriter writer = Json.createWriter(stringWriter)) {
+            JsonObjectBuilder object = Json.createObjectBuilder();
+            for (Object o: map.entrySet()) {
+                Map.Entry e = (Map.Entry) o;
+                Set evalue = (Set) e.getValue();
+                JsonArrayBuilder a = Json.createArrayBuilder();
+                for (Object evo: evalue) {
+                    a.add(evo.toString());
+                }
+                object.add(e.getKey().toString(), a.build());
+            }
+            writer.writeObject(object.build());
+        }
+        return stringWriter.toString();
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private static MultiMap multiMapFromJson(String s) {
+        MultiMap ret = null;
+        try (JsonReader reader = Json.createReader(new StringReader(s))) {
+            JsonObject object = reader.readObject();
+            ret = new MultiMap(object.size());
+            for (Map.Entry<String, JsonValue> e: object.entrySet()) {
+                JsonValue value = e.getValue();
+                if (value instanceof JsonArray) {
+                    for (JsonString js: ((JsonArray) value).getValuesAs(JsonString.class)) {
+                        ret.put(e.getKey(), js.getString());
+                    }
+                } else if (value instanceof JsonString) {
+                    // in some cases, when JsonValue.toString() is called, then additional quotation marks are left in value
+                    ret.put(e.getKey(), ((JsonString) value).getString());
+                } else {
+                    ret.put(e.getKey(), e.getValue().toString());
+                }
+            }
+        }
+        return ret;
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/data/imagery/ImageryInfo.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/imagery/ImageryInfo.java	(revision 12850)
+++ /trunk/src/org/openstreetmap/josm/data/imagery/ImageryInfo.java	(revision 12851)
@@ -27,5 +27,5 @@
 import org.openstreetmap.gui.jmapviewer.tilesources.TileSourceInfo;
 import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.Preferences.pref;
+import org.openstreetmap.josm.data.StructUtils.StructEntry;
 import org.openstreetmap.josm.io.Capabilities;
 import org.openstreetmap.josm.io.OsmApi;
@@ -214,36 +214,36 @@
      */
     public static class ImageryPreferenceEntry {
-        @pref String name;
-        @pref String d;
-        @pref String id;
-        @pref String type;
-        @pref String url;
-        @pref double pixel_per_eastnorth;
-        @pref String eula;
-        @pref String attribution_text;
-        @pref String attribution_url;
-        @pref String permission_reference_url;
-        @pref String logo_image;
-        @pref String logo_url;
-        @pref String terms_of_use_text;
-        @pref String terms_of_use_url;
-        @pref String country_code = "";
-        @pref String date;
-        @pref int max_zoom;
-        @pref int min_zoom;
-        @pref String cookies;
-        @pref String bounds;
-        @pref String shapes;
-        @pref String projections;
-        @pref String icon;
-        @pref String description;
-        @pref MultiMap<String, String> noTileHeaders;
-        @pref MultiMap<String, String> noTileChecksums;
-        @pref int tileSize = -1;
-        @pref Map<String, String> metadataHeaders;
-        @pref boolean valid_georeference;
-        @pref boolean bestMarked;
+        @StructEntry String name;
+        @StructEntry String d;
+        @StructEntry String id;
+        @StructEntry String type;
+        @StructEntry String url;
+        @StructEntry double pixel_per_eastnorth;
+        @StructEntry String eula;
+        @StructEntry String attribution_text;
+        @StructEntry String attribution_url;
+        @StructEntry String permission_reference_url;
+        @StructEntry String logo_image;
+        @StructEntry String logo_url;
+        @StructEntry String terms_of_use_text;
+        @StructEntry String terms_of_use_url;
+        @StructEntry String country_code = "";
+        @StructEntry String date;
+        @StructEntry int max_zoom;
+        @StructEntry int min_zoom;
+        @StructEntry String cookies;
+        @StructEntry String bounds;
+        @StructEntry String shapes;
+        @StructEntry String projections;
+        @StructEntry String icon;
+        @StructEntry String description;
+        @StructEntry MultiMap<String, String> noTileHeaders;
+        @StructEntry MultiMap<String, String> noTileChecksums;
+        @StructEntry int tileSize = -1;
+        @StructEntry Map<String, String> metadataHeaders;
+        @StructEntry boolean valid_georeference;
+        @StructEntry boolean bestMarked;
         // TODO: disabled until change of layers is implemented
-        // @pref String default_layers;
+        // @StructEntry String default_layers;
 
         /**
Index: /trunk/src/org/openstreetmap/josm/data/imagery/ImageryLayerInfo.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/imagery/ImageryLayerInfo.java	(revision 12850)
+++ /trunk/src/org/openstreetmap/josm/data/imagery/ImageryLayerInfo.java	(revision 12851)
@@ -19,4 +19,5 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.StructUtils;
 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryPreferenceEntry;
 import org.openstreetmap.josm.gui.PleaseWaitRunnable;
@@ -86,5 +87,6 @@
     public void load(boolean fastFail) {
         clear();
-        List<ImageryPreferenceEntry> entries = Main.pref.getListOfStructs("imagery.entries", null, ImageryPreferenceEntry.class);
+        List<ImageryPreferenceEntry> entries = StructUtils.getListOfStructs(
+                Config.getPref(), "imagery.entries", null, ImageryPreferenceEntry.class);
         if (entries != null) {
             for (ImageryPreferenceEntry prefEntry : entries) {
@@ -362,5 +364,5 @@
             entries.add(new ImageryPreferenceEntry(info));
         }
-        Main.pref.putListOfStructs("imagery.entries", entries, ImageryPreferenceEntry.class);
+        StructUtils.putListOfStructs(Config.getPref(), "imagery.entries", entries, ImageryPreferenceEntry.class);
     }
 
Index: /trunk/src/org/openstreetmap/josm/data/imagery/OffsetBookmark.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/imagery/OffsetBookmark.java	(revision 12850)
+++ /trunk/src/org/openstreetmap/josm/data/imagery/OffsetBookmark.java	(revision 12851)
@@ -12,7 +12,7 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.Preferences;
-import org.openstreetmap.josm.data.Preferences.pref;
-import org.openstreetmap.josm.data.Preferences.writeExplicitly;
+import org.openstreetmap.josm.data.StructUtils;
+import org.openstreetmap.josm.data.StructUtils.StructEntry;
+import org.openstreetmap.josm.data.StructUtils.WriteExplicitly;
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
@@ -34,9 +34,9 @@
     private static final List<OffsetBookmark> allBookmarks = new ArrayList<>();
 
-    @pref private String projection_code;
-    @pref private String imagery_name;
-    @pref private String name;
-    @pref @writeExplicitly private double dx, dy;
-    @pref private double center_lon, center_lat;
+    @StructEntry private String projection_code;
+    @StructEntry private String imagery_name;
+    @StructEntry private String name;
+    @StructEntry @WriteExplicitly private double dx, dy;
+    @StructEntry private double center_lon, center_lat;
 
     public boolean isUsable(ImageryLayer layer) {
@@ -167,5 +167,6 @@
 
     public static void loadBookmarks() {
-        List<OffsetBookmark> bookmarks = Main.pref.getListOfStructs("imagery.offsetbookmarks", null, OffsetBookmark.class);
+        List<OffsetBookmark> bookmarks = StructUtils.getListOfStructs(
+                Config.getPref(), "imagery.offsetbookmarks", null, OffsetBookmark.class);
         if (bookmarks == null) {
             loadBookmarksOld();
@@ -184,5 +185,5 @@
 
     public static void saveBookmarks() {
-        Main.pref.putListOfStructs("imagery.offsetbookmarks", allBookmarks, OffsetBookmark.class);
+        StructUtils.putListOfStructs(Config.getPref(), "imagery.offsetbookmarks", allBookmarks, OffsetBookmark.class);
     }
 
@@ -276,5 +277,5 @@
      */
     public Map<String, String> toPropertiesMap() {
-        return Preferences.serializeStruct(this, OffsetBookmark.class);
+        return StructUtils.serializeStruct(this, OffsetBookmark.class);
     }
 
@@ -287,5 +288,5 @@
      */
     public static OffsetBookmark fromPropertiesMap(Map<String, String> properties) {
-        return Preferences.deserializeStruct(properties, OffsetBookmark.class);
+        return StructUtils.deserializeStruct(properties, OffsetBookmark.class);
     }
 }
Index: /trunk/src/org/openstreetmap/josm/data/osm/Filter.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/Filter.java	(revision 12850)
+++ /trunk/src/org/openstreetmap/josm/data/osm/Filter.java	(revision 12851)
@@ -4,6 +4,6 @@
 import java.util.Objects;
 
-import org.openstreetmap.josm.data.Preferences.pref;
-import org.openstreetmap.josm.data.Preferences.writeExplicitly;
+import org.openstreetmap.josm.data.StructUtils.StructEntry;
+import org.openstreetmap.josm.data.StructUtils.WriteExplicitly;
 import org.openstreetmap.josm.data.osm.search.SearchMode;
 import org.openstreetmap.josm.data.osm.search.SearchSetting;
@@ -71,8 +71,8 @@
 
     public static class FilterPreferenceEntry {
-        @writeExplicitly
-        @pref public String version = "1";
+        @WriteExplicitly
+        @StructEntry public String version = "1";
 
-        @pref public String text;
+        @StructEntry public String text;
 
         /**
@@ -85,12 +85,12 @@
          * @see SearchMode
          */
-        @writeExplicitly
-        @pref public String mode = "add";
+        @WriteExplicitly
+        @StructEntry public String mode = "add";
 
-        @pref public boolean case_sensitive;
+        @StructEntry public boolean case_sensitive;
 
-        @pref public boolean regex_search;
+        @StructEntry public boolean regex_search;
 
-        @pref public boolean mapCSS_search;
+        @StructEntry public boolean mapCSS_search;
 
         /**
@@ -98,6 +98,6 @@
          * @see Filter#enable
          */
-        @writeExplicitly
-        @pref public boolean enable = true;
+        @WriteExplicitly
+        @StructEntry public boolean enable = true;
 
         /**
@@ -106,6 +106,6 @@
          * @see Filter#hiding
          */
-        @writeExplicitly
-        @pref public boolean hiding;
+        @WriteExplicitly
+        @StructEntry public boolean hiding;
 
         /**
@@ -114,6 +114,6 @@
          * @see Filter#inverted
          */
-        @writeExplicitly
-        @pref public boolean inverted;
+        @WriteExplicitly
+        @StructEntry public boolean inverted;
 
         @Override
Index: /trunk/src/org/openstreetmap/josm/data/osm/FilterModel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/FilterModel.java	(revision 12850)
+++ /trunk/src/org/openstreetmap/josm/data/osm/FilterModel.java	(revision 12851)
@@ -17,4 +17,5 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.StructUtils;
 import org.openstreetmap.josm.data.osm.Filter.FilterPreferenceEntry;
 import org.openstreetmap.josm.data.osm.search.SearchParseError;
@@ -22,4 +23,5 @@
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.widgets.OSDLabel;
+import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.Utils;
@@ -71,5 +73,6 @@
      */
     public void loadPrefs(String prefEntry) {
-        List<FilterPreferenceEntry> entries = Main.pref.getListOfStructs(prefEntry, null, FilterPreferenceEntry.class);
+        List<FilterPreferenceEntry> entries = StructUtils.getListOfStructs(
+                Config.getPref(), prefEntry, null, FilterPreferenceEntry.class);
         if (entries != null) {
             for (FilterPreferenceEntry e : entries) {
@@ -89,5 +92,5 @@
             entries.add(flt.getPreferenceEntry());
         }
-        Main.pref.putListOfStructs(prefEntry, entries, FilterPreferenceEntry.class);
+        StructUtils.putListOfStructs(Config.getPref(), prefEntry, entries, FilterPreferenceEntry.class);
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolutionUtil.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolutionUtil.java	(revision 12850)
+++ /trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolutionUtil.java	(revision 12851)
@@ -15,9 +15,10 @@
 import java.util.stream.Collectors;
 
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.Preferences.pref;
+import org.openstreetmap.josm.data.StructUtils;
+import org.openstreetmap.josm.data.StructUtils.StructEntry;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Tag;
 import org.openstreetmap.josm.data.osm.TagCollection;
+import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.Pair;
@@ -158,10 +159,11 @@
     public static Collection<AutomaticTagConflictResolver> getAutomaticTagConflictResolvers() {
         if (automaticTagConflictResolvers == null) {
-            Collection<AutomaticCombine> automaticTagConflictCombines =
-                    Main.pref.getListOfStructs(
+            Collection<AutomaticCombine> automaticTagConflictCombines = StructUtils.getListOfStructs(
+                            Config.getPref(),
                             "automatic-tag-conflict-resolution.combine",
                             defaultAutomaticTagConflictCombines, AutomaticCombine.class);
             Collection<AutomaticChoiceGroup> automaticTagConflictChoiceGroups =
-                    AutomaticChoiceGroup.groupChoices(Main.pref.getListOfStructs(
+                    AutomaticChoiceGroup.groupChoices(StructUtils.getListOfStructs(
+                            Config.getPref(),
                             "automatic-tag-conflict-resolution.choice",
                             defaultAutomaticTagConflictChoices, AutomaticChoice.class));
@@ -230,14 +232,14 @@
 
         /** The Tag key to match */
-        @pref public String key;
+        @StructEntry public String key;
 
         /** A free description */
-        @pref public String description = "";
+        @StructEntry public String description = "";
 
         /** If regular expression must be used to match the Tag key or the value. */
-        @pref public boolean isRegex;
+        @StructEntry public boolean isRegex;
 
         /** The separator to use to combine the values. */
-        @pref public String separator = ";";
+        @StructEntry public String separator = ";";
 
         /** If the combined values must be sorted.
@@ -249,5 +251,5 @@
          * </ul>
          */
-        @pref public String sort;
+        @StructEntry public String sort;
 
         /** Default constructor. */
@@ -317,17 +319,17 @@
 
         /** The Tag key to match. */
-        @pref public String key;
+        @StructEntry public String key;
 
         /** The name of the {link AutomaticChoice group} this choice belongs to. */
-        @pref public String group;
+        @StructEntry public String group;
 
         /** A free description. */
-        @pref public String description = "";
+        @StructEntry public String description = "";
 
         /** If regular expression must be used to match the Tag key or the value. */
-        @pref public boolean isRegex;
+        @StructEntry public boolean isRegex;
 
         /** The Tag value to match. */
-        @pref public String value;
+        @StructEntry public String value;
 
         /**
@@ -335,5 +337,5 @@
          * Natural String ordering is used to identify the best score.
          */
-        @pref public String score;
+        @StructEntry public String score;
 
         /** Default constructor. */
@@ -404,5 +406,5 @@
 
         /** The Tag key to match. */
-        @pref public String key;
+        @StructEntry public String key;
 
         /** The name of the group. */
@@ -410,5 +412,5 @@
 
         /** If regular expression must be used to match the Tag key. */
-        @pref public boolean isRegex;
+        @StructEntry public boolean isRegex;
 
         /** The list of choice to choose from. */
Index: /trunk/src/org/openstreetmap/josm/gui/io/importexport/WMSLayerExporter.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/io/importexport/WMSLayerExporter.java	(revision 12850)
+++ /trunk/src/org/openstreetmap/josm/gui/io/importexport/WMSLayerExporter.java	(revision 12851)
@@ -7,5 +7,5 @@
 import java.io.ObjectOutputStream;
 
-import org.openstreetmap.josm.data.Preferences;
+import org.openstreetmap.josm.data.StructUtils;
 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryPreferenceEntry;
 import org.openstreetmap.josm.gui.MainApplication;
@@ -42,5 +42,5 @@
                 oos.writeObject(MainApplication.getMap().mapView.getCenter());
                 ImageryPreferenceEntry entry = new ImageryPreferenceEntry(((AbstractTileSourceLayer) layer).getInfo());
-                oos.writeObject(Preferences.serializeStruct(entry, ImageryPreferenceEntry.class));
+                oos.writeObject(StructUtils.serializeStruct(entry, ImageryPreferenceEntry.class));
             }
         }
Index: /trunk/src/org/openstreetmap/josm/gui/io/importexport/WMSLayerImporter.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/io/importexport/WMSLayerImporter.java	(revision 12850)
+++ /trunk/src/org/openstreetmap/josm/gui/io/importexport/WMSLayerImporter.java	(revision 12851)
@@ -12,5 +12,5 @@
 
 import org.openstreetmap.josm.actions.ExtensionFileFilter;
-import org.openstreetmap.josm.data.Preferences;
+import org.openstreetmap.josm.data.StructUtils;
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
@@ -72,5 +72,5 @@
 
                 @SuppressWarnings("unchecked")
-                ImageryPreferenceEntry entry = Preferences.deserializeStruct(
+                ImageryPreferenceEntry entry = StructUtils.deserializeStruct(
                         (Map<String, String>) ois.readObject(),
                         ImageryPreferenceEntry.class);
Index: /trunk/src/org/openstreetmap/josm/io/session/ImagerySessionExporter.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/session/ImagerySessionExporter.java	(revision 12850)
+++ /trunk/src/org/openstreetmap/josm/io/session/ImagerySessionExporter.java	(revision 12851)
@@ -13,5 +13,5 @@
 import javax.swing.SwingConstants;
 
-import org.openstreetmap.josm.data.Preferences;
+import org.openstreetmap.josm.data.StructUtils;
 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryPreferenceEntry;
 import org.openstreetmap.josm.data.imagery.OffsetBookmark;
@@ -84,5 +84,5 @@
         layerElem.setAttribute("version", "0.1");
         ImageryPreferenceEntry e = new ImageryPreferenceEntry(layer.getInfo());
-        Map<String, String> data = new LinkedHashMap<>(Preferences.serializeStruct(e, ImageryPreferenceEntry.class));
+        Map<String, String> data = new LinkedHashMap<>(StructUtils.serializeStruct(e, ImageryPreferenceEntry.class));
         Utils.instanceOfThen(layer, AbstractTileSourceLayer.class, tsLayer -> {
             data.putAll(tsLayer.getDisplaySettings().toPropertiesMap());
Index: /trunk/src/org/openstreetmap/josm/io/session/ImagerySessionImporter.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/session/ImagerySessionImporter.java	(revision 12850)
+++ /trunk/src/org/openstreetmap/josm/io/session/ImagerySessionImporter.java	(revision 12851)
@@ -8,5 +8,5 @@
 import java.util.Map;
 
-import org.openstreetmap.josm.data.Preferences;
+import org.openstreetmap.josm.data.StructUtils;
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryPreferenceEntry;
@@ -42,5 +42,5 @@
         Map<String, String> attributes = readProperties(elem);
 
-        ImageryPreferenceEntry prefEntry = Preferences.deserializeStruct(attributes, ImageryPreferenceEntry.class);
+        ImageryPreferenceEntry prefEntry = StructUtils.deserializeStruct(attributes, ImageryPreferenceEntry.class);
         ImageryInfo info = new ImageryInfo(prefEntry);
         ImageryLayer layer = ImageryLayer.create(info);
Index: /trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java	(revision 12850)
+++ /trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java	(revision 12851)
@@ -67,5 +67,7 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.Preferences;
+import org.openstreetmap.josm.data.StructUtils;
+import org.openstreetmap.josm.data.StructUtils.StructEntry;
+import org.openstreetmap.josm.data.StructUtils.WriteExplicitly;
 import org.openstreetmap.josm.io.CertificateAmendment.CertAmend;
 import org.openstreetmap.josm.spi.preferences.Config;
@@ -86,5 +88,5 @@
          * The character subset. Basically a free identifier, but should be unique.
          */
-        @Preferences.pref
+        @StructEntry
         public String charset;
 
@@ -92,6 +94,6 @@
          * Platform font name.
          */
-        @Preferences.pref
-        @Preferences.writeExplicitly
+        @StructEntry
+        @WriteExplicitly
         public String name = "";
 
@@ -99,6 +101,6 @@
          * File name.
          */
-        @Preferences.pref
-        @Preferences.writeExplicitly
+        @StructEntry
+        @WriteExplicitly
         public String file = "";
 
@@ -525,5 +527,5 @@
             os.write(content);
             try (Writer w = new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8))) {
-                Collection<FontEntry> extrasPref = Main.pref.getListOfStructs(
+                Collection<FontEntry> extrasPref = StructUtils.getListOfStructs(Config.getPref(),
                         "font.extended-unicode.extra-items", getAdditionalFonts(), FontEntry.class);
                 Collection<FontEntry> extras = new ArrayList<>();
Index: /trunk/test/unit/org/openstreetmap/josm/data/imagery/ImageryInfoTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/data/imagery/ImageryInfoTest.java	(revision 12850)
+++ /trunk/test/unit/org/openstreetmap/josm/data/imagery/ImageryInfoTest.java	(revision 12851)
@@ -12,5 +12,5 @@
 import org.junit.Rule;
 import org.junit.Test;
-import org.openstreetmap.josm.data.Preferences;
+import org.openstreetmap.josm.data.StructUtils;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 import org.openstreetmap.josm.tools.MultiMap;
@@ -56,5 +56,5 @@
 
     /**
-     * Tests the {@linkplain Preferences#serializeStruct(Object, Class) serialization} of {@link ImageryInfo.ImageryPreferenceEntry}
+     * Tests the {@linkplain StructUtils#serializeStruct(Object, Class) serialization} of {@link ImageryInfo.ImageryPreferenceEntry}
      */
     @Test
@@ -64,14 +64,14 @@
         info.noTileHeaders.put("ETag", "foo");
         info.noTileHeaders.put("ETag", "bar");
-        final Map<String, String> map = Preferences.serializeStruct(info, ImageryInfo.ImageryPreferenceEntry.class);
+        final Map<String, String> map = StructUtils.serializeStruct(info, ImageryInfo.ImageryPreferenceEntry.class);
         assertEquals("{noTileHeaders={\"ETag\":[\"foo\",\"bar\"]}}", map.toString());
     }
 
     /**
-     * Tests the {@linkplain Preferences#deserializeStruct(Map, Class)} deserialization} of {@link ImageryInfo.ImageryPreferenceEntry}
+     * Tests the {@linkplain StructUtils#deserializeStruct(Map, Class)} deserialization} of {@link ImageryInfo.ImageryPreferenceEntry}
      */
     @Test
     public void testDeserializeStruct() {
-        final ImageryInfo.ImageryPreferenceEntry info = Preferences.deserializeStruct(
+        final ImageryInfo.ImageryPreferenceEntry info = StructUtils.deserializeStruct(
                 Collections.singletonMap("noTileHeaders", "{\"ETag\":[\"foo\",\"bar\"]}"), ImageryInfo.ImageryPreferenceEntry.class);
         MultiMap<String, String> expect = new MultiMap<>();
@@ -84,9 +84,9 @@
 
     /**
-     * Tests the {@linkplain Preferences#deserializeStruct(Map, Class)} deserialization} of legacy {@link ImageryInfo.ImageryPreferenceEntry}
+     * Tests the {@linkplain StructUtils#deserializeStruct(Map, Class)} deserialization} of legacy {@link ImageryInfo.ImageryPreferenceEntry}
      */
     @Test
     public void testDeserializeStructTicket12474() {
-        final ImageryInfo.ImageryPreferenceEntry info = Preferences.deserializeStruct(
+        final ImageryInfo.ImageryPreferenceEntry info = StructUtils.deserializeStruct(
                 Collections.singletonMap("noTileHeaders", "{\"ETag\":\"foo-and-bar\"}"), ImageryInfo.ImageryPreferenceEntry.class);
         final Set<String> eTag = info.noTileHeaders.get("ETag");
