`

libgdx Reading & writing JSON

 
阅读更多

Overview

libgdx can perform automatic object to JSON serialization and JSON to object deserialization. Four small classes make up the API:

  • JsonWriter: A builder style API for emitting JSON.
  • JsonReader: Parses JSON and builds a DOM of JsonValue objects.
  • JsonValue: Describes a JSON object, array, string, float, long, boolean, or null.
  • Json: Reads and writes arbitrary object graphs using JsonReader and JsonWriter.

To use these classes outside of libgdx, see the JsonBeans project.

Used to the default Android json.org library? Get started with this great tutorial.

Writing Object Graphs

The Json class uses reflection to automatically serialize objects to JSON. For example, here are two classes (getters/setters and constructors omitted):

public class Person {
   private String name;
   private int age;
   private ArrayList numbers;
}

public class PhoneNumber {
   private String name;
   private String number;
}

Example object graph using these classes:

Person person = new Person();
person.setName("Nate");
person.setAge(31);
ArrayList numbers = new ArrayList();
numbers.add(new PhoneNumber("Home", "206-555-1234"));
numbers.add(new PhoneNumber("Work", "425-555-4321"));
person.setNumbers(numbers);

The code to serialize this object graph:

Json json = new Json();
System.out.println(json.toJson(person));

{numbers:[{class:com.example.PhoneNumber,number:"206-555-1234",name:Home},{class:com.example.PhoneNumber,number:"425-555-4321",name:Work}],name:Nate,age:31}

That is compact, but hardly legible. The prettyPrint method can be used:

Json json = new Json();
System.out.println(json.prettyPrint(person));

{
numbers: [
    {
        class: com.example.PhoneNumber,
        number: "206-555-1234",
        name: Home
    },
    {
        class: com.example.PhoneNumber,
        number: "425-555-4321",
        name: Work
    }
],
name: Nate,
age: 31
}

Note that the class for the PhoneNumber objects in the ArrayList numbers field appears in the JSON. This is required to recreate the object graph from the JSON because ArrayListcan hold any type of object. Class names are only output when they are required for deserialization. If the field was ArrayList<PhoneNumber> numbers then class names would only appear when an item in the list extends PhoneNumber. If you know the concrete type or aren't using generics, you can avoid class names being written by telling the Json class the types:

Json json = new Json();
json.setElementType(Person.class, "numbers", PhoneNumber.class);
System.out.println(json.prettyPrint(person));

{
numbers: [
    {
        number: "206-555-1234",
        name: Home
    },
    {
        number: "425-555-4321",
        name: Work
    }
],
name: Nate,
age: 31
}

When writing the class cannot be avoided, an alias can be given:

Json json = new Json();
json.addClassTag("phoneNumber", PhoneNumber.class);
System.out.println(json.prettyPrint(person));

{
numbers: [
    {
        class: phoneNumber,
        number: "206-555-1234",
        name: Home
    },
    {
        class: phoneNumber,
        number: "425-555-4321",
        name: Work
    }
],
name: Nate,
age: 31
}

The Json class can write and read both JSON and a couple JSON-like formats. It supports "JavaScript", where the object property names are only quoted when needed. It also supports a "minimal" format (the default), where both object property names and values are only quoted when needed.

Json json = new Json();
json.setOutputType(OutputType.json);
json.setElementType(Person.class, "numbers", PhoneNumber.class);
System.out.println(json.prettyPrint(person));

{
"numbers": [
    {
        "number": "206-555-1234",
        "name": "Home"
    },
    {
        "number": "425-555-4321",
        "name": "Work"
    }
],
"name": "Nate",
"age": 31
}

Reading Object Graphs

The Json class uses reflection to automatically deserialize objects from JSON. Here is how to deserialize the JSON from the previous examples:

Json json = new Json();
String text = json.toJson(person);
Person person2 = json.fromJson(Person.class, text);

The type passed to fromJson is the type of the root of the object graph. From this, the Jsonclass determines the types of all the fields and all other objects encountered, recursively. The "knownType" and "elementType" of the root can be passed to toJson. This is useful if the type of the root object is not known:

Json json = new Json();
json.setOutputType(OutputType.minimal);
String text = json.toJson(person, Object.class);
System.out.println(json.prettyPrint(text));
Object person2 = json.fromJson(Object.class, text);

{
class: com.example.Person,
numbers: [
    {
        class: com.example.PhoneNumber,
        number: "206-555-1234",
        name: Home
    },
    {
        class: com.example.PhoneNumber,
        number: "425-555-4321",
        name: Work
    }
],
name: Nate,
age: 31
}

To read the JSON as a DOM of maps, arrays, and values, the JsonReader class can be used:

Json json = new Json();
String text = json.toJson(person, Object.class);
JsonValue root = new JsonReader().parse(text);

The JsonValue describes a JSON object, array, string, float, long, boolean, or null.

Customizing Serialization

Usually automatic serialization is desired and there is no need to customize how specific classes are serialized. When needed, serialization can be customized by either having the class to be serialized implement the Json.Serializable interface, or by registering aJson.Serializer with the Json instance.

This example uses Json.Serializable to write a phone number as an object with a single field:

static public class PhoneNumber implements Json.Serializable {
   private String name;
   private String number;

   public void write (Json json) {
      json.writeValue(name, number);
   }

   public void read (Json json, JsonValue jsonMap) {
      name = jsonMap.child().name();
      number = jsonMap.child().asString();
   }
}

Json json = new Json();
json.setElementType(Person.class, "numbers", PhoneNumber.class);
String text = json.prettyPrint(person);
System.out.println(text);
Person person2 = json.fromJson(Person.class, text);

{
numbers: [
    {
        Home: "206-555-1234"
    },
    {
        Work: "425-555-4321"
    }
],
name: Nate,
age: 31
}

The class implementing Json.Serializable must have a zero argument constructor because object construction is done for you. In the write method, the surrounding JSON object has already been written. The read method always receives a JsonValue that represents that JSON object.

Json.Serializer provides more control over what is output, requiring writeObjectStartand writeObjectEnd to be called if you require a JSON object like Json.Serializable. Alternatively, a JSON array or a simple value (string, int, boolean) could be output instead of an object. Json.Serializer also allows the object creation to be customized:

Json json = new Json();
json.setSerializer(PhoneNumber.class, new Json.Serializer<PhoneNumber>() {
   public void write (Json json, PhoneNumber number, Class knownType) {
      json.writeObjectStart();
      json.writeValue(number.name, number.number);
      json.writeObjectEnd();
   }

   public PhoneNumber read (Json json, JsonValue jsonData, Class type) {
      PhoneNumber number = new PhoneNumber();
      number.setName(jsonData.child().name());
      number.setNumber(jsonData.child().asString());
      return number;
   }
});
json.setElementType(Person.class, "numbers", PhoneNumber.class);
String text = json.prettyPrint(person);
System.out.println(text);
Person person2 = json.fromJson(Person.class, text);

Serialization Methods

Json has many methods to read and write data to the JSON. Write methods without a name string are used to write a value that is not a JSON object field (eg, a string or an object in a JSON array). Write methods that take a name string are used to write a field name and value for a JSON object.

writeObjectStart is used to start writing a JSON object, then values can be written using the write methods that take a name string. When the object is finished, writeObjectEndmust be called:

json.writeObjectStart();
json.writeValue("name", "value");
json.writeObjectEnd();

The writeObjectStart methods that take an actualType and a knownType will write a class field to the JSON if the types differ. This enables the actual type to be known during deserialization. For example, the known type may be java.util.Map but the actual type is java.util.LinkedHashMap (which extends HashMap), so deserialization needs to know the actual type to create.

Writing arrays works in a similar manner, except the values should be written using the write methods that do not take a name string:

json.writeArrayStart();
json.writeValue("value1");
json.writeValue("value2");
json.writeArrayEnd();

The Json class can automatically write Java object fields and values. writeFields writes all fields and values for the specified Java object to the current JSON object:

json.writeObjectStart();
json.writeFields(someObject);
json.writeObjectEnd();

The writeField method writes the value for a single Java object field:

json.writeObjectStart();
json.writeField(someObject, "javaFieldName", "jsonFieldName");
json.writeObjectEnd();

Many of the write methods take an "element type" parameter. This is used to specify the known type of objects in a collection. For example, for a list:

ArrayList list = new ArrayList();
list.add(someObject1);
list.add(someObject2);
list.add(someObject3);
list.add(someOtherObject);
...
json.writeObjectStart();
json.writeValue("items", list);
json.writeObjectEnd();

{
    items: [
        { class: com.example.SomeObject, value: 1 },
        { class: com.example.SomeObject, value: 2 },
        { class: com.example.SomeObject, value: 3 },
        { class: com.example.SomeOtherObject, value: four }
    ]
}

Here the known type of objects in the list is Object, so each object in the JSON for "items" has a class field that specifies Integer or String. By specifying the element type, Integer is used as the known type so only the last entry in the JSON for "items" has a class field:

json.writeObjectStart();
json.writeValue("items", list, ArrayList.class, Integer.class);
json.writeObjectEnd();

{
    items: [
        { value: 1 },
        { value: 2 },
        { value: 3 },
        { class: com.example.SomeOtherObject, value: four }
    ]
}

For maps, the element type is used for the values. The keys for maps are always strings, a limitation of how object fields are described using JSON.

Note that the Json class uses generics on Java field declarations to determine the element type where possible.

Event Based Parsing

 

The JsonReader class reads JSON and has protected methods that are called as JSON objects, arrays, strings, floats, longs, and booleans are encountered. By default, these methods build a DOM out of JsonValue objects. These methods can be overridden to do your own event based JSON handling.

分享到:
评论

相关推荐

    libgdx FullScreen&vsync

    LibGDX是一个强大的开源游戏开发框架,用于创建跨平台的游戏。在这个主题中,我们主要探讨的是LibGDX中的全屏模式(FullScreen)和垂直同步(VSync)功能,这两个特性对于游戏性能和用户体验至关重要。 全屏模式...

    libgdx Continuous & non continuous rendering

    LibGDX 提供了丰富的图形绘制功能,其中“Continuous & non continuous rendering”是两个重要的渲染模式,它们对于优化游戏性能和响应性至关重要。 **连续渲染(Continuous Rendering)** 连续渲染是一种实时更新...

    libgdx JSON

    LibGDX JSON是一个在LibGDX游戏开发框架中用于处理JSON(JavaScript Object Notation)数据的库。JSON是一种轻量级的数据交换格式,被广泛应用于网络通信和数据存储,因为它易于阅读和编写,同时也容易让机器解析和...

    libgdx JSON(2)

    在"libgdx JSON(2)"这个主题中,我们将会深入探讨LibGDX框架中JSON库的高级用法,包括但不限于以下内容: 1. **JSON序列化与反序列化**: - 序列化是将Java对象转换为JSON字符串的过程,以便存储或传输。LibGDX...

    libgdx项目,json 还原为 csd

    标题“libgdx项目,json 还原为 csd”表明这个项目涉及将使用JSON格式存储的数据转换回CSD(可能指的是Custom Shape Data或某种特定的游戏资源格式)以便在LibGDX项目中使用。CSD格式通常是由游戏或特定工具自定义的...

    LibGDX Game Development Essentials

    本书“LibGDX Game Development Essentials”致力于为读者提供LibGDX游戏开发框架的核心知识,引导读者了解并掌握如何使用LibGDX来制作游戏。LibGDX是一个开放源码的Java游戏开发框架,它为游戏开发者提供了跨平台...

    libGDX 1.10.0 开发包

    LibGDX 是一个开源的游戏开发框架,主要用于构建跨平台的2D和3D游戏。它为开发者提供了丰富的功能,使得游戏开发变得更加高效和便捷。在提供的"libGDX 1.10.0 开发包"中,包含了以下几个关键组件: 1. **gdx-1.10.0...

    libgdx游戏

    **LibGDX游戏开发详解** LibGDX是一个强大的开源Java框架,专为跨平台2D和3D游戏开发设计。这个框架允许开发者使用单一代码库创建游戏,可以在Android、iOS、Windows、Mac OS X和Linux等多个平台上运行。"libgdx...

    libgdx教程

    6. **文件I/O**:LibGDX提供了方便的文件读写功能,包括读取JSON、XML等数据格式,便于资源管理和数据持久化。 7. **Scene2D**:一套高级的2D场景管理工具,包含UI组件、动画系统和粒子效果,让开发者可以快速构建...

    Libgdx开发丛书之 Learning LibGDX Game Development, 2nd Edition

    《Libgdx开发丛书之 Learning LibGDX Game Development, 2nd Edition》是一本专为游戏开发者准备的图书,旨在帮助读者深入理解并熟练运用LibGDX这一强大的跨平台游戏开发框架。LibGDX是一个开源的Java库,支持在...

    libgdx Skin类的使用

    LibGDX是一个强大的开源游戏开发框架,用于创建跨平台的游戏。在LibGDX中,`Skin`类是一个非常重要的工具,它主要用于管理UI组件的外观和感觉,包括纹理、字体和样式。`Skin`类使得游戏开发者能够轻松地定义和应用...

    使用LibGDX开发一个完整游戏 教程全集

    LibGDX提供了Preferences类来存储简单的键值对数据,而更多的复杂数据可以使用JSON或XML序列化。 在这一系列的教程中,你将逐步学习如何使用上述技术和工具,从创建基本的Game类开始,搭建游戏结构,到设计游戏逻辑...

    LibGDX音频案例素材.zip

    LibGDX是一个强大的开源游戏开发框架,主要用于创建跨平台的游戏。这个"LibGDX音频案例素材.zip"压缩包显然是为了教学或实践LibGDX中音频处理功能而准备的。让我们详细了解一下LibGDX的音频模块及其在游戏开发中的...

    libgdx TexturePackerTest

    - **对应的精灵表(SpriteSheet JSON或XML)**:描述每个图像在纹理atlas中的位置和大小,便于在代码中使用。 - **测试代码**:展示如何在LibGDX项目中加载和使用由Texture Packer生成的纹理atlas。 在实际应用中,...

    libgdx1.6.1.rar

    LibGDX是一个强大的开源游戏开发框架,用于创建跨平台的游戏。这个“libgdx1.6.1.rar”文件包含了LibGDX库的1.6.1版本,它是一个流行的Java库,支持开发者构建游戏,从Android到iOS,再到桌面平台如Windows、Linux和...

    LibGDX Lua Tutorial工程

    LibGDX是一个强大的开源游戏开发框架,它支持跨平台的游戏开发,包括Android、iOS、桌面系统(Windows、MacOS、Linux)以及Web浏览器。在这个"LibGDX Lua Tutorial工程"中,开发者可以学习如何利用LibGDX框架结合Lua...

    libgdx-1.6.1.zip

    《深入解析libgdx-1.6.1》 libgdx是一款强大的开源游戏开发框架,专注于跨平台的游戏开发,支持Android、iOS、HTML5、桌面应用等多种平台。本篇文章将详细探讨libgdx 1.6.1版本中的关键组件和特性,帮助开发者更好...

    Libgdx开源游戏 【蚂蚁回家】libgdx实现

    《蚂蚁回家》是一款基于Libgdx框架开发的开源游戏,展示了Libgdx的强大功能和灵活性。Libgdx是一个跨平台的游戏开发库,支持Windows、Linux、MacOS、Android以及iOS等多个操作系统,它提供了丰富的功能,使得开发者...

    libgdx-0.9.8.zip

    5. **文件I/O**:它提供了方便的数据读写接口,可以处理XML、JSON、图像、音频等资源。 6. **场景管理**:通过Scene2D库,开发者可以方便地构建2D游戏场景,包括舞台、演员、动作和动画等。 7. **网络通信**:...

    Libgdx专题系列 第一篇 第七节

    Skin skin = new Skin(Gdx.files.internal("ui/uiskin.json")); LabelStyle labelStyle = skin.get("default-font", LabelStyle.class); Label myLabel = new Label("多行\n文本示例", labelStyle); ``` 最后,可能...

Global site tag (gtag.js) - Google Analytics