【问题标题】:How can I serialize a custom object that has a Context as a private member using Gson?如何使用 Gson 序列化具有 Context 作为私有成员的自定义对象?
【发布时间】:2016-04-28 10:44:17
【问题描述】:

我有一个自定义对象的 ArrayList,我尝试使用 Gson 将其作为 JSON 字符串存储到磁盘。这对于只包含基本类型数据(如字符串)的对象非常有用,但我有一个类有一个私有成员,用于存储 Activity 的上下文。当我尝试使用 Gson 序列化此类时,出现以下异常:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.xxxx.xxxx/com.xxxx.xxxx.MainActivity}: java.lang.SecurityException: Can't make method constructor accessible
                                                                       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
                                                                       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
                                                                       at android.app.ActivityThread.-wrap11(ActivityThread.java)
                                                                       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
                                                                       at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                       at android.os.Looper.loop(Looper.java:148)
                                                                       at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                                       at java.lang.reflect.Method.invoke(Native Method)
                                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
                                                                    Caused by: java.lang.SecurityException: Can't make method constructor accessible
                                                                       at java.lang.reflect.Constructor.setAccessible(Constructor.java:336)
                                                                       at com.google.gson.internal.ConstructorConstructor.newDefaultConstructor(ConstructorConstructor.java:101)
                                                                       at com.google.gson.internal.ConstructorConstructor.get(ConstructorConstructor.java:83)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:96)
                                                                       at com.google.gson.Gson.getAdapter(Gson.java:407)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getFieldAdapter(ReflectiveTypeAdapterFactory.java:136)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.access$100(ReflectiveTypeAdapterFactory.java:49)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(ReflectiveTypeAdapterFactory.java:106)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:105)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:161)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:97)
                                                                       at com.google.gson.Gson.getAdapter(Gson.java:407)
                                                                       at com.google.gson.internal.bind.ArrayTypeAdapter$1.create(ArrayTypeAdapter.java:48)
                                                                       at com.google.gson.Gson.getAdapter(Gson.java:407)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getFieldAdapter(ReflectiveTypeAdapterFactory.java:136)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.access$100(ReflectiveTypeAdapterFactory.java:49)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(ReflectiveTypeAdapterFactory.java:106)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:105)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:161)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:97)
                                                                       at com.google.gson.Gson.getAdapter(Gson.java:407)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getFieldAdapter(ReflectiveTypeAdapterFactory.java:136)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.access$100(ReflectiveTypeAdapterFactory.java:49)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(ReflectiveTypeAdapterFactory.java:106)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:105)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:161)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:97)
                                                                       at com.google.gson.Gson.getAdapter(Gson.java:407)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getFieldAdapter(ReflectiveTypeAdapterFactory.java:136)
                                                                       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.access$100(ReflectiveTypeAdapterFactory.java:49)
                                                                    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(Refle

我猜问题是 Context 中有一个 Gson 无法访问的方法,因为它受到保护或类似的东西。那么有没有办法可以使用 Gson 序列化包含其他复杂对象的对象?

这是一个会导致崩溃的短代码 sn-p:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyObject myObject = new MyObject(this);

        Gson gson = new Gson();
        String myObjectJson = gson.toJson(myObject);
    }

    public class MyObject {

        private Context context;

        public MyObject(Context context) {
            this.context = context;
        }
    }
}

【问题讨论】:

    标签: java android serialization gson


    【解决方案1】:

    Context 不可序列化。您应该将变量声明为 transient 以防止它被序列化。当然你应该在反序列化时手动分配它。

    public class MyObject {
    
        private transient Context context;
    
        // ... other fields here
    
        public MyObject() {
        }
    
        public void setContext(Context context) {
            this.context = context;
        }
    
    }
    

    【讨论】:

    • 甚至更多——如果你确实以某种方式对其进行了序列化,它就不能作为序列化另一端的有效上下文。 OP 几乎可以肯定做错了什么。
    • @GabeSechan 我不确定,但 Gson 似乎存在某种问题(请参阅here)。从构造函数参数中删除 Context 可能会解决这种情况下的问题。
    • @GabeSechan - 我知道序列化在反序列化期间将不再使用的 Context 是没有意义的。问题不在于我需要上下文(我总是可以手动设置它,如建议的那样),而更多的是我已经在一个复杂的应用程序中嵌入了一个复杂的类,我只是想避免大量的重构如果这不是必需的。我只是不确定是否有任何方法可以让 Gson 优雅地处理这种事情。如果我必须在序列化期间排除 Context 并手动设置它,如果这是处理此问题的唯一方法,那很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-17
    • 2018-06-10
    • 2020-07-19
    相关资源
    最近更新 更多