java Gson.toJson 给出了 StackOverFlowError,在这种情况下如何获得正确的 json?(公共静态类)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13460200/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 12:48:53  来源:igfitidea点击:

Gson.toJson gives StackOverFlowError, how to get proper json in this case? (public static class)

javaandroidjson

提问by Jeroen

I currently have the following class:

我目前有以下课程:

 static final class TabInfo{
   public final String tag;
   public final Class<?> clss;
   public Bundle args;

   TabInfo(String _tag, Class<?> _class, Bundle _args) {
       tag = _tag;
       clss = _class;
       args = _args;
   }
 }

of which I would like to create json out of. In order to do this, I am using the following code:

我想从中创建json。为了做到这一点,我使用了以下代码:

 Gson gson= new Gson();
 Type hmType= new TypeToken<TabInfo>(){}.getType();
 String json = gson.toJson(methodToGetAnInstanceOfTabInfoClassHere, hmType);

When I am doing this, I get a java.lang.StackOverFlowError:

当我这样做时,我得到一个 java.lang.StackOverFlowError:

E/AndroidRuntime(10353):    at Java.lang.StringBuffer.append(StringBuffer.java:219)
E/AndroidRuntime(10353):    at java.io.StringWriter.write(StringWriter.java:147)
E/AndroidRuntime(10353):    at com.google.gson.stream.JsonWriter.string(JsonWriter.java:519)
E/AndroidRuntime(10353):    at com.google.gson.stream.JsonWriter.writeDeferredName(JsonWriter.java:387)
E/AndroidRuntime(10353):    at com.google.gson.stream.JsonWriter.beginObject(JsonWriter.java:300)
E/AndroidRuntime(10353):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:190)
E/AndroidRuntime(10353):    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrap    E/AndroidRuntime(20692):     at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.write(ReflectiveTypeAdapterFactory.java:89)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.write(ReflectiveTypeAdapterFactory.java:89)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.write(ReflectiveTypeAdapterFactory.java:89)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.write(ReflectiveTypeAdapterFactory.java:89)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.write(ReflectiveTypeAdapterFactory.java:89)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.write(ReflectiveTypeAdapterFactory.java:89)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.write(ReflectiveTypeAdapterFactory.java:89)
E/AndroidRuntime(20692):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)

So, my question is: how can I get my gson to create valid json of the java objects from class TabInfo without getting a stackoverflowerror?

所以,我的问题是:如何让我的 gson 从 TabInfo 类创建 Java 对象的有效 json 而不会出现 stackoverflowerror?

Btw. as all of you can see, I have not asked that many questions before, so if you have any feedback for me on how to improve my question: let me know!

顺便提一句。正如你们所看到的,我以前没有问过那么多问题,所以如果你们对我的问题有任何反馈,请告诉我如何改进我的问题:让我知道!

EDIT 1:The bundle class is a standard bundle, fi: Bundle args = new Bundle(); args.putint("someint", 1);

编辑 1:bundle 类是一个标准的 bundle,fi: Bundle args = new Bundle(); args.putint("someint", 1);

See the updated stacktrace...

查看更新的堆栈跟踪...

EDIT 2:If I take a single instance of a TabInfo, by using a String.class as an argument, eg:

编辑 2:如果我采用 TabInfo 的单个实例,通过使用 String.class 作为参数,例如:

  TabInfo test= new TabInfo("test", String.class, new Bundle());
  String result=gson.toJson(test, hmType);

Then I get the following stacktrace:

然后我得到以下堆栈跟踪:

E/AndroidRuntime(22068): java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: java.lang.String. Forgot to register a type adapter?
E/AndroidRuntime(22068):    at com.google.gson.internal.bind.TypeAdapters.write(TypeAdapters.java:64)
E/AndroidRuntime(22068):    at com.google.gson.internal.bind.TypeAdapters.write(TypeAdapters.java:61)
E/AndroidRuntime(22068):    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
E/AndroidRuntime(22068):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.write(ReflectiveTypeAdapterFactory.java:89)
E/AndroidRuntime(22068):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
E/AndroidRuntime(22068):    at com.google.gson.Gson.toJson(Gson.java:586)
E/AndroidRuntime(22068):    at com.google.gson.Gson.toJson(Gson.java:565)
E/AndroidRuntime(22068):    at com.google.gson.Gson.toJson(Gson.java:520)

Does this mean that I need to make a TypeToken for all 24 different classes that might be part of a TabInfo class? How do I resolve this?

这是否意味着我需要为可能属于 TabInfo 类的所有 24 个不同类创建一个 TypeToken?我该如何解决?

Edit 3

编辑 3

Ok, thanks to @Zaske, I have found a fix for the first part of my problem. Using another class signature as shown below

好的,感谢@Zaske,我找到了解决问题第一部分的方法。使用另一个类签名,如下所示

