<NME> _SharedPreferencesImpl_JSON.java
<BEF> 
package org.holoeverywhere.preference;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Build.VERSION;
import android.util.Log;

import org.holoeverywhere.HoloEverywhere;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class _SharedPreferencesImpl_JSON extends _SharedPreferencesBase {
    private class ClearJSONManipulate implements FutureJSONManipulate {
        @Override
        public boolean onJSONManipulate(JSONObject object) {
            @SuppressWarnings("unchecked")
            Iterator<String> iterator = object.keys();
            while (iterator.hasNext()) {
                final String key = iterator.next();
                object.remove(key);
                notifyOnChange(key);
            }
            return true;
        }
    }

    private final class CouldNotCreateStorage extends RuntimeException {
        private static final long serialVersionUID = -8602981054023098742L;

        public CouldNotCreateStorage(File file, String message) {
            super("File \"" + file.getAbsolutePath() + "\": " + message);
        }
    }

    private final class EditorImpl extends _BaseEditor {
        private final List<FutureJSONManipulate> manipulate = new ArrayList<FutureJSONManipulate>();

        private EditorImpl add(FutureJSONManipulate t) {
            manipulate.add(t);
            return this;
        }

        @Override
        public void apply() {
            JSONObject data = getData();
            synchronized (data) {
                try {
                    for (FutureJSONManipulate m : manipulate) {
                        if (!m.onJSONManipulate(data)) {
                            throw new RuntimeException(m.getClass()
                                    .getSimpleName() + ": Manipulate failed");
                        }
                    }
                    saveDataToFile(file, data);
                } catch (Exception e) {
                    Log.e(TAG, "Error while save preferences data", e);
                } finally {
                    manipulate.clear();
                }
            }
        }

        @Override
        public Editor clear() {
            return add(new ClearJSONManipulate());
        }

        @Override
        public boolean commit() {
            try {
                apply();
                return true;
            } catch (Exception e) {
                return false;
            }
        }

        @Override
        public Editor putBoolean(String key, boolean value) {
            return add(new PutValueJSONManipulate(key, value));
        }

        @Override
        public Editor putFloat(String key, float value) {
            return add(new PutValueJSONManipulate(key, (double) value));
        }

        @Override
        public Editor putFloatSet(String key, Set<Float> value) {
            return add(new PutValueJSONManipulate(key, value));
        }

        @Override
        public Editor putInt(String key, int value) {
            return add(new PutValueJSONManipulate(key, value));
        }

        @Override
        public Editor putIntSet(String key, Set<Integer> value) {
            return add(new PutValueJSONManipulate(key, value));
        }

        @Override
        public Editor putJSONArray(String key, JSONArray value) {
            return add(new PutValueJSONManipulate(key, value));
        }

        @Override
        public Editor putJSONObject(String key, JSONObject value) {
            return add(new PutValueJSONManipulate(key, value));
        }

        @Override
        public Editor putLong(String key, long value) {
            return add(new PutValueJSONManipulate(key, value));
        }

        @Override
        public Editor putLongSet(String key, Set<Long> value) {
            return add(new PutValueJSONManipulate(key, value));
        }

        @Override
        public Editor putString(String key, String value) {
            return add(new PutValueJSONManipulate(key, value));
        }

        @Override
        public Editor putStringSet(String key, Set<String> value) {
            return add(new PutValueJSONManipulate(key, value));
        }

        @Override
        public Editor remove(String key) {
            return add(new RemoveValueJSONManipulate(key));
        }

    }

    private static interface FutureJSONManipulate {
        public boolean onJSONManipulate(JSONObject object);
    }

    private static final class ImplReference {
        private JSONObject data;
        private Set<OnSharedPreferenceChangeListener> listeners;
    }

    private class PutValueJSONManipulate implements FutureJSONManipulate {
        private String key;
        private Object t;

        public PutValueJSONManipulate(String key, Object t) {
            this.key = key;
            this.t = t;
        }

        @Override
        public boolean onJSONManipulate(JSONObject object) {
            try {
                if (t instanceof Set) {
                    t = new JSONArray((Set<?>) t);
                }
                object.put(key, t);
                notifyOnChange(key);
                return true;
            } catch (JSONException e) {
                return false;
            }
        }
    }

    private class RemoveValueJSONManipulate implements FutureJSONManipulate {
        private String key;

        public RemoveValueJSONManipulate(String key) {
            this.key = key;
        }

        @Override
        public boolean onJSONManipulate(JSONObject object) {
            object.remove(key);
            notifyOnChange(key);
            return true;
        }
    }

    private static final Map<String, ImplReference> refs = new HashMap<String, ImplReference>();
    private static final String TAG = _SharedPreferencesImpl_JSON.class.getSimpleName();
    private String charset;
    private File file;
    private final String fileTag;

    @SuppressLint("NewApi")
    public _SharedPreferencesImpl_JSON(Context context, String name, int mode) {
        setCharset("utf-8");
        try {
            File tempFile = new File(context.getApplicationInfo().dataDir
                    + "/shared_prefs");
            if (tempFile.exists()) {
                if (!tempFile.isDirectory()) {
                    if (!tempFile.delete() && !tempFile.mkdirs()) {
                        throw new CouldNotCreateStorage(tempFile,
                                "Сann't create a storage for the preferences.");
                    }
                    if (VERSION.SDK_INT >= 9) {
                        tempFile.setWritable(true);
                        tempFile.setReadable(true);
                    }
                }
            } else {
                if (!tempFile.mkdirs()) {
                    throw new CouldNotCreateStorage(tempFile,
                            "Сann't create a storage for the preferences.");
                }
                if (VERSION.SDK_INT >= 9) {
                    tempFile.setWritable(true);
                    tempFile.setReadable(true);
                }
            }
            tempFile = new File(tempFile, name + ".json");
            if (!tempFile.exists() && !tempFile.createNewFile()) {
                throw new CouldNotCreateStorage(tempFile,
                        "Сann't create a storage for the preferences.");
            }
            if (VERSION.SDK_INT >= 9) {
                switch (mode) {
                    case Context.MODE_WORLD_WRITEABLE:
                        tempFile.setWritable(true, false);
                        tempFile.setReadable(true, false);
                        break;
                    case Context.MODE_WORLD_READABLE:
                        tempFile.setWritable(true, true);
                        tempFile.setReadable(true, false);
                        break;
                    case Context.MODE_PRIVATE:
                    default:
                        tempFile.setWritable(true, true);
                        tempFile.setReadable(true, true);
                        break;
                }
            }
            file = tempFile;
            fileTag = file.getAbsolutePath().intern();
            if (getReference().data == null) {
                getReference().data = readDataFromFile(file);
            }
        } catch (IOException e) {
            throw new RuntimeException("IOException", e);
        }
    }

    @Override
    public synchronized boolean contains(String key) {
        return getData().has(key);
    }

    @Override
    public Editor edit() {
        return new EditorImpl();
    }

    @Override
    public synchronized Map<String, ?> getAll() {
        Map<String, Object> map = new HashMap<String, Object>(getData()
                .length());
        Iterator<?> i = getData().keys();
        while (i.hasNext()) {
            Object o = i.next();
            String key = o instanceof String ? (String) o : o.toString();
            try {
                map.put(key, getData().get(key));
            } catch (JSONException e) {
            }
        }
        return map;
    }

    @Override
    public boolean getBoolean(String key, boolean defValue) {
        return getData().optBoolean(key, d().getBoolean(key, defValue));
    }

    public String getCharset() {
        return charset;
    }

    protected JSONObject getData() {
        return getReference().data;
    }

    @Override
    public float getFloat(String key, float defValue) {
        return (float) getData().optDouble(key, d().getFloat(key, defValue));
    }

    @Override
    public Set<Float> getFloatSet(String key, Set<Float> defValue) {
        return getSet(key, defValue);
    }

    @Override
    public int getInt(String key, int defValue) {
        return getData().optInt(key, d().getInt(key, defValue));
    }

    @Override
    public Set<Integer> getIntSet(String key, Set<Integer> defValue) {
        return getSet(key, defValue);
    }

    @Override
    public JSONArray getJSONArray(String key, JSONArray defValue) {
        JSONArray a = getData().optJSONArray(key);
        return a == null ? defValue : a;
    }

    @Override
    public JSONObject getJSONObject(String key, JSONObject defValue) {
        JSONObject a = getData().optJSONObject(key);
        return a == null ? defValue : a;
    }

    @Override
    public long getLong(String key, long defValue) {
        return getData().optLong(key, d().getLong(key, defValue));
    }

    @Override
    public Set<Long> getLongSet(String key, Set<Long> defValue) {
        return getSet(key, defValue);
    }

    protected synchronized ImplReference getReference() {
        ImplReference ref = refs.get(fileTag);
        if (ref == null) {
            ref = new ImplReference();
            refs.put(fileTag, ref);
        }
        return ref;
    }

    @SuppressWarnings("unchecked")
    private <T> Set<T> getSet(String key, Set<T> defValue) {
        JSONArray a = getData().optJSONArray(key);
        if (a == null) {
            try {
                Object o = d().get(key);
                if (o != null) {
                    return new HashSet<T>(Arrays.asList((T[]) o));
                }
            } catch (Exception e) {
            }
            return defValue;
        }
        Set<T> set = new HashSet<T>(Math.max(a.length(), 0));
        for (int i = 0; i < a.length(); i++) {
            set.add((T) a.opt(i));
        }
        return set;
    }

    @Override
    public String getString(String key, String defValue) {
        String defValue2 = d().getString(key);
        return getData().optString(key, defValue2 == null ? defValue : defValue2);
    }

    @Override
    public Set<String> getStringSet(String key, Set<String> defValue) {
        return getSet(key, defValue);
    }

    public void notifyOnChange(String key) {
        Set<OnSharedPreferenceChangeListener> listeners = getReference().listeners;
        if (listeners == null) {
            return;
        }
        synchronized (listeners) {
            for (OnSharedPreferenceChangeListener listener : listeners) {
                listener.onSharedPreferenceChanged(this, key);
            }
        }
    }

    protected JSONObject readDataFromFile(File file) {
        try {
            InputStream is = new FileInputStream(file);
            Reader reader;
            try {
                reader = new InputStreamReader(is, charset);
            } catch (UnsupportedEncodingException e) {
                if (HoloEverywhere.DEBUG) {
                    Log.w(TAG, "Encoding unsupport: " + charset);
                }
                reader = new InputStreamReader(is);
            }
            reader = new BufferedReader(reader, 1024);
            StringBuilder builder = new StringBuilder(Math.max(is.available(),
                    0));
            char[] buffer = new char[8192];
            int c;
            while ((c = reader.read(buffer)) > 0) {
                builder.append(buffer, 0, c);
            }
            reader.close();
            is.close();
            return new JSONObject(builder.toString());
        } catch (Exception e) {
            return new JSONObject();
        }
    }

    @Override
    public void registerOnSharedPreferenceChangeListener(
            android.content.SharedPreferences.OnSharedPreferenceChangeListener listener) {
        throw new RuntimeException(
                "android.content.SharedPreferences.OnSharedPreferenceChangeListener don't supported on JSON impl");
    }

    @Override
    public synchronized void registerOnSharedPreferenceChangeListener(
            OnSharedPreferenceChangeListener listener) {
        Set<OnSharedPreferenceChangeListener> listeners = getReference().listeners;
        if (listeners == null) {
            getReference().listeners = listeners = new HashSet<SharedPreferences.OnSharedPreferenceChangeListener>();
        }
        if (!listeners.contains(listener)) {
            listeners.add(listener);
        }
    }

    public void saveDataToFile(File file, JSONObject data) {
        String s;
        if (HoloEverywhere.DEBUG) {
            try {
                s = data.toString(2);
            } catch (JSONException e) {
                Log.e(TAG, "JSONException", e);
                s = data.toString();
            }
        } else {
            s = data.toString();
        }
        byte[] b;
        try {
            b = s.getBytes(charset);
        } catch (UnsupportedEncodingException e) {
            b = s.getBytes();
        }
        try {
            OutputStream os = new FileOutputStream(file);
            os.write(b);
            os.flush();
            os.close();
        } catch (IOException e) {
            throw new RuntimeException("IOException", e);
        }
    }

    public void setCharset(String charset) {
        if (charset == null || !Charset.isSupported(charset)) {
            throw new RuntimeException("Illegal charset: " + charset);
        }
        this.charset = charset;
    }

    @Override
    public void unregisterOnSharedPreferenceChangeListener(
            android.content.SharedPreferences.OnSharedPreferenceChangeListener listener) {
        throw new RuntimeException(
                "android.content.SharedPreferences.OnSharedPreferenceChangeListener don't supported on JSON impl");
    }

    @Override
    public synchronized void unregisterOnSharedPreferenceChangeListener(
            OnSharedPreferenceChangeListener listener) {
        Set<OnSharedPreferenceChangeListener> listeners = getReference().listeners;
        if (listeners == null) {
            return;
        }
        if (listeners.contains(listener)) {
            listeners.remove(listener);
        }
        if (listeners.size() == 0) {
            getReference().listeners = null;
        }
    }
}

<MSG> Fix bug #586

<DFF> @@ -39,7 +39,7 @@ public class _SharedPreferencesImpl_JSON extends _SharedPreferencesBase {
             Iterator<String> iterator = object.keys();
             while (iterator.hasNext()) {
                 final String key = iterator.next();
-                object.remove(key);
+                iterator.remove();
                 notifyOnChange(key);
             }
             return true;

{'addition_count': 1, 'commit_subject': 'Fix bug #586', 'deletion_count': 1, 'file_extension': '.java', 'lang': 'java', 'license': 'mit', 'repo_name': 'Prototik/HoloEverywhere'}