简体   繁体   English

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

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

I currently have the following class:我目前有以下 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.我想从中创建 json 。 In order to do this, I am using the following code:为此,我使用以下代码:

 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$1.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$1.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$1.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$1.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$1.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$1.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$1.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? 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?

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();编辑 1:捆绑包 class 是标准捆绑包,fi: Bundle args = new Bundle(); args.putint("someint", 1); 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$1.write(TypeAdapters.java:64)
E/AndroidRuntime(22068):    at com.google.gson.internal.bind.TypeAdapters$1.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$1.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?这是否意味着我需要为可能属于 TabInfo class 的所有 24 个不同类创建一个 TypeToken? How do I resolve this?我该如何解决这个问题?

Edit 3编辑 3

Ok, thanks to @Zaske, I have found a fix for the first part of my problem.好的,感谢@Zaske,我找到了解决问题第一部分的方法。 Using another class signature as shown below使用另一个 class 签名,如下所示

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.现在我可以用它制作 json,但是,当我尝试通过创建实际的 HashMap < String, < Stack < TabInfo >> > 来做到这一点时,我又遇到了麻烦。 The typetoken i use in that case is:我在这种情况下使用的 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?所以,现在我的最后一个问题是:如何将 hashmap 中的一组 tabinfo 堆栈转换为 json?

Edit 4 Here's some more information: The used Bundle class is the Bundle class used in Android to provide arguments to activities and fragments.编辑 4这里有一些更多信息: 使用的 Bundle class 是用于 Android 的 Bundle class 用于向活动提供 ZDBC11CAABD5BDA99E7DZ2786 活动(See http://developer.android.com/reference/android/os/Bundle.html ) (见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 output (见下文)

 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 时,它会中断(它用完 memory ...)...

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 不要将Class用作字段,而是使用包含完整类名的String
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, 我不知道Bundle课程是什么 - 请提供信息,
as I had to change a bit and write my own class for experiment. 因为我不得不改变一点并写自己的课程进行实验。

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. 我查看了Bundle类,发现它包含太多信息(以我的拙见),是一个简单的参数集合。
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. 因此,除非Bundle为您提供集合不具备的特殊功能,否则请不要使用它。
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. 根据经验记住,您不能使用Json序列化所有内容 - 有一些限制(例如递归数据类型) - 所以是的,有些情况下您必须从一种类型转换为JSON可序列化类型。
This pattern is also used in other cases, I suggest you read more about data transfer objects 此模式也用于其他情况,我建议您阅读有关数据传输对象的更多信息

Another case that occurred to me was I was holding a reference of Dialog in my Serialized class .我发生的另一个案例是我在我的序列化 class 中持有 Dialog 的引用 While writing that class to preferences was throwing an exception.在将 class 写入首选项时抛出异常。

The fix to avoid that is use of transient keyword to make a particular field non-serializable ( SO link for that particular solution ).避免这种情况的解决方法是使用transient关键字使特定字段不可序列化( 该特定解决方案的 SO 链接)。

Example Code:示例代码:

public class Player implements Serializable { 
    private int id;
    private String name;
    private String slug;

    @Nullable
    transient Dialog prevDialogWeakRef;//non-serialised object

    // set getters()/setters()
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM