使GSON将数字反序列化为整数或双精度数

时间:2014-07-24 06:44:42

标签: java json gson

我在使用GSON时遇到了困难。

我有一个简单的JSON,我想反序列化为Map<String,Object>

对我而言,123应该被解析为int(或long),123.4作为float(或double)解析。

另一方面,GSON一直创造双打。

我可以告诉GSON不要一直滥用双倍吗?

我的实际代码:

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

4 个答案:

答案 0 :(得分:3)

以下代码编译&amp;工作原理:

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;
          }
      }
    }

}

我的解决方案将首先尝试将字符串解析为数字,如果失败则会让标准的Gson解串器完成工作。

如果您需要一个非特定于语言环境的数字解析器,请使用此方法解析数字:

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;
}

答案 1 :(得分:1)

混合这样的类型(双打整数)并不是一个好方法。由于您使用Object作为类型,因此您无法从地图中获取整数和双精度。 Gson决定哪种类型更适合Object。在你的情况下,它是Double,因为所有值都可以加倍,但所有值都是CAN&#39; T BE整数。

如果确实需要混合类型,请尝试使用Number类而不是Object。例如:

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()));
    }

输出:[1,2.5,4,5.66]

虽然这个:

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()));
}

会给你输出:[1.0,2.5,4.0,5.66]

答案 2 :(得分:0)

您可以执行以下更改以解析该数据:

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

及以下是您实际解析它的代码。

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();
    }

}

答案 3 :(得分:0)

如果您不必专门使用 gson 库,则可以使用 jackson 一种解决以下反序列化的方法:

new ObjectMapper().readValue(yourJson, new TypeReference<Map<String,Object>>() {});

下面是一个完整的junit测试,该测试揭示了两个库之间的差异,即反序列化一个整数值:

@Test
public void integerDeserializationTest() throws Exception {

    final String jsonSource = "{\"intValue\":1,\"doubleValue\":2.0,\"stringValue\":\"value\"}";

    //Using gson library "intValue" is deserialized to 1.0
    final String gsonWrongResult = "{\"intValue\":1.0,\"doubleValue\":2.0,\"stringValue\":\"value\"}";
    Map<String,Object> gsonMap = new Gson().fromJson(jsonSource, new TypeToken<Map<String, Object>>() {
    }.getType());
    assertThat(new Gson().toJson(gsonMap),is(gsonWrongResult));


    //Using jackson library "intValue" is deserialized to 1
    Map<String,Object> jacksonMap = new ObjectMapper().readValue(jsonSource, new TypeReference<Map<String,Object>>() {});
    assertThat(new ObjectMapper().writeValueAsString(jacksonMap),is(jsonSource));

}