首页 > 解决方案 > 如何使用 auto-value-gson 映射未知的 json 字段

问题描述

我正在与他们的api对话的 android 中制作一个简单的 github gist view 应用程序。

但我不确定如何使用 AutoValue 和 GSON 来映射这个 json 响应。请注意,我已经删除了很多键,因为我目前不需要它,实际响应看起来像这样

示例响应

[
  {
    "id": "3937809cf12adae05595c43c5ef4ce56",
    "files": {
      "main.css": {
        "filename": "main.css",
        "type": "text/css",
        "language": "CSS",
        "raw_url": "https://gist.githubusercontent.com/*/3937809cf12adae05595c43c5ef4ce56/raw/f46b97a4cf561fa18e50e14bed734eea78bc58d9/main.css",
        "size": 102
      },
      "readme.txt": {
        "filename": "readme.txt",
        "type": "text/plain",
        "language": "Text",
        "raw_url": "https://gist.githubusercontent.com/*/3937809cf12adae05595c43c5ef4ce56/raw/aa7bf7046baaf58b23b4fa4c3b19a575d5eae36e/readme.txt",
        "size": 192
      }
    }
  }
]

问题 我读过我可以在StringFile对象之间映射以使其工作。但它不起作用,因为fileskey 是或可以是对象的对象。

那么如何使用 auto-value-gson 映射这些未知对象的对象呢?甚至可能吗?

代码

GistResponse.java

@AutoValue
public abstract class GistResponse {

    @SerializedName("id")
    public abstract String getId();

    @SerializedName("files")
    public abstract FileName getFileNameList();

    public static Builder builder() {
        return new AutoValue_GistResponse.Builder();
    }

    @AutoValue.Builder
    public abstract static class Builder {
        public abstract Builder setId(String value);
        public abstract Builder setFileNameList(FileName value);

        public abstract GistResponse build();
    }

    public static TypeAdapter<GistResponse> typeAdapter(Gson gson) {
        return new AutoValue_GistResponse.GsonTypeAdapter(gson);
    }

}

文件名.java

@AutoValue
public abstract class FileName {

    public abstract Map<String, File> getFilesList();

    public static Builder builder() {
        return new AutoValue_FileName.Builder();
    }

    @AutoValue.Builder
    public abstract static class Builder {
        public abstract Builder setFilesList(Map<String, File> value);
        public abstract FileName build();
    }

    public static TypeAdapter<FileName> typeAdapter(Gson gson) {
        return new AutoValue_FileName.GsonTypeAdapter(gson);
    }
}

文件.java

@AutoValue
public abstract class File {

    @SerializedName("filename")
    public abstract String getFileName();

    @SerializedName("type")
    public abstract String getType();

    @SerializedName("language")
    public abstract String getLanguage();

    @SerializedName("raw_url")
    public abstract String getRawUrl();

    @SerializedName("size")
    public abstract Integer getSize();

    public static Builder builder() { return new AutoValue_File.Builder(); }

    @AutoValue.Builder
    public abstract static class Builder {
        public abstract Builder setFileName(String value);
        public abstract Builder setType(String value);
        public abstract Builder setLanguage(String value);
        public abstract Builder setRawUrl(String value);
        public abstract Builder setSize(Integer value);

        public abstract File build();
    }

    public static TypeAdapter<File> typeAdapter(Gson gson) {
        return new AutoValue_File.GsonTypeAdapter(gson);
    }
}

相关主题和信息:

标签: javaandroidgsonretrofitauto-value

解决方案


从那以后,我找到了一个解决方案,其中包括编写一个TypeAdapter实际上非常简单的自定义。

这是代码:

public class FileTypeAdapter extends TypeAdapter {

    @Override
    public void write(JsonWriter out, Object value) throws IOException {}

    @Override
    public List<File> read(JsonReader jsonReader) throws IOException {

        ArrayList<File> fileList = new ArrayList<>();

        if (jsonReader.peek() == JsonToken.NULL) {
            jsonReader.nextNull();
            return fileList;
        }

        jsonReader.beginObject();
        while (jsonReader.hasNext()) {

            jsonReader.nextName();

            if (jsonReader.peek() == JsonToken.NULL) {
                jsonReader.nextNull();
                continue;
            }

            File.Builder file = File.builder();

            jsonReader.beginObject();
            while (jsonReader.hasNext()) {

                String nextName = jsonReader.nextName();

                switch (nextName) {
                    case "filename": {
                        String nextString = jsonReader.nextString();
                        file.setFileName(nextString);
                        break;
                    }
                    case "type": {
                        String nextString = jsonReader.nextString();
                        file.setType(nextString);
                        break;
                    }
                    case "language": {

                        if (jsonReader.peek() == JsonToken.NULL) {
                            jsonReader.nextNull();
                        } else {
                            String nextString = jsonReader.nextString();
                            file.setLanguage(nextString);
                        }
                        break;
                    }
                    case "raw_url": {
                        String nextString = jsonReader.nextString();
                        file.setRawUrl(nextString);
                        break;
                    }
                    case "size": {
                        Integer nextInt = jsonReader.nextInt();
                        file.setSize(nextInt);
                        break;
                    }
                    default: {
                        jsonReader.skipValue();
                    }
                }
            }
            fileList.add(file.build());
            jsonReader.endObject();
        }
        jsonReader.endObject();
        return fileList;
    }
}

然后只需用@GsonTypeAdapterinside注释 files 字段GistResponse.java

@AutoValue
public abstract class GistResponse {

    @SerializedName("id")
    public abstract String getId();

    @GsonTypeAdapter(FileTypeAdapter.class)
    @SerializedName("files")
    public abstract FileName getFileNameList();

    public static Builder builder() {
        return new AutoValue_GistResponse.Builder();
    }

    @AutoValue.Builder
    public abstract static class Builder {
        public abstract Builder setId(String value);
        public abstract Builder setFileNameList(FileName value);

        public abstract GistResponse build();
    }

    public static TypeAdapter<GistResponse> typeAdapter(Gson gson) {
        return new AutoValue_GistResponse.GsonTypeAdapter(gson);
    }

}

现在可以解析它了。


推荐阅读