背景:
在实际项目中,经常遇到json字符串转为lua对象后,需要判断字段是否缺失、是否与定义的类型保持一致。
不同对象需要分别判断,需要写大量重复代码,效率低,而且容易出错,所以这里实现一种可行且高效的方式。
使用案例演示:
Lua
--如果字段不是必须要检验项,可以构造时给false
--普通对象
local Cat = {
male = JsonLuaValidator.bool(),
age = JsonLuaValidator.int(),
speed = JsonLuaValidator.number(),
food = JsonLuaValidator.string()
}
local RefCat = JsonLuaValidator.object(Cat)
--对象内嵌对象
local Animal = {
addr = JsonLuaValidator.string(),
cat = RefCat,
arrcat = JsonLuaValidator.array(RefCat)
}
local RefAnimal = JsonLuaValidator.object(Animal)
--数组
local RefArrayAnimal = JsonLuaValidator.array(RefAnimal)
--普通变量示例------------------------------------------------------------------
local obj = "abc"
print(JsonLuaValidator.check(obj, JsonLuaValidator.string(), "data"))
--普通对象示例------------------------------------------------------------------
local str = [[
{
"male":true,
"age":1,
"speed":1.2,
"food":"fish"
}
]]
local obj = json.decode(str)
print(JsonLuaValidator.check(obj, RefCat, "data"))
--对象嵌套示例------------------------------------------------------------------
local str = [[
{
"addr":"china",
"cat":{
"male":true,
"age":1,
"speed":1.2,
"food":"fish"
},
"arrcat":[
{
"male":false,
"age":1,
"speed":1.2,
"food":"fish"
},
{
"male":true,
"age":2,
"speed":1.2,
"food":"fish"
}
]
}
]]
local obj = json.decode(str)
print(JsonLuaValidator.check(obj, RefAnimal, "data"))
--数组对象示例------------------------------------------------------------------
local str = [[
[
{
"addr":"china",
"cat":{
"male":true,
"age":1,
"speed":1.2,
"food":"fish"
},
"arrcat":[
{
"male":false,
"age":1,
"speed":1.2,
"food":"fish"
},
{
"male":true,
"age":2,
"speed":1.2,
"food":"fish"
}
]
},
{
"addr":"china",
"cat":{
"male":true,
"age":1,
"speed":1.2,
"food":"fish"
},
"arrcat":[
{
"male":false,
"age":1,
"speed":1.2,
"food":"fish"
},
{
"male":true,
"age":2,
"speed":1.2,
"food":"fish"
}
]
}
]
]]
local obj = json.decode(str)
print(JsonLuaValidator.check(obj, RefArrayAnimal, "data"))
面向对象实现
Lua
local JsonLuaValidator = {}
--构造一个`bool`对象
function JsonLuaValidator.bool(bIsRequired)
if nil==bIsRequired then bIsRequired=true end
return {t = "bool", --表示变量类型
req = bIsRequired, --表示该变量是否为必检项
v = false --表示该变量的类型值
}
end
--构造一个`integer`对象
function JsonLuaValidator.int(bIsRequired)
if nil==bIsRequired then bIsRequired=true end
return {t = "int", req = bIsRequired, v = 0}
end
--构造一个`float`对象
function JsonLuaValidator.float(bIsRequired)
if nil==bIsRequired then bIsRequired=true end
return {t = "float", req = bIsRequired, v = 0.0}
end
--构造一个`number`对象
function JsonLuaValidator.number(bIsRequired)
if nil==bIsRequired then bIsRequired=true end
return {t = "number", req = bIsRequired, v = 0}
end
--构造一个`string`对象
function JsonLuaValidator.string(bIsRequired)
if nil==bIsRequired then bIsRequired=true end
return {t = "string", req = bIsRequired, v = ""}
end
--构造一个`object`对象,`referenceObject`为参考对象
function JsonLuaValidator.object(referenceObject, bIsRequired)
if nil==bIsRequired then bIsRequired=true end
return {t = "object",
req = bIsRequired,
--[[
参考对象,表示`referenceObject`对象中必检项必须全都存在于待检测对象中且类型一致,参考对象中的每一个字段必须使用`JsonLuaValidator`进行初始化。
例如:
local Student = {
ok = JsonLuaValidator.bool(),
age = JsonLuaValidator.int(),
score = JsonLuaValidator.number(),
name = JsonLuaValidator.string(),
sch = JsonLuaValidator.array({""})
}
]]--
v = referenceObject
}
end
--构造一个`array`对象,`referenceObject`为数组中的元素参考对象
function JsonLuaValidator.array(referenceObject, bIsRequired)
if nil==bIsRequired then bIsRequired=true end
return {t = "array",
req = bIsRequired,
--[[
参考对象数组,通常长度为1即可,主要是告诉检测器,这个被检测的数组中的所有类型都是满足这个对象,
例如:
{JsonLuaValidator.string()}表示字符串数组、
{JsonLuaValidator.number()}表示数字数组、
{JsonLuaValidator.bool()}表示bool数组、
{JsonLuaValidator.object({a=JsonLuaValidator.bool(),b=JsonLuaValidator.number()})}表示对象数组
入参`referenceObject`只需要传入一个引用构造对象即可
]]--
v = {referenceObject}
}
end
--[[
功能:校验json字符串转为lua对象后,字段的缺失与合法性的判断。
参数:luaObj-json字符串转换为lua的对象
refObject-校验合法性的参考对象,也就是luaObj对象的变异体,变异体本身以及变异体里面的字段变量都需要使用`JsonLuaValidator`进行初始化
objName-对象名称,通常是顶级对象名称,主要是用来返回失败时,输出哪个字段失败
返回值:boolean,string-分别表示成功与失败、失败原因信息
]]--
function JsonLuaValidator.check(luaObj, refObject, objName)
objName = objName or ""
--检测refObject必须满足固定格式要求
if type(refObject)~="table" then
return false,"inner error:the ref object `"..objName.."` is invalid table"
end
if type(refObject.t)~="string" then
return false,"inner error:the field `t` in ref object `"..objName.."` is not string or not exists"
end
if type(refObject.req)~="boolean" then
return false,"inner error:the field `req` in ref object `"..objName.."` is not boolean or not exists"
end
if type(refObject.v)=="nil" then
return false,"inner error:the field `v` in ref object `"..objName.."` is not exists"
end
if true~=refObject.req then
return true,"" --不是必须检验项则默认合法
end
if refObject.t == "bool" then
if type(luaObj) ~= "boolean" then
return false,objName.." is not boolean or not exists"
end
elseif refObject.t == "int" then
if math.type(luaObj) ~= "integer" then
return false,objName.." is not integer or not exists"
end
elseif refObject.t == "float" then
if math.type(luaObj) ~= "float" then
return false,objName.." is not float or not exists"
end
elseif refObject.t == "number" then
if type(luaObj) ~= "number" then
return false,objName.." is not number or not exists"
end
elseif refObject.t == "string" then
if type(luaObj) ~= "string" then
return false,objName.." is not string or not exists"
end
elseif refObject.t == "object" then
if type(luaObj) ~= "table" then
return false,objName.." is not table or not exists"
end
if type(refObject.v) ~= "table" then
return false,"inner error:the field `v` in ref object `"..objName.."` is not table or not exists"
end
for k,v in pairs(refObject.v) do
local _ok,err = JsonLuaValidator.check(luaObj[k], v, objName.."."..k)
if not _ok then
return false,err
end
end
elseif refObject.t == "array" then
if type(luaObj) ~= "table" then
return false,objName.." is not array or not exists"
end
if type(refObject.v) ~= "table" then
return false,"inner error:the field `v` in ref object `"..objName.."` is not array or not exists"
end
local newRefObj = refObject.v[1]
for i=1,#luaObj do
local _ok,err = JsonLuaValidator.check(luaObj[i], newRefObj, objName.."["..i.."]")
if not _ok then
return false,err
end
end
end
return true,""
end
return JsonLuaValidator