7.4 JSON支持

Limax提供完整的JSON支持(Java,C#,C++,Lua版本均提供与Javascript一致的JSON支持,使用上最大限度保证与javascript相同),便于同其它支持JSON的第三方系统进行交互。


  • 7.4.1 编码

    Javascript JSON.stringify(obj)
    Java String limax.codec.JSON.stringify(Object obj);
    C# string limax.codec.JSON.stringify(object obj);
    C++

    std::string limax::JSON::stringify(const T& object);

    std::string limax::JSON::stringify(const char *obj);

    std::string limax::JSON::stringify(std::shared_ptr<limax::JSON> obj);

    Lua JSON.stringify(obj)

    C++,Lua版本中的串应该使用UTF8编码。


    • 类型映射

      Javascript Java C# C++ Lua
      Number

      byte

      Byte

      sbyte

      SByte

      int8_t

      Number

      byte

      Byte

      uint8_t

      short

      Short

      short

      Int16

      int16_t

      ushort

      UInt16

      uint16_t

      int

      Integer

      AtomicInteger

      int

      Int32

      int32_t

      uint

      UInt32

      uint32_t

      long

      Long

      AtomicLong

      long

      Int64

      int64_t

      ulong

      UInt64

      uint64_t

      float

      Float

      float

      Float

      float

      double

      Double

      double

      Double

      double
      boolean

      boolean

      Boolean

      AtomicBoolean

      bool

      bool

      bool boolean
      string

       

       

       

      char

      Character

       

      String

       

       

       

      char

      Char

      string

      String

      char

      const char*

      const std::string&

       

      string
      Array

      java.reflect.Array

      Collection

      IEnumerable

      std::list<T>

      std::vector<T>

      std::deque<T>

      std::unordered_set<T>

      std::set<T>

      table
      object

      JSONSerializable

      JSONMarshal

      Map

      JSONSerializable

      JSONMarshal

      IDictionary

       

      JSONMarshal

      std::unordered_map<K,V>

      std::map<K,V>

      table
      null null null

       

       

      JSON

       

       

       

      JSON

       

      const JSON&

      std::shared_ptr<JSON>

      注意,JSON规范对应的类型object,在之后文档中写作JSON/Object,避免与Java, C#, C++实现的JSON类构造出来的对象JSON Object混淆。数组就写作JSON/Array, 以此类推。这些通称JSON元件。

      1. Java的java.reflect.Array表示支持原生数组,Collection对应了各种集合容器。

      2. C#所有容器,原生数组均派生自IEnumerable,所以编码时优先IDictionary检测,区分出是否需要按JSON/Object编码。

      3. C++版本不支持任何类型的原生数组,或者说不支持指针方式指向的对象,const char*的支持只是一种语法糖,这种参数进入编码器前,立刻被转换成std::string。既然不支持指针方式指向的对象,也就意味着不会编码生成null,除非在JSONBuilder上使用null()方法硬编码一个null,或者进行中继,见后。

      4. Lua中table的使用乱七八糟,编码器通过#table>0的方法区分JSON/Array与JSON/Object,如果需要正确编码,不要在一个table上混用数组操作和对象操作。Lua的nil解释为null。

      5. null不利于各语言版本互操作,为了减少不必要的麻烦,尽可能避免使用。

      6. 关联容器Map,IDictionary,std::unordered_map<K,V>,std::map<K,V>,table被编码为JSON/Object时,其中的key被强制转换为字符串,按JSON/String编码。 如果容器定义了非string类型的key, 应该小心验证强制转换的结果是否符合预期。

      7. 如果编码结果提交给Javascript处理,必须注意到Javascript的Number最多支持53位整型。

      8. 表格的最后一行没有Javascript的对应,Java,C#,C++,执行JSON中继任务时使用,见后。


    • 代码生成实现(Java,C#,C++)

      Java,C#,C++三种类型化语言,使用JSONMarshal与JSONBuilder进行交互完成JSON/Object的编码。limax环境下,具体对象的JSONMarshal.marshal方法可以通过代码生成实现。 只要在bean, cbean,xbean,protocol的xml描述中正确使用json属性即可,例如:


      	<bean name="JChild" json="true">
      		<variable name="val" type="string"/>
      	</bean>
      
      	<bean name="JBean" json="true">
      		<variable name="intset" type="set" value="int"/>
      		<variable name="child" type="JChild"/>
      		<variable name="ignore" type="binary" json="false"/>
      	</bean>
      

      使用生成的JBean类型的对象,调用JSON类的静态方法stringify,即可获得类似如下的输出结果:


      	{"intset":[1,2],"child":{"val":"it's child"}}
      

      bean,cbean,xbean,protocol元素上设定属性json="true",允许为该类型生成JSON/Object编码代码, 同时默认下属variable元素的json属性为true, 除非为variable单独设置属性json="false",关闭该元素对应字段的代码成。上例中JBean.ignore字段,在编码时被忽略。


      代码生成时,将严格检查xml描述,确保生成有效的JSON/Object编码代码,否则抛出异常,停止生成。具体来说,3种情况:

      1. 使用了binary类型

      2. 使用了any类型

      3. 引用的bean没有开启json="true"


    • 反射方式实现(Java,C#)

      Java,C#支持反射,只需要在定义类的时候实现JSONSerializable标签接口即可,支持该标签的对象在编码时被直接解释为JSON/Object,字段名即是对象的key, 例如定义两个Java类:


      	public class JChild implements JSONSerializable {
      		private String val = "it's child";
      	}
      
      	public class JBean implements JSONSerializable {
      		private int intset[] = new int[] { 1, 2 };
      		private JChild child = new JChild();
      		private transient Octets ignore;
      	}
      

      System.out.println(JSON.stringify(new JBean())) 即可输出与上面例子相同的结果。

      在这里Java关键字transient,阻止了ignore字段的编码,C#没有类似特性,必须注意。特别的,C#类中定义的属性字段在反射时将获得一个C#内部编码的字段名,需要JSON编码的类尽量避免使用属性字段。


      编码器执行反射时,只考虑对象所属类本身,不考虑基类,即便基类同样实现了JSONSerializable接口。


      如果被反射的字段类型没有在类型映射一节的表格中列出,编码时将抛出JSONException异常,编码失败。详见后节——异常规范。


    • 关联容器方式实现(Java,C#,C++)

      直接对一个关联容器编码即可。

      例如Java代码:


      	Map<String, Object> jchild = new HashMap<>();
      	jchild.put("val", "it's child");
      	Map<String, Object> jbean = new HashMap<>();
      	jbean.put("intset", new int[]{1,2});
      	jbean.put("child", jchild);
      	System.out.println(JSON.stringify(jbean));
      

      可以输出与上面例子相同的结果。


      C++中基本类型缺少一个公共基类,所以上述结果无法实现。


      	std::unordered_map<std::string, std::string> jchild;
      	jchild.insert(std::make_pair("val", "it's child"));
      	std::unordered_map<std::string, std::unordered_map<std::string, std::string>> jbean;
      	jbean.insert(std::make_pair("child", jchild));
      	printf("%s\n", JSON::stringify(jbean).c_str());
      

      只能拼凑出规整的结果:


      	{"child":{"val":"it's child"}}
      

      由上可见:

      1. 对于C++,多数情况下只有使用代码生成方式,或者参考生成的代码,手工实现。

      2. 关联容器方式比生成代码方式,反射方式可读性差很多,非特殊情况不值得使用。


上一页 下一页