如何防止gson将整数转换为双精度 [英] How can I prevent gson from converting integers to doubles
问题描述
我的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屋!