【问题标题】:Custom Json serialization with Gson使用 Gson 自定义 Json 序列化
【发布时间】:2018-07-30 09:12:24
【问题描述】:

我正在使用一个类层次结构,其中一个类定义了一组实例

public class Base {
    String id;
    String name;
    String type;
} 

public class Group<T extends Base>  extends Base {
    Collection<T> elements;

}

还有许多其他类型派生自基类并且可以添加到组中。每种类型都有自己的属性

Gson 默认序列化适用于非组对象,但对于组对象,我需要仅使用基类属性对集合元素进行序列化,并排除所有其他属性。

问题:

  1. 完成这项工作的最佳方法是什么?
  2. 如果 Group 也是一个基类,我希望对其所有子类自动完成自定义序列化怎么办?

编辑:

@保罗。我认为你的建议在我的情况下不起作用。 我过度简化了模型。

这里是对模型的更详细的描述。

public interface Node {
    BaseObject getAsBaseObject();
}

public class Base {
    String id;
    String name;
    String type;
}

public class BaseObject extends Base implements Node {
    String description;

    @Override
    public BaseObject getAsBaseObject() {
        return this;
    }
}

public class Group<T extends Node>  extends BaseObject {
    Collection<BaseObject> elements;

    void addElement(T element) {
        elements.add(element.getAsBaseObject());
    }
}

Node 接口用作复合节点的基础。考虑 Foo 和 Foo 的组...

public interface FooBase extends Node {

}

public class Foo extends BaseObject implements FooBase {
    String prop1;
}

public class FooGroup extends Group<FooBase> implements FooBase{

}

假设我有一个 FooGroup,其中包含一些 Foo 和 Foo 组。 我需要序列化对象看起来像这样:

{
  "id": "",
  "type": "",
  "name": "",
  "description": " ",
  "objects": [
    {
      "type": "",
      "name": "",
      "id": ""
    },
    {
      "type": "",
      "name": "",
      "id": ""
    },
    {
      "type": "",
      "name": "",
      "id": ""
    },
    {
      "type": "",
      "name": "",
      "id": ""
    }
  ]
}

我认为@Expose 在这里不起作用,因为描述字段也会在对象集合中公开

我可以通过注册一个自定义的 JsonSerializer 来做到这一点 但这是正确/最简单的方法吗?

如果这是要走的路,有没有办法只注册一个序列化器来处理所有 Group 类派生?

【问题讨论】:

    标签: java json serialization gson


    【解决方案1】:

    Gson 有一个专门为此制作的 @Expose 注释。首先,将基类的字段标记为已公开:

    public class Base {
        @Expose
        String id;
        @Expose
        String name;
        @Expose
        String type;
    } 
    

    然后,在创建您的 Gson 对象时,使其忽略您尚未公开的字段:

    Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
    

    别忘了公开elements 数组:

    public class Group<T extends Base> extends Base {
        @Expose
        Collection<T> elements;
    }
    

    序列化现在将按预期工作。为了测试这一点,让我们创建一个扩展 Base 的小助手类:

    public class BaseExtension extends Base {
        private String notExposed;
    
        public BaseExtension(String notExposed) {
            this.notExposed = notExposed;
        }
    }
    

    现在,让我们创建一个BaseExtensions 的Group(为了清楚起见,使用Guava):

    BaseExtension b1 = new BaseExtension("BaseExt1");
    BaseExtension b2 = new BaseExtension("BaseExt2");
    BaseExtension b3 = new BaseExtension("BaseExt3");
    
    Group group = new Group<>(Lists.newArrayList(b1, b2, b3));
    

    如果我们对此进行序列化,我们会得到三个没有notExposed 属性的元素——事实上,这些元素将是完全空的,因为idnametype 还没有值:

    System.out.println(gson.toJson(group));
    // Produces { "elements" : [ {}, {}, {} ] }
    

    将值添加到您的 Base 类以查看更有用的输出。

    【讨论】:

    • 感谢您的回答,但我认为此解决方案行不通。请查看我编辑的问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-30
    • 2020-09-09
    • 2017-04-23
    相关资源
    最近更新 更多