低版本CJson反序列化方案
现在的API接口普遍使用Json语法来描述,API的返回通常使用类似这样的结构:{code:0,message:,data:{。。。}}
即所有API都有code和message属性以表示成功或错误,它和业务是无关的;其它属性数据则在data中定义,它和业务是相关的。
这种情况在CJAVA中做反序列化时一般用泛型表示,如:classMyAPI{publicintx;publicinty;}classApiResponseT{publicintcode;publicstringmessage;publicTdata;}ApiResponseMyAPIrespJsonConvert。DeserializeObject(。。。);
C的处理方案由于RTTI(RuntimeTypeInformation运行时类型信息)并不包含属性名等信息,无法通过反射找到类结构的属性,因此无法实现CJAVA那种看起来比较优雅的写法。
github上解决这个问题的项目很多,但它们许多要求使用c17或20以上的版本,由于我的项目限制只能使用c14,因此我只看c11或14的解决方案。
这些项目的解决方案大体有两类:
1。提供更友好的读写属性的方法,比如通过〔。。。〕〔。。。〕层层嵌套,让用户更容易读写属性,但是它并没有完成在对象结构实体上的映射和赋值,相当于这个工作得用户来做,因此它更像是只提供了一些序列化反序列化的辅助方法,而不是完整的json和对象转化的解决方案,标星超过3万的https:github。comnlohmannjson就是这种情况;
2。允许用户用通常的写法去定义类结构,再通过宏去标识需要和json做映射的属性,完成类似其他语言的反射机制,当然它是在编译期实现属性定位而不是其他语言的运行期。
方案2在使用成本上相较方案1要小很多,也更符合主流方案的习惯。我看了几个项目,最后选了jsonstruct(https:github。comjorgenjsonstruct),它的解决方案是:
对于一个json串:{One:1,Two:two,Three:3。333}
定义一个类:structJsonObject{intOne;std::stringTwo;doubleThree;JSOBJ(One,Two,Three);};
JSOBJ是用于解决反射问题的宏,也可以定义在类外面:structJsonObject{intOne;std::stringTwo;doubleThree;};JSOBJEXT(JsonObject,One,Two,Three);
反序列化:JS::ParseContextcontext(jsondata);JsonObjectobj;context。parseTo(obj);
由此可见,除了所有方案都要写的类结构定义之外,为反序列化要做的也就只写几行代码而已,相对方案1是简单了很多的,与CJAVA的解决方案相当。
回到最初的需求:{code:0,message:,data:{。。。}}
这个结构是嵌套的,无法使用类似于CJAVA的写法:classMyAPI{publicintx;publicinty;}classApiResponseT{publicintcode;publicstringmessage;publicTdata;}ApiResponseMyAPIrespJsonConvert。DeserializeObject(。。。);
jsonstruct的文档和examples中也没有提供明确的案例可以参考。
我试了一下,可以这样来定义:structApiResponse{intcode;stringmessage;JSOBJ(code,message);}structMyApiData{intx;inty;JSOBJ(x,y);}structMyAPI:publicApiResponse{MyApiDatadata;JSOBJ(data);}
然后这样解析就可以了:JS::ParseContextcontext(。。。);MyAPImyApi;context。parseTo(myApi);
上述写法,相较CJAVA,CJAVA是用ApiResponse来包MyAPI(泛型传参),C是用MyAPI来包ApiResponse(子类继承),并将子属性data从MyAPI拆出来,相当于多定义了一级,从语法上似乎稍微累赘一点,但整体结构还是清晰直观的。