11

I have an ArrayList which contains ArrayLists, each ArrayList in the Root list contains one ArrayList of Integers and one of Strings. I am converting it with Gson to a String to save it with SharedPreferences. But when I am reconverting it, Gson gives me 2.131558489E9 instead of the original int 2131558489. How can I fix this Problem? Best Regards.

Here is how I convert the ArrayList: levelPattern is the ArrayList

String levelPatternGson = new Gson().toJson(levelPattern);

And this is how I convert it back:

levelPattern = new Gson().fromJson(levelPatternGson, ArrayList.class);
Chinaedu Onwukwe
  • 437
  • 1
  • 7
  • 20
  • 1
    Convert ArrayList to an ArrayList of Strings. Why don't you do this? – Alireza Mohamadi May 07 '16 at 17:28
  • you are defenitly doing something wrong when serializing to json... Can you please post the code so I can see where the issue could be at? – ΦXocę 웃 Пepeúpa ツ May 07 '16 at 17:35
  • If want to convert you only ArrayList into string you should use toString() method. I also convert arraylist to string using gson and getting desired result 2131558489. Add your code that is used to convert arraylist to string using gson – USKMobility May 07 '16 at 17:56
  • Possible duplicate of [How to prevent Gson from converting a long number (a json string ) to scientific notation format?](http://stackoverflow.com/questions/11586299/how-to-prevent-gson-from-converting-a-long-number-a-json-string-to-scientific) – OneCricketeer May 07 '16 at 18:17

2 Answers2

8

There is no difference in json standard between integers and doubles, there is only number type. That is why gson by default converts numbers to doubles if you don't give him what type you want.

Easy fix would be to use TypeToken and change data structure to multiple arrays or custom object (like in @totoro demo).

new Gson().fromJson(levelPatternGson, new TypeToken<List<Integer>>() {}.getType());

But you could also write custom List deserializer:

public static class ListDeserializerDoubleAsIntFix implements JsonDeserializer<List>{

    @Override  @SuppressWarnings("unchecked")
    public List deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        return (List) read(json);
    }

    public Object read(JsonElement in) {

        if(in.isJsonArray()){
            List<Object> list = new ArrayList<Object>();
            JsonArray arr = in.getAsJsonArray();
            for (JsonElement anArr : arr) {
                list.add(read(anArr));
            }
            return list;
        }else if(in.isJsonObject()){
            Map<String, Object> map = new LinkedTreeMap<String, Object>();
            JsonObject obj = in.getAsJsonObject();
            Set<Map.Entry<String, JsonElement>> entitySet = obj.entrySet();
            for(Map.Entry<String, JsonElement> entry: entitySet){
                map.put(entry.getKey(), read(entry.getValue()));
            }
            return map;
        }else if( in.isJsonPrimitive()){
            JsonPrimitive prim = in.getAsJsonPrimitive();
            if(prim.isBoolean()){
                return prim.getAsBoolean();
            }else if(prim.isString()){
                return prim.getAsString();
            }else if(prim.isNumber()){
                Number num = prim.getAsNumber();
                // here you can handle double int/long values
                // and return any type you want
                // this solution will transform 3.0 float to long values
                if(Math.ceil(num.doubleValue())  == num.longValue())
                    return num.longValue();
                else{
                    return num.doubleValue();
                }
            }
        }
        return null;
    }
}

and use it like this:

GsonBuilder builder=new GsonBuilder();
List<List> levelPattern = Arrays.asList(Arrays.asList(2131558489L, 2L, 3L), 
                                        Arrays.asList("one", "two", "three"));
String levelPatternGson = new Gson().toJson(levelPattern);
List levelPattern2 = new GsonBuilder()
        .registerTypeAdapter(List.class, new ListDeserializerDoubleAsIntFix())
        .create()
        .fromJson(levelPatternGson, List.class);

System.out.println(levelPattern2);

Json: [[2131558489,2,3],["one","two","three"]]

Output: [[2131558489, 2, 3], [one, two, three]]

Community
  • 1
  • 1
varren
  • 14,551
  • 2
  • 41
  • 72
  • How does that cover his `List`? – totoro May 07 '16 at 21:01
  • @totoro Thx, yep you are right, this answer was incomplete. Updated the post. I wanted to add http://stackoverflow.com/a/36529534/1032167 this link at the end but forgot to post changes. – varren May 07 '16 at 21:24
  • @totoro i still would prefere your solution with custom object or maybe multiple arraylists, or maybe `Map` because it is usually hard to work with `List>` but who knows, maybe OP really needs this data structure – varren May 07 '16 at 21:35
6

I am not sure I understand the question completely...

I am assuming your ArrayList is not using generics.

This solution is a generics version, using an Object to hold the two different typed ArrayLists.

class Test {

    static class Bar {
        private List<Integer> integers;
        private List<String> strings;
    }

    public static void main(String[] argv) {
        Type baseType = new TypeToken<List<Bar>>() {}.getType();
        List<Bar> foos = new ArrayList<>();

        Bar bar;

        bar = new Bar();
        bar.integers = Arrays.asList(1, 2, 3, 4);
        bar.strings = Arrays.asList("a", "b", "c", "d");
        foos.add(bar);

        bar = new Bar();
        bar.integers = Arrays.asList(5, 6, 7, 2131558489);
        bar.strings = Arrays.asList("e", "f", "g", "h");
        foos.add(bar);

        Gson gson = new Gson();
        String tmp = gson.toJson(foos, baseType);
        System.out.println(tmp);
        foos = gson.fromJson(tmp, baseType);
        System.out.print(foos.get(1).integers.get(3));
    }
}

Output

JSON: [{"integers":[1,2,3,4],"strings":["a","b","c","d"]},{"integers":[5,6,7,2131558489],"strings":["e","f","g","h"]}]

The Integer: 2131558489

totoro
  • 2,469
  • 2
  • 19
  • 23