JSON反序列化:java.lang.Double无法强制转换为java.lang.Long

时间:2016-11-28 18:05:18

标签: java json gson

以下工作并在控制台上打印42:

long l = (new Gson()).fromJson("42", Long.class);
System.out.printf("[%d]\n", l);

以下也适用并打印相同的内容:

final Type TYPE = new TypeToken<Long>() {}.getType();
long l = (new Gson()).fromJson("42", TYPE); 

...但是下面的内容不起作用:

  private static <T> T fromJSON(String json, Class<T> klass) {
     final Type TYPE = new TypeToken<T>() {}.getType();  
     T rv = (new Gson()).fromJson(json, TYPE);   
     return rv;
  }

  public static void main(String args[]) throws Exception {
     long l = fromJSON("42", Long.class);  // line where the exception is thrown
  }

...以上引发了以下异常:

Exception in thread "main" java.lang.ClassCastException: java.lang.Double
cannot be cast to java.lang.Long

...在源中标记的行。

完整的痕迹很浅,只有这一行:

 [java] Exception in thread "main" java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Long
 [java]     at FooMain.main(FooMain.java:18)

为什么会发生这种情况,为什么在编译时没有检测到问题?

我用gson 2.8.0测试了这个。

我认为这可能与在运行时擦除的泛型类型信息有关,因此可能无法在运行时基于提供的泛型类型构造TypeToken

经过进一步的实验证明,我得到的例外情况与我正在做的完全相同:

private static Object fromJSON(String json) {
    final Type TYPE = new TypeToken<Object>() {}.getType();
    Object rv = (new Gson()).fromJson(json, TYPE);
    return rv;
}

public static void main(String args[]) throws Exception {
    long l = (long) fromJSON("42");
}

...上面在运行时产生完全相同的跟踪,这与类型擦除解释一致。所以我想我们只需要等到Java 9。

1 个答案:

答案 0 :(得分:2)

简短的回答是&#34;类型擦除&#34;。

答案越长,代码的通用版本 - new TypeToken<T>()调用 - 不会为每次调用记录不同的类型值。 T的值仅在编译时使用,在运行时不可用,并且只有一个运行时版本的代码必须处理可传递给它的每个值。 / p>

结果是Gson最终试图解析&#34; T&#34;类型的值,并且无法知道T实际上是{{1 }}。因此它根据内容猜测,内容是一个数字,它与数字类型一起使用,具有最广泛的可能值 - Long