如何防止Gson将整数表示为浮点数

Mar*_*phy 55 java android gson

当我尝试将字符串转换为json时,Gson有一些奇怪的行为.下面的代码将字符串草稿转换为json响应.有没有办法阻止gson将'.0添加到所有整数值?

ArrayList<Hashtable<String, Object>> responses;
Type ResponseList = new TypeToken<ArrayList<Hashtable<String, Object>>>() {}.getType();
responses = new Gson().fromJson(draft, ResponseList);

draft:
[ {"id":4077395,"field_id":242566,"body":""},
  {"id":4077398,"field_id":242569,"body":[[273019,0],[273020,1],[273021,0]]},
  {"id":4077399,"field_id":242570,"body":[[273022,0],[273023,1],[273024,0]]}
]

responses:
[ {id=4077395.0, body=, field_id=242566.0},
  {id=4077398.0, body=[[273019.0, 0.0], [273020.0, 1.0], [273021.0, 0.0]], field_id=242569.0},
  {id=4077399.0, body=[[273022.0, 0.0], [273023.0, 1.0], [273024.0, 0.0]], field_id=242570.0}
]
Run Code Online (Sandbox Code Playgroud)

See*_*ker 53

从2.8.9版本开始,库提供了一个解决方案。

\n

我们可以通过该方法设置Object如何转换为数字GsonBuilder.setObjectToNumberStrategy()

\n

LONG_OR_DOUBLE在这种情况下,实施将起作用。可以用作

\n
Gson gson = new GsonBuilder()\n    .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)\n    .create();\nresponses = gson.fromJson(draft, ResponseList);\n
Run Code Online (Sandbox Code Playgroud)\n

有关详细信息,请参阅 GitHub 拉取请求:支持对象和数字反序列化的任意数字实现,由 lyubomyr-shaydariv \xc2\xb7 拉取请求 #1290 \xc2\xb7 google/gson \xc2\xb7 GitHub

\n

  • 这应该是公认的解决方案。谢谢。 (2认同)

dim*_*414 40

你告诉Gson它正在寻找一个Strings to Objects的地图列表,它实际上是为了对它的类型做出最佳猜测.由于JSON不区分整数和浮点字段,因此对于数字字段,Gson必须默认为Float/Double.

Gson从根本上构建用于检查要填充的对象的类型,以确定如何解析数据.如果你没有给它任何暗示,那就不会很好.一种选择是定义一个自定义的JsonDeserializer,但更好的方法是不使用HashMap(绝对不使用Hashtable!),而是给Gson更多关于它期望的数据类型的信息.

class Response {
  int id;
  int field_id;
  ArrayList<ArrayList<Integer>> body; // or whatever type is most apropriate
}

responses = new Gson()
            .fromJson(draft, new TypeToken<ArrayList<Response>>(){}.getType());
Run Code Online (Sandbox Code Playgroud)

同样,Gson的重点是将结构化数据无缝转换为结构化对象.如果你要求它创建一个几乎未定义的结构,比如对象的映射列表,那么你就会击败Gson的整个点,并且可能会使用一些更简单的JSON解析器.


Mar*_*man 25

这有效:

 Gson gson = new GsonBuilder().
        registerTypeAdapter(Double.class,  new JsonSerializer<Double>() {   

    @Override
    public JsonElement serialize(Double src, Type typeOfSrc, JsonSerializationContext context) {
        if(src == src.longValue())
            return new JsonPrimitive(src.longValue());          
        return new JsonPrimitive(src);
    }
 }).create();
Run Code Online (Sandbox Code Playgroud)

  • 嗨,我发现这个答案,并使用你在这篇文章中提到的方式,但仍然,我得到双倍,它应该是int :-( (10认同)

Leo*_*eon 6

基本上,这个问题没有完美的答案.所有"解决方案"仅适用于某些情况.这是向gson团队报告的一个问题,遗憾的是他们似乎坚持认为"javascript没有整数类型",好像他们没有意识到gson是针对java而不是javascript.所以他们拒绝修复它直到今天(现在是2018年),尽管像杰克逊这样的其他lib根本没有这样的问题,尽管有多容易修复它.因此,您可能必须自己从gson源代码中修复问题并构建自己的gson.jar.源文件是gson/src/main/java/com/google/gson/internal/bind/ObjectTypeAdapter.java

case NUMBER:
   return in.nextDouble();
Run Code Online (Sandbox Code Playgroud)


Ste*_*tad 5

我参加聚会很晚,但是我自己碰到了这个。就我而言,我不想在ArrayList中指定一个Integer类型-因为它可以是String或Integer。

我的解决方案如下:

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Double.class,  new JsonSerializer<Double>() {

    public JsonElement serialize(Double src, Type typeOfSrc,
                JsonSerializationContext context) {
            Integer value = (int)Math.round(src);
            return new JsonPrimitive(value);
        }
    });

Gson gs = gsonBuilder.create();
Run Code Online (Sandbox Code Playgroud)

而不是使用默认的Gson定义Gson gs = new Gson();,我重写了Double.class序列化以返回整数。

就我而言,我的JSON中包含Strings和Integers,但是我没有任何双打,因此这没有问题。

如果您需要一个double或float值,我想可以添加一些逻辑来测试每种数据类型特定的属性的值并返回适当的值。就像是

if(/*source has a decimal point*/){
  return new JsonPrimitive(src); 
} else if (/* source has some attribute of a Float */){
  Float value = /*convert the src value from double to a Float */;
  return new JsonPrimitive(value);
} else {
  //it looks like an integer
  Integer value = (int)Math.round(src);
  return new JsonPrimitive(value);
}
Run Code Online (Sandbox Code Playgroud)

我不知道如何测试或转换这些数据类型,但这应该使您走上正确的道路。

  • 在我看来,听到“ *它可以是字符串或整数*”是一个很大的危险信号。听起来您的JSON数据结构不好-您正在创建整数和字符串的列表吗?从技术上讲,JSON规范允许这样做,但是这会给尝试与其进行接口的每个反序列化器带来麻烦。而是考虑a)如果只是一些数字巧合而留下整个列表字符串,b)将数字分成自己的列表,或者c)将列表类型更改为更复杂的对象,以更好地反映数据。 (3认同)