Sortable JsonArray

2,349 views
Skip to first unread message

Per Lindberg

unread,
Apr 17, 2012, 4:09:03 AM4/17/12
to google-gson

I sorely miss the ability to sort a JsonArray, e.g. by providing a
Comparator.
I would also be able to do foreach on a JsonArray, i.e. for
(JsonElement e : myJsonArray) { ... }

In general, it would be most useful if JsonArray and JsonObject could
implement Collection.

I would also like to have some kind of put(name,element) method on
JsonOject that replaces an element.

(Or... have I missed something?)

Brandon Mintern

unread,
Apr 17, 2012, 2:49:33 PM4/17/12
to googl...@googlegroups.com
For the iteration example, it is definitely possible in gson-2.1:

$ cat IterableJsonArray.java
import com.google.gson.*;

public class IterableJsonArray {
public static void main(String[] args) {
JsonArray myJsonArray = new
JsonParser().parse(args[0]).getAsJsonArray();
for (JsonElement e: myJsonArray) {
System.out.println(e.getAsString());
}
}
}

$ javac -cp gson-2.1.jar IterableJsonArray.java
$ java -cp .:gson-2.1.jar IterableJsonArray '["foo","bar","baz"]'
foo
bar
baz


Unfortunately, there's no easy way to sort a JsonArray in place. There
is the naive method of sorting via a list, but that involves copying
twice:

$ cat SortJsonArray.java
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import java.util.Collections;
import java.util.List;

class SortJsonArray {
public static void main(String[] args) {
Gson gson = new Gson();
JsonArray myJsonArray = new
JsonParser().parse(args[0]).getAsJsonArray();
List<String> strings = gson.fromJson(myJsonArray, new
TypeToken<List<String>>(){}.getType());
Collections.sort(strings);
myJsonArray = gson.toJsonTree(strings).getAsJsonArray();
for (JsonElement e: myJsonArray) {
System.out.println(e.getAsString());
}
}
}

$ javac -cp gson-2.1.jar SortJsonArray.java
$ java -cp .:gson-2.1.jar SortJsonArray '["foo","bar","baz"]'
bar
baz
foo


You could perform some truly horrific introspection to sort in place,
but it's highly susceptible to be broken in code updates. I'll reply
shortly with an example of that.

> --
> You received this message because you are subscribed to the Google Groups "google-gson" group.
> To post to this group, send email to googl...@googlegroups.com.
> To unsubscribe from this group, send email to google-gson...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/google-gson?hl=en.
>

Brandon Mintern

unread,
Apr 17, 2012, 3:07:29 PM4/17/12
to googl...@googlegroups.com
On Tue, Apr 17, 2012 at 11:49 AM, Brandon Mintern <min...@easyesi.com> wrote:
> You could perform some truly horrific introspection to sort in place,
> but it's highly susceptible to be broken in code updates. I'll reply
> shortly with an example of that.

Here I present a truly terrible means of sorting a JsonArray in place
that I by no means recommend using:

$ cat SortJsonArrayReflection.java
import com.google.gson.*;
import java.lang.reflect.Field;
import java.util.*;

class SortJsonArrayReflection {
private static final Field elements;
static {
try {
elements = JsonArray.class.getDeclaredField("elements");
elements.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new RuntimeException("JsonArray internal API has changed!");
}
}

public static List<JsonElement> getElementList(JsonArray arr) {
try {
return (List<JsonElement>) elements.get(arr);
} catch (IllegalArgumentException e) {
// this shouldn't happen in practice
} catch (IllegalAccessException e) {
// this shouldn't happen in practice
}
throw new RuntimeException("JsonArray internal API has changed!");
}

public static void main(String[] args) {
JsonArray myJsonArray = new
JsonParser().parse(args[0]).getAsJsonArray();

Collections.sort(getElementList(myJsonArray), new
JsonStringComparator());


for (JsonElement e: myJsonArray) {
System.out.println(e.getAsString());
}
}

public static class JsonStringComparator implements
Comparator<JsonElement> {
@Override
public int compare(JsonElement o1, JsonElement o2) {
if (o1 == null) {
return o2 == null ? 0 : -1;
} else if (o2 == null) {
return 1;
} else if (o1.isJsonNull()) {
return o2.isJsonNull() ? 0 : -1;
} else if (o2.isJsonNull()) {
return 1;
} else {
return o1.getAsString().compareTo(o2.getAsString());
}
}
}
}

$ javac -cp gson-2.1.jar SortJsonArrayReflection.java
Note: SortJsonArrayReflection.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
$ java -cp .:gson-2.1.jar SortJsonArrayReflection '["foo","bar","baz"]'
bar
baz
foo

Reply all
Reply to author
Forward
0 new messages