【问题标题】:Read JSON file via Gson when using a list of objects使用对象列表时通过 Gson 读取 JSON 文件
【发布时间】:2017-05-08 09:12:16
【问题描述】:

我尽量解释我的情况。我想用 Gson 读取一个包含对象列表的 JSON 文件。这个对象是基类,因为我有几个扩展它的对象。

{ 
    "name":"Test", 
    "url":"http://test.test", 
    "script":[ 
        { "actionId":1, "actionType":"click", "id":"testId", "redirect" : "http://google.de" },
        { "actionId":2, "actionType":"write", "id":"testId2", "content":"testContent" } 
    ] 
}

基类称为ScriptElement,它也包含每个子对象所需的一些值。 ScriptInputScriptClickable 是孩子。 如果我将列表转换为 JSON,我会得到一个生成良好的 JSON 文件。但是当我读取JSON文件并将其转换回对象时,它只包含ScriptElement对象,并且缺少ScriptInputScriptClickable的附加信息。

【问题讨论】:

  • 你至少可以给我们看 json 文件!
  • { "name":"Test", "url":"http://test.test", "script":[ { "actionId":1, "actionType":"click", "id":"testId", "redirect" : "http://google.de" }, { "actionId":2, "actionType":"write", "id":"testId2", "content":"testContent" } ] } 我试图将它添加到正文中,但我永久收到代码无效的消息。不知道为什么。
  • 你可以编辑你的帖子而不是你的评论吗?
  • 就像我说的,我不能。系统提示我的代码有错误,无法添加。

标签: java json gson


【解决方案1】:

这是一个经典案例:发生这种情况是因为 Gson 不知道 ScriptElementactionType 值如何相互关联。您只需告诉 Gson 如何映射这些。

为简单起见,我假设您的映射如下所示:

final class Response {
    final String name = null;
    final URL url = null;
    final List<ScriptElement> script = null;
}
abstract class ScriptElement {
    final int actionId = Integer.valueOf(0);
    final String id = null;
}
final class ScriptClickable extends ScriptElement {
    final URL redirect = null;
}
final class ScriptInput extends ScriptElement {
    final String content = null;
}

现在,只需注册一个JsonDeserializer 即可根据actionType 属性值生成ScriptElement

private static final Gson gson = new GsonBuilder()
        .registerTypeAdapter(ScriptElement.class, (JsonDeserializer<ScriptElement>) (jsonElement, type, context) -> {
            final String actionType = jsonElement.getAsJsonObject().getAsJsonPrimitive("actionType").getAsString();
            switch ( actionType ) {
            case "click":
                return context.deserialize(jsonElement, ScriptClickable.class);
            case "write":
                return context.deserialize(jsonElement, ScriptInput.class);
            default:
                throw new JsonParseException("Unrecognized action type: " + actionType);
            }
        })
        .create();

如您所见,您唯一需要做的就是:

  • 从 JSON 树中获取操作类型。
  • 使用适当的类引用将操作类型值分派到下游反序列化上下文(让 Gson 做它最擅长的事情)。

完成后,您可以对其进行测试:

try ( final JsonReader jsonReader = getPackageResourceJsonReader(Q43843846.class, "test.json") ) {
    final Response response = gson.fromJson(jsonReader, Response.class);
    for ( final ScriptElement element : response.script ) {
        if ( element instanceof ScriptClickable ) {
            final ScriptClickable clickable = (ScriptClickable) element;
            System.out.println(clickable.redirect);
        } else if ( element instanceof ScriptInput ) {
            final ScriptInput input = (ScriptInput) element;
            System.out.println(input.content);
        } else {
            throw new AssertionError(element);
        }
    }
}

输出:

http://google.de
测试内容

查看更多关于多态对象反序列化的信息:

【讨论】:

  • 我正在考虑使用类似的东西,但我虽然会有一个更“集成”到 gson 中的解决方案。但非常感谢您的帮助。 :) 我会测试它。
  • @Marco 不,核心 Gson 中没有类似的东西。考虑 Gson 是一种构造函数,它只集成了琐碎的案例。
【解决方案2】:

好的,基于json结构做一个具有这些属性的类

public class User{
private String name;
private String url;
private ArrayList<Script>script;
}
public class Script{
private int actionId;
private String actionType;
private String id;
private String redirect;
}

现在当你想用 gson 解析它时 您应该从用户类创建一个引用 将 json 从文件中拉到你将创建的 myJsonString 变量

User user=new Gson().fromJson(myJsonString,User.class);

【讨论】:

  • 您好,您的用户类别是正确的,看起来和我的很接近。但是 Script 只是一个 BaseClass,此列表中的所有元素都是从 Script 扩展而来的子类。像这样public class ScriptClickable extends ScriptElement { @SerializedName("redirect") @Expose private String redirect; @Override public boolean execute() { //execute the code which is important for a scriptClickable System.out.println("Doing a button click"); return true; } }
  • 我使用子类的原因是“执行”方法。根据脚本类,它会做一些不同的事情。
  • 什么意思!我根据您的脚本结构制作了脚本类,否则将无法正常工作
  • 执行方法是什么?
  • 你的元素应该和json结构的名字完全一样,否则不起作用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-02
相关资源
最近更新 更多