5

I have to clone a JSONObject on Android. I am aware of the easy way:

JSONObject clone = new JSONObject(original.toString());

but somehow it feels wrong/slow to do it this way. I found this: https://stackoverflow.com/a/12809884/322642 , but on Android I do not have JSONObject.getNames - anyone has a good pointer on how to do this?

Gibolt
  • 42,564
  • 15
  • 187
  • 127
ligi
  • 39,001
  • 44
  • 144
  • 244
  • you have the `names` method that returns a JSONArray of names. I agree, there is a bit of overhead, but it should work. – Blackbelt Jun 04 '14 at 09:27
  • Is new JSONObject(String) slow/wrong way to create JSONObject? – Kanak Sony Jun 04 '14 at 09:28
  • @KanakSony nothing wrong. the string is just parsed – Blackbelt Jun 04 '14 at 09:31
  • @blackbelt, than how it can be slower or a wrong way, as only String is being cloned from older reference to new object like new JSONObject(new String(String))? – Kanak Sony Jun 04 '14 at 09:36
  • @KanakSony, it would be simple if you take a look to the source code. [Here](http://grepcode.com/file/repo1.maven.org/maven2/org.json/json/20080701/org/json/JSONObject.java#JSONObject.%3Cinit%3E%28java.lang.String%29), for instance. – Blackbelt Jun 04 '14 at 09:40
  • It is not new JSONObject(String) that is the problem. Mainly the fact to go over a string-representation to clone a object is what bothers me. So you have to serialize and deserialize to clone. – ligi Jun 04 '14 at 10:07
  • http://stackoverflow.com/questions/869033/how-do-i-copy-an-object-in-java – Zasz Apr 04 '17 at 11:31

3 Answers3

2

the fastest + minimal way I found is this. it does deep copy.

JSONObject clone= new JSONObject(original.toMap());

Update: as per Marcos's comment the toMap() function is not available in Android. but the org.json library available on maven under groupId org.json has it: https://search.maven.org/artifact/org.json/json/20210307/bundle

Ali
  • 115
  • 1
  • 3
  • 9
0

You can do it with:

public JSONObject shallowCopy(JSONObject original) {
    JSONObject copy = new JSONObject();

    for ( Iterator<String> iterator = original.keys(); iterator.hasNext(); ) {
        String      key     = iterator.next();
        JSONObject  value   = original.optJSONObject(key);

        try {
            copy.put(key, value);
        } catch ( JSONException e ) {
            //TODO process exception
        }
    }

    return copy;
}

But remember it is not deep copy.

0

Your solution is inefficient, requiring the object to be serialized, and then for the String to be re-parsed.

The simplest, most performant solution is:

JSONObject copy = new JSONObject();
for (Object key : original.keySet()) {
  Object value = original.get(key);
  copy.put(key, value);
}

Note: This is a only a shallow copy

Gibolt
  • 42,564
  • 15
  • 187
  • 127
  • Also, this is a shallow copy only for the upper-level keys. If there are some nested JSON objects, they will be left attached still. – Andrei K. Dec 14 '22 at 07:22
  • `shallow copy` already specifies that only the top layer gets copied – Gibolt Dec 14 '22 at 07:50
  • Unsure about it: [1](https://en.wiktionary.org/wiki/shallow_copy), [2](https://developer.mozilla.org/en-US/docs/Glossary/Shallow_copy) – Andrei K. Dec 14 '22 at 09:32
  • Update: yes, @Gibolt, I think you are correct. My misconception was that in a shallow copy we replace all the references (even the nested ones), but keep the end (leaf) values the same. But actually it's just about creating a new object which has got exactly the same data structures under the hood. My first comment is confusing, would like to remove it. – Andrei K. Dec 14 '22 at 10:00