如何防止Gson将长号(json字符串)转换为科学记数法格式?

我需要将json字符串转换为java对象并将其显示为long。 json字符串是一个固定的长数组:

{numbers [ 268627104, 485677888, 506884800 ] } 

转换的代码在所有情况下都可以正常工作,除了以0结尾的数字。它将这些转换为科学记数字格式:

  public static Object fromJson(HttpResponse response, Class classOf) throws IOException { InputStream instream = response.getResponseInputStream(); Object obj = null; try { Reader reader = new InputStreamReader(instream, HTTP.UTF_8); Gson gson = new Gson(); obj = gson.fromJson(reader, classOf); Logger.d(TAG, "json --> "+gson.toJson(obj)); } catch (UnsupportedEncodingException e) { Logger.e(TAG, "unsupported encoding", e); } catch (Exception e) { Logger.e(TAG, "json parsing error", e); } return obj; } 

实际结果:Java对象:268627104,485677888,5.068848E + 8

请注意,最后一个数字将转换为科学记数法格式。 任何人都可以建议可以做些什么来解决它或阻止或撤消它? 我正在使用Gson v1.7.1

如果序列化为String是一个选项,您可以配置GSON来执行以下操作:

 GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setLongSerializationPolicy( LongSerializationPolicy.STRING ); Gson gson = gsonBuilder.create(); 

这将产生类似于:

 {numbers : [ "268627104", "485677888", "506884800" ] } 

另一种解决方法是使用JsonParser类。 这将返回Gson对象表示(JsonElement)而不是用户定义的类,但避免了转换为科学记数法的问题。

 import java.lang.reflect.Type; import java.util.Map; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; public class GsonTest { public static void main(String[] args) { String json = "{numbers:[268627104,485677888,506884800]}"; Gson gson = new Gson(); Type type = new TypeToken>(){}.getType(); Map jsonMap = gson.fromJson(json, type); System.out.println("Gson output:"); System.out.println(jsonMap); JsonParser jsonParser = new JsonParser(); JsonElement jsonElement = jsonParser.parse(json); System.out.println("JsonParser output:"); System.out.println(jsonElement); } } 

代码输出:

 Gson output: {numbers=[2.68627104E8, 4.85677888E8, 5.068848E8]} JsonParser output: {"numbers":[268627104,485677888,506884800]} 

我有一个类似的问题,它不仅将整数转换为double,而且实际上对于某些长数字也会失去精度,如相关问题所述 。

我跟踪了这​​个转换为ObjectTypeAdapterread方法,具体来说:

 case NUMBER: return in.nextDouble(); 

有可能插入一个修改过的TypeAdapter for Object ,但我无法使其工作,所以我只是将read方法( Object read(JsonReader in) )复制到我自己的代码中并将上面的行修改为:

 case NUMBER: final String s = in.nextString(); try { return Integer.parseInt(s); } catch (NumberFormatException e) { // ignore } try { return Long.parseLong(s); } catch (NumberFormatException e) { // ignore } return Double.parseDouble(s); 

我希望Gson默认这样做..

然后我把其他连接件放在一个看起来像这样的辅助方法中:

 public static Object parse(final Reader r) { try (final JsonReader jr = new JsonReader(r)) { jr.setLenient(true); boolean empty = true; Object o = null; try { jr.peek(); empty = false; o = read(jr); } catch (EOFException e) { if (!empty) { throw new JsonSyntaxException(e); } } if (o != null && jr.peek() != JsonToken.END_DOCUMENT) { throw new JsonIOException("JSON document was not fully consumed."); } return o; } catch (IOException e) { throw new JsonIOException(e); } } 

所以现在代替new Gson().fromJson(r, Object.class) ,我调用parse(r)

这对我很有用,因为我希望能够用任何结构解析json数据,但是如果你有一个特定的类,你可能只需要在该类的成员中消除Object出现。

得到同样的问题,经过一些调查后我发现了。

行为:

  • GSON
    对于没有小数部分的数字, Gson会将其转换为Double
  • jackson
    对于没有小数部分的数字, Jackson会将其转换为IntegerLong Integer ,取决于数字的大小。

可能的解决方案:

  • 明确地将Gson的返回值从Double转换为Long
  • Jackson代替。
    我更喜欢这个。

代码 – 测试Jackson

ParseNumberTest.java:

 import java.util.List; import org.testng.Assert; import org.testng.annotations.Test; import com.fasterxml.jackson.databind.ObjectMapper; /** * test - jackson parse numbers, * * @author eric * @date Jan 13, 2018 12:28:36 AM */ public class ParseNumberTest { @Test public void test() throws Exception { String jsonFn = "numbers.json"; ObjectMapper mapper = new ObjectMapper(); DummyData dd = mapper.readValue(this.getClass().getResourceAsStream(jsonFn), DummyData.class); for (Object data : dd.dataList) { System.out.printf("data type: %s, value: %s\n", data.getClass().getName(), data.toString()); Assert.assertTrue(data.getClass() == Double.class || data.getClass() == Long.class || data.getClass() == Integer.class); System.out.printf("%s\n\n", "------------"); } } static class DummyData { List dataList; public List getDataList() { return dataList; } public void setDataList(List dataList) { this.dataList = dataList; } } } 

numbers.json:

 { "dataList": [ 150000000000, 150778742934, 150000, 150000.0 ] } 

怎么运行:

  • 测试用例基于JacksonTestNG
  • numbers.json放在与ParseNumberTest.java相同的包中。
  • 作为testng测试运行,然后它将打印解析结果的类型和值。

输出:

 data type: java.lang.Long, value: 150000000000 ------------ data type: java.lang.Long, value: 150778742934 ------------ data type: java.lang.Integer, value: 150000 ------------ data type: java.lang.Double, value: 150000.0 ------------ PASSED: test 

不聪明,但仍然工作的方法是添加“在数字的开头和结尾。然后处理完成后,删除它。

我没有找到解决我的gson格式化数字的问题的解决方案,以0结尾的科学记数法。 我改为使用解决方法将这种科学记数法转换为用逗号格式化的双精度数。 “value”是json字符串。

  private String formatNumber(String value) { double dValue = Double.parseDouble(value); String pattern = "#,###"; DecimalFormat formatter = new DecimalFormat(pattern); String newNumber = formatter.format(dValue); return newNumber; } 

这不能回答问题,但是解决问题的另一个步骤是显示系统所需的数字。