Make GSON deserialize numbers to integers or doubles

I am having a hard time with GSON.

I have a simple JSON that I want to deserialize to a Map<String,Object> .

It's really intuitive to me that 123 should be parsed as an int (or long), 123.4 as a float( or double).

GSON on the other hand creates Doubles all the time.

Can I tell GSON to not abuse double all the time?

My actual code:

Type mapType = new TypeToken<Map<String, Object>>() {}.getType();
GSON gson = new Gson();
Map<String, Object> map = gson.fromJson(someString, mapType);

The following code compiles & works:

package test;

import java.lang.reflect.Type;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;

public class Main {

    public static void main(String[] args) {
        GsonBuilder builder = new GsonBuilder();
        builder.registerTypeAdapter(Object.class, new MyObjectDeserializer());
        Gson gson = builder.create();
        String array = "[1, 2.5, 4, 5.66]";

        Type objectListType = new TypeToken<ArrayList<Object>>() {}.getType();
        List<Object> obj = gson.fromJson(array, objectListType);

        System.out.println(Arrays.toString(obj.toArray()));
    }

    public static class MyObjectDeserializer implements JsonDeserializer<Object> {

        public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 
            throws JsonParseException {

          Number num = null;
          try {
              num = NumberFormat.getInstance().parse(json.getAsJsonPrimitive().getAsString());
          } catch (Exception e) {
              //ignore
          }
          if (num == null) {
              return context.deserialize(json, typeOfT);
          } else {
              return num;
          }
      }
    }

}

My solution will first try to parse the string as a number, if that fails it will let the standard Gson deserializer do the work.

If you need a number parser that is not locale specific use this method to parse a number:

private static Number parse(String str) {
    Number number = null;
    try {
        number = Float.parseFloat(str);
    } catch(NumberFormatException e) {
    try {
        number = Double.parseDouble(str);
    } catch(NumberFormatException e1) {
        try {
            number = Integer.parseInt(str);
        } catch(NumberFormatException e2) {
            try {
                number = Long.parseLong(str);
            } catch(NumberFormatException e3) {
                throw e3;
            }       
        }       
    }       
}
    return number;
}

You can do the following changes in order to parse that data:

   testData1={"GOAL1":123, "GOAL2":123.45,"GOAL5":1256,"GOAL6":345.98}

and below is your code to actually parse it.

Type mapType = new TypeToken<Map<String, Object>>() {
}.getType();
String str = prop.getProperty("testData1");
System.out.println(str);
Gson gson = new Gson();
Map<String, Object> map = gson.fromJson(str, mapType);
for (String key : map.keySet()) {
    String a = null;
    try {

        if (map.get(key) instanceof Double) {
            a = "" + map.get(key);

        } else {
            if (map.get(key) instanceof String) {
                a = (String) map.get(key);

            } else {
                a = null;
            }
        }

        if (a != null && a.contains(".") && !a.endsWith(".0")) {

            // Convert it into Double/Float
        } else {
            // Work as Integer
        }

    } catch (Exception ex) {
        ex.printStackTrace();
    }

}

It's not a good aproach to mix types like this (integers with doubles). Since you are using Object as a type, you won't be able to get both Integers and Doubles from the map. Gson decides which type is more apropriate for Object. In your case it is Double, because all values CAN BE doubles, but all values CAN'T BE integers.

If you really need to mix types, try to use Number class instead of Object. Example:

public static void main(String[] args){
        String array = "[1, 2.5, 4, 5.66]";
        Gson gson = new Gson();

        Type type = new TypeToken<ArrayList<Number>>() {}.getType();
        List<Number> obj = gson.fromJson(array, type);

        System.out.println(Arrays.toString(obj.toArray()));
    }

Output: [1, 2.5, 4, 5.66]

While this:

public static void main(String[] args){
    String array = "[1, 2.5, 4, 5.66]";
    Gson gson = new Gson();

    Type type = new TypeToken<ArrayList<Object>>() {}.getType();
    List<Object> obj = gson.fromJson(array, type);

    System.out.println(Arrays.toString(obj.toArray()));
}

will give you output: [1.0, 2.5, 4.0, 5.66]

链接地址: http://www.djcxy.com/p/80654.html

上一篇: 为什么在C#中“int []是uint [] == true”

下一篇: 使GSON反序列化数字为整数或双精度