【问题标题】:How to do Custom Serialization using GSON?如何使用 GSON 进行自定义序列化?
【发布时间】:2013-05-09 12:43:10
【问题描述】:

我有一个案例,我想使用 GSON 自定义序列化功能。

class Student{
   public String name;
   public int rollNumber;

   public Student(String name, int rollNumber){
        this.name = name;
        this.rollNumber = rollNumber;
   }

   public int getRollNumber(){
       return this.rollNumber;
   }

   public String getName(){
       return this.name;
   }


}
class School{

    public Student[] students;

    public School(Student[] students){
          this.students = students;
    }


   public Students[] getStudents(){
       return this.students;
   }

}

当我这样做的时候

private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create();

Student[] students = new Student[2];

students[0] = new Student("sam", 1);

students[1] = new Student("tom", 2);

School school = new School(students);

GSON.toJson(school);

我得到这样的输出:

[{"name":"sam","rollNumer":1},{"name":"tom","rollNumer":2}]

但我希望它是:

["student":{"name":"sam","rollNumer":1},"student":{"name":"tom","rollNumer":2}]

如何使用 GSON 自定义序列化来实现这一点?

我试过thisthis。但没有太大帮助。

【问题讨论】:

  • 您想要的输出不是有效的 JSON。如果您坚持生成它,那么您可以使用JSONWriter 来生成它,但老实说,我不知道您为什么要生成语法不正确的数据。
  • @Perception 是否因为重复键“学生”而无效?还是其他原因?
  • 这是无效的,因为您的 JSON 数组中的对象没有正确地用大括号括起来。您可以随时使用jsonlint等在线工具检查数据的有效性

标签: java json gson


【解决方案1】:

这个

["student":{"name":"sam","rollNumer":1},"student":{"name":"tom","rollNumer":2}]

不是有效的 JSON(您可以使用jsonlint 等在线工具自行验证)。详情见JSON specification

对象的定义

对象是一组无序的名称/值对。一个对象以 {(左大括号)开始,以 }(右大括号)结束。每个名称后跟 :(冒号),名称/值对用 ,(逗号)分隔。

数组的定义

数组是值的有序集合。数组以 [(左括号)开头,以 ](右括号)结尾。值用 ,(逗号)分隔。

值的定义

值可以是双引号中的字符串、数字、true 或 false 或 null,也可以是对象或数组。这些结构可以嵌套。

您的输出定义了一个 JSON 数组,但该数组中的对象没有正确地用大括号括起来。正确的表示应该是这样的:

[{"student":{"name":"sam","rollNumer":1}}, {"student":{"name":"tom","rollNumer":2}}]

可以用这个简单的 Gson TypeAdapter 生成:

class StudentAdapter extends TypeAdapter<Student> {

    @Override
    public void write(final JsonWriter writer, final Student student)
            throws IOException {
        if (student == null) {
            writer.nullValue();
            return;
        }

        writer.beginObject();
        writer.name("student");
        writer.beginObject();
        writer.name("name");
        writer.value(student.getName());
        writer.name("rollNumber");
        writer.value(student.getRollNumber());
        writer.endObject();
        writer.endObject();
    }

    @Override
    public Student read(final JsonReader reader) throws IOException {
        if (reader.peek() == JsonToken.NULL) {
            reader.nextNull();
            return null;
        }

        final Student student = new Student();
        reader.beginObject();
        reader.nextName(); // discard the 'student' wrapper property
        reader.beginObject();
        while (reader.hasNext()) {
            final String attrName = reader.nextName();
            if ("name".equals(attrName)) {
                student.setName(reader.nextString());
            } else if ("rollNumber".equals(attrName)) {
                student.setRollNumber(reader.nextInt());
            }
        }
        reader.endObject();
        reader.endObject();

        return student;
    }
}

测试方法:

@Test
public void testWriteSchoolsAsJSONWithGsonAndCustomOutput()
        throws Exception {
    final Gson gson = new GsonBuilder().registerTypeAdapter(Student.class,
            new StudentAdapter()).create();

    Student[] students = new Student[2];
    students[0] = new Student("sam", 1);
    students[1] = new Student("tom", 2);

    School school = new School(students);

    final String outputJson = gson.toJson(school);
    System.out.println(outputJson);

    school = gson.fromJson(outputJson, School.class);
    System.out.println(school);
}

以及“相关”输出:

{"students":[{"student":{"name":"sam","rollNumber":1}},{"student":{"name":"tom","rollNumber":2}}]}

【讨论】:

    【解决方案2】:

    首先你不能得到输出为 ["student":{"name":"sam","rollNumer":1},"student":{"name":"tom","rollNumer" :2}] 因为您试图将对象转换为 json 而不是对象数组。

    我试过你的代码,我得到以下输出

    {"students":[{"name":"sam","rollNumber":1},{"name":"tom","rollNumber":2}]}

    代码如下:

        Student[] students = new Student[2];
    
        students[0] = new Student("sam", 1);
    
        students[1] = new Student("tom", 2);
    
        School school = new School(students);
    
        Gson gson = new GsonBuilder().disableHtmlEscaping().create();
    
        System.out.println(gson.toJson(school));
    

    【讨论】:

    • School 有一组 Student 对象。
    【解决方案3】:

    根据你的课程,你得到了正确的结果。

    您的对象Student 如下所示:

    {"name":"sam", "rollNumer":1}
    

    很简单,JSON 中的对象被{} 包围,并包含属性/值对...

    然后,JSON 中的数组用[] 包围,并包含许多用逗号分隔的对象/值。由于您有一个Student 数组,因此您只有许多对象,例如上面用逗号分隔的对象,并且全部由[] 包围。

    这正是你所拥有的......一切都有意义!

    好的,您希望 JSON 在每个 Student 对象之前包含 "student",但是这个字符串 "student" 是什么?它从何而来?事实上,在你的类中任何地方都没有这样的字符串,那么你希望 Gson(或任何库)如何将它包含在 JSON 中?

    如果您确实需要该字符串,则需要以某种方式将其包含在您的类中,而我想出的最简单的方法是使用 Map 而不是数组,如下所示:

    public Map<String, Student> students;
    

    然后像这样将学生添加到地图中:

    Student student = new Student("sam", 1);
    students.put("student", student);
    //add other students...
    

    请注意,现在您确实有字符串"student",与学生相关联作为地图中的键...

    现在您或多或少会得到您想要的结果,但不完全是!因为整个事物将被{} 包围而不是[],因为Map 是一个对象,而不是一个数组...

    {"student":{"name":"sam","rollNumer":1}},{"student":{"name":"tom","rollNumer":2}}
    

    恐怕无法得到完全符合您要求的响应(据我所知)......

    【讨论】:

      猜你喜欢
      • 2013-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-23
      相关资源
      最近更新 更多