如何防止gson将整数转换为双精度 [英] How can I prevent gson from converting integers to doubles

查看:654
本文介绍了如何防止gson将整数转换为双精度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的json中有整数,我不希望gson将它们转换为双精度。以下不起作用:

  @Test 
public void keepsIntsAsIs(){
String json = [{\ id\:1,\ quantity\:2,\ name\:\ apple\},{\ id\:3, \ quantity\:4,\ name\:\ orange\}];
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Double.class,new DoubleSerializerAsInt());
Gson gson = gsonBuilder.create();
List< Map< String,Object>> l = gson.fromJson(json,List.class);
for(Map< String,Object> item:l){
System.out.println(item);



private static class DoubleSerializerAsInt implements JsonSerializer< Double> {
$ b $ @Override
public JsonElement serialize(Double aDouble,Type类型,JsonSerializationContext jsonSerializationContext){
int value =(int)Math.round(aDouble);
返回新的JsonPrimitive(value);


输出不是我想要的:

  {id = 1.0,quantity = 2.0,name = apple} 
{id = 3.0,quantity = 4.0,name = orange }

有没有办法在我的地图中使用整数而不是双精度?

  {id = 1,quantity = 2,name = apple} 
{id = 3,quantity = 4,name = orange}

编辑:并非所有的字段都是整数。我相应地修改了我的示例。
我在网上阅读了很多例子,包括本网站的一些答案,但在这种特殊情况下它不起作用。

解决方案

c $ c> JsonSerializer 就像你的问题。

2)我不认为这种行为来自 Double 解串器。它更像是json对象/映射问题。

这是来自源代码

  case NUMBER:
return in.nextDouble();

所以你可以尝试使用自定义解串器来处理 Map< String,Object> (或者一些更通用的地图,如果你想的话):

  public static class MapDeserializerDoubleAsIntFix implements JsonDeserializer< Map< ;字符串,对象>> {

@Override @SuppressWarnings(unchecked)
public Map< String,Object> (JsonElement json,类型typeOfT,JsonDeserializationContext上下文)抛出JsonParseException {
return(Map< String,Object>)read(json);

$ b $ 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));
}
返回列表;
} else if(in.isJsonObject()){
Map< String,Object> map = new LinkedTreeMap< String,Object>();
JsonObject obj = in.getAsJsonObject();
Set< Map.Entry< String,JsonElement>> entitySet = obj.entrySet(); (Map.Entry< String,JsonElement> entry:entitySet){
map.put(entry.getKey(),read(entry.getValue()));
}
返回地图;
} 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();
//在这里你可以处理double int / long值
//并返回任何你想要的类型
//这个解决方案将3.0 float转换为long值
if(Math。 ceil(num.doubleValue())== num.longValue())
返回num.longValue();
else {
return num.doubleValue();
}
}
}
返回null;




$ b $ p
$ b

要使用它,你必须给出正确的 TypeToken registerTypeAdapter gson.fromJson 函数:

 字符串json =[{\id \:1,\quantity \:2,\name \:\apple \},{\id \:3,\quantity \:4,\name \:\orange \} ]; 

GsonBuilder gsonBuilder = new GsonBuilder();

gsonBuilder.registerTypeAdapter(new TypeToken< Map< String,Object>>(){}。getType(),new MapDeserializerDoubleAsIntFix());

Gson gson = gsonBuilder.create();
List< Map< String,Object>> l = gson.fromJson(json,new TypeToken< List< Map< String,Object>>>(){}。getType());

(Map< String,Object> item:l)
System.out.println(item);

String serialized = gson.toJson(l);
System.out.println(serialized);

结果:

  {id = 1,quantity = 2,name = apple} 
{id = 3,quantity = 4,name = orange}
序列化回: [{id:1,quantity:2,name:apple},{id:3,quantity:4,name:orange}]






PS:这是您可以尝试的另一种选择。就我个人而言,我觉得为您的json创建自定义对象而不是 List< Map< String,Integer>> 更酷更容易阅读方式

I've got integers in my json, and I do not want gson to convert them to doubles. The following does not work:

@Test
public void keepsIntsAsIs(){
    String json="[{\"id\":1,\"quantity\":2,\"name\":\"apple\"},{\"id\":3,\"quantity\":4,\"name\":\"orange\"}]";
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(Double.class,  new DoubleSerializerAsInt());
    Gson gson = gsonBuilder.create();
    List<Map<String, Object>> l = gson.fromJson(json, List.class);
    for(Map<String, Object> item : l){
        System.out.println(item);
    }
}

private static class DoubleSerializerAsInt implements JsonSerializer<Double>{

    @Override
    public JsonElement serialize(Double aDouble, Type type, JsonSerializationContext jsonSerializationContext) {
        int value = (int)Math.round(aDouble);
        return new JsonPrimitive(value);
    }
}

The output is not what I want:

{id=1.0, quantity=2.0, name=apple}
{id=3.0, quantity=4.0, name=orange}

Is there a way to have Integers instead of Doubles in my Map?

{id=1, quantity=2, name=apple}
{id=3, quantity=4, name=orange}

Edit: not all my fields are integer. I've modified my example accordingly. I've read quite a few examples online, including some answers on this site, but it does not work in this particular case.

解决方案

1) You have to create custom JsonDeserializer and not JsonSerializer like in your question.

2) I don't think this behavior comes from Double deserializer. it is more like json object/map problem

Here is from source code:

case NUMBER:
      return in.nextDouble();

So you can try approach with custom deserializer for Map<String, Object> (or some more generic map if you want) :

public static class MapDeserializerDoubleAsIntFix implements JsonDeserializer<Map<String, Object>>{

    @Override  @SuppressWarnings("unchecked")
    public Map<String, Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        return (Map<String, Object>) 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;
    }
}

To use it you will have to give proper TypeToken to registerTypeAdapter and gson.fromJson function:

String json="[{\"id\":1,\"quantity\":2,\"name\":\"apple\"}, {\"id\":3,\"quantity\":4,\"name\":\"orange\"}]";

GsonBuilder gsonBuilder = new GsonBuilder();

gsonBuilder.registerTypeAdapter(new TypeToken<Map <String, Object>>(){}.getType(),  new MapDeserializerDoubleAsIntFix());

Gson gson = gsonBuilder.create();
List<Map<String, Object>> l = gson.fromJson(json, new TypeToken<List<Map<String, Object>>>(){}.getType() );

for(Map<String, Object> item : l)
    System.out.println(item);

String serialized = gson.toJson(l);
System.out.println(serialized);

Result:

{id=1, quantity=2, name=apple}
{id=3, quantity=4, name=orange}
Serialized back to: [{"id":1,"quantity":2,"name":"apple"},{"id":3,"quantity":4,"name":"orange"}]


PS: It is just one more option you can try. Personally i feel like creating custom object for your json instead of List<Map<String, Integer>> is much cooler and easier to read way

这篇关于如何防止gson将整数转换为双精度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