static final class TabInfo{
 TabInfo(String _tag, String _class, Bundle _args) {
   tag = _tag;
   clss = _class;
   args = _args;
 }

}

Now I can make json out of it, but, when I try to do this by creating the actual HashMap < String, < Stack < TabInfo > > > then again I run into trouble. The typetoken i use in that case is:

现在我可以用它来制作 json,但是,当我尝试通过创建实际的 HashMap < String, < Stack < TabInfo > > > 来做到这一点时,我又遇到了麻烦。我在这种情况下使用的 typetoken 是:

 Type hmType = new TypeToken<HashMap<String, Stack<TabInfo>>>(){}.getType();

So, now my final question is: how can I convert a set of tabinfo-stacks in a hashmap to json?

所以,现在我的最后一个问题是:如何将哈希图中的一组 tabinfo 堆栈转换为 json?

Edit 4Here's some more information: The used Bundle class is the Bundle class used in Android to provide arguments to activities and fragments. (See http://developer.android.com/reference/android/os/Bundle.html)

编辑 4这里有更多信息:使用的 Bundle 类是 Android 中用于为活动和片段提供参数的 Bundle 类。(见http://developer.android.com/reference/android/os/Bundle.html

If I do

如果我做

 TabInfo test= new TabInfo("test", "String", new Bundle());
 //stage 1 test
 String result=gson.toJson(test);
 Log.d("new result=",result);

Then I do get my Json output (see below)

然后我得到了我的 Json 输出(见下文)

 D/new result=(20816): {"args":{"mClassLoader":{"packages":{}},"mMap":{},"mHasFds":false,"mFdsKnown":true,"mAllowFds":true},"clss":"String","tag":"test"}

However, when I try to make a Hashmap of stacks out of the TabInfo classes, then it breaks (it runs out of memory...)...

但是,当我尝试从 TabInfo 类中创建堆栈的 Hashmap 时,它会中断(内存不足......)...

采纳答案by Yair Zaslavsky

As I suggested the "change from class" to string,
I allow myself for the sake of our readers to answer here for the first part:
Don't use Class as a field, but use String that will contain the full class name
TabInfo should look like:

当我建议“从类更改”为字符串时,
为了我们的读者,我允许自己在第一部分回答:
不要使用类作为字段,而是使用包含完整类名
TabInfo 的字符串看起来像:

static final class TabInfo{
   public final String tag;
   public final String clss;
   public Bundle args;

   TabInfo(String _tag, Class<?> _class, Bundle _args) {
       tag = _tag;
       clss = _class.getName();
       args = _args;
   }
 }




Regarding 2nd part:
I don't know what Bundle class is - please provide info,
as I had to change a bit and write my own class for experiment.




关于第二部分:
我不知道 Bundle 类是什么 - 请提供信息,
因为我不得不进行一些更改并编写自己的类进行实验。

Person class is:

人类是:

public class Person implements Serializable {
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public Person() {

    }

    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    private String name;
    private int age;
}

Main class for checking is:

检查的主要类是:

public class Main {
    public static void main(String[] args) {
        Type type = new TypeToken<HashMap<String,Stack<Person>>>(){}.getType();
        Gson gson = new Gson();
        HashMap<String,Stack<Person>> map = new HashMap<String, Stack<Person>>();
        map.put("yair", new Stack<Person>());
        map.get("yair").add(new Person("Yair",36));
        String str = gson.toJson(map,type);
        System.out.println(str);
        map = gson.fromJson(str,type);
        String str2 = gson.toJson(map,type);
        System.out.println(str2);

    }
}

Feel free to run it, you will see both str and str2 are printed just fine.

随意运行它,你会看到 str 和 str2 都打印得很好。

Update
I checked the Bundle class, and saw that it contains too much information (In my humble opinion) to be a simple arguments collection.
I don't see why in the above question a simple collection cannot be used instead.
Serialization should contain as minimal data as possible
(think about cases in which you take a serialized data and store it on some storage device, or send it over the network). So unless Bundle provides you a special functionality that a collection doesn't - don't use it.
As a rule of thumb remember you cannot serialize everything with Json - there are limitations (recursive data-types for example) - so yes, there will be cases where you will have to translate from one type to a JSON-serializable type.
This pattern is also used in other cases, I suggest you read more about data transfer objects

更新
我检查了 Bundle 类,发现它包含太多信息(以我的拙见)作为一个简单的参数集合。
我不明白为什么在上面的问题中不能使用简单的集合。
序列化应包含尽可能少的数据
(考虑将序列化数据存储在某个存储设备上或通过网络发送的情况)。因此,除非 Bundle 为您提供了集合没有的特殊功能 - 不要使用它。
根据经验,您不能使用 Json 序列化所有内容 - 存在限制(例如递归数据类型) - 所以是的,在某些情况下,您必须从一种类型转换为 JSON 可序列化类型。
这种模式也用于其他情况,建议您阅读更多有关数据传输对象的信息