java - 无法使用 Gson 将对象(使用 Room DB)序列化为 json 字符串
问题描述
我有一个类 Item(见下文),其中我使用了一些 Room db 注释。它还有一个名为 ItemInfo 的嵌套类。这两个类都有一个空的构造函数。
问题是当我尝试序列化 Item 类的对象时,应用程序崩溃并出现以下错误:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.android.carrymates, PID: 18526
java.lang.SecurityException: Can not make a java.lang.reflect.Method constructor accessible
at java.lang.reflect.AccessibleObject.setAccessible0(AccessibleObject.java:133)
at java.lang.reflect.AccessibleObject.setAccessible(AccessibleObject.java:119)
at com.google.gson.internal.reflect.PreJava9ReflectionAccessor.makeAccessible(PreJava9ReflectionAccessor.java:31)
at com.google.gson.internal.ConstructorConstructor.newDefaultConstructor(ConstructorConstructor.java:103)
at com.google.gson.internal.ConstructorConstructor.get(ConstructorConstructor.java:85)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:101)
at com.google.gson.Gson.getAdapter(Gson.java:458)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
at com.google.gson.Gson.getAdapter(Gson.java:458)
at com.google.gson.internal.bind.ArrayTypeAdapter$1.create(ArrayTypeAdapter.java:48)
at com.google.gson.Gson.getAdapter(Gson.java:458)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
at com.google.gson.Gson.getAdapter(Gson.java:458)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
at com.google.gson.Gson.getAdapter(Gson.java:458)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
at com.google.gson.Gson.getAdapter(Gson.java:458)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
at com.google.gson.Gson.getAdapter(Gson.java:458)
at com.google.gson.Gson.toJson(Gson.java:696)
at com.google.gson.Gson.toJson(Gson.java:683)
at com.google.gson.Gson.toJson(Gson.java:638)
at com.google.gson.Gson.toJson(Gson.java:618)
... more log (irrelevant to question asked)
项目.java
@Entity(tableName = "items", indices = {@Index(value = {"id"}, unique = true), @Index(value = {"owner", "type"})})
public class Item {
@PrimaryKey
@NonNull
String id="";
//...rest fields are int, boolean and String only
@Embedded
ItemInfo itemInfo; // see ItemInfo
public Item() {
}
// ...getters and setters
@IgnoreExtraProperties
public static class ItemInfo {
//...fields are int, boolean and String only
public ItemInfo() {
}
//...getters and setters
}
}
我的猜测是 Room DB 注释正在添加至少一个java.lang.reflect.Method
Gson 无法序列化的类型的对象。
下面是我用来将 Item 对象序列化为 json 字符串的代码,其中是 Item 类的对象,其字段类型为和item
的非空值。String
ItemInfo
Gson gson = new Gson();
String result = gson.toJson(item); // crash begins from here
我该如何解决这个问题?我希望至少有一个解决方案。
解决方案
免责声明:
我不知道RoomDB对@Entity
类做了什么(尽管看起来 RoomDB 使用子类而不是你编写的类)。
我也在JVM上运行测试
但我可以建议你使用@Expose:
public class GsonTest {
private static class SampleModel {
@Expose
private int i;
private Method method;
@Expose
private Nested nested = new Nested();
}
private static class Nested {
@Expose
private String a = "my string";
}
@Test
public void failsWithMethodField() throws Exception {
assertThrows(Exception.class, () -> {
SampleModel sampleModel = new SampleModel();
sampleModel.i = 10;
sampleModel.method = Object.class.getDeclaredMethod("equals", Object.class);
Gson gson = new Gson();
gson.toJson(sampleModel);
});
}
@Test
public void withExposedDoesNotFail() {
assertDoesNotThrow(() -> {
SampleModel sampleModel = new SampleModel();
sampleModel.method = Object.class.getDeclaredMethod("equals", Object.class);
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
String json = gson.toJson(sampleModel);
System.out.println(json); // {"i":0,"nested":{"a":"my string"}}
});
}
}
必不可少的部分是Gson
使用excludeFieldsWithoutExposeAnnotation
选项进行配置:
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
@Expose
然后用注解标记所有在序列化和反序列化时应该使用的字段。
推荐阅读
- python - 从 pandas DataFrame 的集合中提取所有元素
- typescript - 在 Typescript 中,有没有办法检查对象或函数是否在“import * as myImport”语句中导入?
- java - 如何在 Java 中隐藏输入并将其转换为星号
- typescript - 如何将 NextJS 构建到 es5?
- r - 在ggplot中的多面板图上聚集了x轴刻度
- python-3.x - 如何在 Django 的应用程序之间获取外键值?
- javascript - 在一页上加载多个 vue 实例后,其中一个实例不起作用
- r - 多变量分布错误:sigma' 不是正定的
- excel - 如何在 vlookup 不起作用的 excel 范围内拉出最近的字符串?
- flutter - Flutter 在播放前缓存视频在 Futurebuild 上为空