Gson.toJson for java.io.文件在迁移到API 31 Android 12后给出“{}”

lxkprmvk  于 2022-12-16  发布在  Android
关注(0)|答案(1)|浏览(93)

更新targetSdk到31后,gson.ToJson在android 12设备(vivo v2036)上开始给出List<File>的空结果。尝试传递TypeToken也仍然保持不变。有趣的是,它在较低的android和targetSdk 30上运行良好。

public void save(Context context, List<File> files) {
    Gson gson = new Gson();
    String json = gson.toJson(files);
    //getting json value as "[{}]"
}
mwngjboj

mwngjboj1#

Gson没有java.io.File的内置适配器,因此它福尔斯使用反射。对于第三方类,应该避免使用反射,因为它访问它们的内部字段,这会使您依赖于它们的内部实现。内部实现可能会在任何时候更改,因为它不是公共API的一部分,因此可能会破坏JSON序列化逻辑。
正如@CommonsWare提到的,你可以将列表的类型改为List<String>,这样只使用Gson有内置适配器的类型,或者你也可以为File注册一个定制的TypeAdapter来解决这个问题:

class FileTypeAdapter extends TypeAdapter<File> {
    @Override
    public void write(JsonWriter out, File file) throws IOException {
        if (value == null) {
            out.nullValue();
        } else {
            out.value(file.getPath());
        }
    }

    @Override
    public File read(JsonReader in) throws IOException {
        if (in.peek() == JsonToken.NULL) {
            in.nextNull();
            return null;
        } else {
            return new File(in.nextString());
        }
    }
}

(巧合的是,这个定制的TypeAdapter也会生成更紧凑的JSON,因为它将File序列化为JSON字符串值,而基于反射的适配器会将其序列化为具有JSON字符串属性的JSON对象。)
然后,您可以按如下方式注册适配器:

Gson gson = new GsonBuilder()
    .registerTypeAdapter(File.class, new FileTypeAdapter())
    .create();

如果这不能解决您的问题,您也可以尝试使用GsonBuilder.registerTypeHierarchyAdapter注册适配器。可能Android正在创建自定义File子类的示例。
要检测您意外依赖Android类的基于反射的序列化的任何情况,您可以使用GsonBuilder.addReflectionAccessFilter​(ReflectionAccessFilter.BLOCK_ALL_ANDROID)(需要Gson 2.9.1或更高版本)。

相关问题