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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24926786/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 15:47:15  来源:igfitidea点击:

Make GSON deserialize numbers to integers or doubles

javajsongson

提问by Merchuk Hul

I am having a hard time with GSON.

我在 GSON 上遇到了困难。

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

我有一个简单的 JSON,我想将它反序列化为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).

对我来说,123 应该被解析为 int(或 long),123.4 应该被解析为 float(或 double),这对我来说真的很直观。

GSON on the other hand creates Doubles all the time.

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

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

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

My actual code:

我的实际代码:

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

回答by mayr

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.

混合这样的类型(整数与双打)并不是一个好方法。由于您使用 Object 作为类型,因此您将无法从地图中同时获得 Integers 和 Doubles。Gson 决定哪种类型更适合 Object。在您的情况下,它是 Double,因为所有值都可以加倍,但所有值都不能是整数。

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

如果确实需要混合类型,请尝试使用 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()));
    }

Output: [1, 2.5, 4, 5.66]

输出:[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]

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

回答by Praveen Kumar

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

}

回答by g00dnatur3

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.

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

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

回答by gcallea

If you are not bound to specifically use gsonlibrary you can solve this deserializing using Hymansonone as follow:

如果您不必专门使用gson库,则可以使用Hymansonone解决此反序列化问题,如下所示:

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

Here a complete junit test that expose the differences between the two libraries deserializing an integer value:

这是一个完整的 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 Hymanson library "intValue" is deserialized to 1
    Map<String,Object> HymansonMap = new ObjectMapper().readValue(jsonSource, new TypeReference<Map<String,Object>>() {});
    assertThat(new ObjectMapper().writeValueAsString(HymansonMap),is(jsonSource));

}