// ============================================================
zfbool ZFSerializableDataParseJson(ZF_OUT ZFSerializableData &ret, ZF_IN const ZFInputCallback &input)
{
    if(!input.callbackIsValid())
    {
        return zffalse;
    }
    ZFJsonItem jsonElement = ZFJsonFromInput(input);
    if(jsonElement.jsonType() == ZFJsonType::e_JsonNull)
    {
        return zffalse;
    }
    if(!ZFJsonToSerializableData(ret, jsonElement))
    {
        return zffalse;
    }

    {
        ZFString *v = input.callbackTagGet<ZFString *>(ZFCallbackTagKeyword_resPath);
        if(v != zfnull)
        {
            ret.serializableDataTagSetMarkCached(ZFSerializableDataTagKeyword_resPath, v);
        }
        else
        {
            v = input.callbackTagGet<ZFString *>(ZFCallbackTagKeyword_filePath);
            if(v != zfnull)
            {
                ret.serializableDataTagSetMarkCached(ZFSerializableDataTagKeyword_filePath, v);
            }
        }
    }
    return zftrue;
}
    void performanceTest(ZF_IN const ZFJsonItem &jsonItem)
    {
        zfindex toDataTimes = 10000;
        ZFCoreStatistic::invokeTimeAccurateLogBegin(zfText("ZFJsonPerformance_test_toData"));
        for(zfindex i = 0; i < toDataTimes; ++i)
        {
            zfstring tmp;
            ZFJsonToOutput(ZFOutputCallbackForString(tmp), jsonItem);
        }
        ZFCoreStatistic::invokeTimeAccurateLogEnd(zfText("ZFJsonPerformance_test_toData"));

        zfindex fromDataTimes = toDataTimes;
        zfstring jsonString;
        ZFJsonToOutput(ZFOutputCallbackForString(jsonString), jsonItem);
        ZFCoreStatistic::invokeTimeAccurateLogBegin(zfText("ZFJsonPerformance_test_fromData"));
        for(zfindex i = 0; i < fromDataTimes; ++i)
        {
            ZFJsonFromInput(ZFInputCallbackForBuffer(jsonString.cString()));
        }
        ZFCoreStatistic::invokeTimeAccurateLogEnd(zfText("ZFJsonPerformance_test_fromData"));
        ZFJsonItem jsonItemNew = ZFJsonFromInput(ZFInputCallbackForBuffer(jsonString.cString()));

        this->testCaseOutputSeparator();

        ZFTimeValue toDataUsedTime = ZFCoreStatistic::invokeTimeAccurateGetTotalTime(zfText("ZFJsonPerformance_test_toData"));
        this->testCaseOutput(zfText("serialize to data %zi times cost %s seconds"),
            toDataTimes,
            ZFTimeValueToStringFriendly(toDataUsedTime).cString());

        ZFTimeValue fromDataUsedTime = ZFCoreStatistic::invokeTimeAccurateGetTotalTime(zfText("ZFJsonPerformance_test_fromData"));
        this->testCaseOutput(zfText("serialize from data %zi times cost %s seconds"),
            fromDataTimes,
            ZFTimeValueToStringFriendly(fromDataUsedTime).cString());

        #if 0
            this->testCaseOutputSeparator();
            this->testCaseOutput(zfText("content: %s"), jsonString.cString());
            this->testCaseOutput(zfText("newly: %s"), ZFJsonToString(jsonItemNew).cString());
        #endif

        ZFCoreStatistic::invokeTimeAccurateRemove(zfText("ZFJsonPerformance_test_toData"));
        ZFCoreStatistic::invokeTimeAccurateRemove(zfText("ZFJsonPerformance_test_fromData"));
    }
ZFOBJECT_CREATOR_DEFINE(ZFObjectCreatorType_json, data)
{
    ZFJsonItem jsonObject = ZFJsonFromInput(ZFInputCallbackForFileDescriptor(data));
    if(jsonObject.jsonType() == ZFJsonType::e_JsonNull)
    {
        return zfautoObjectNull;
    }
    ZFSerializableData serializableData;
    if(ZFJsonToSerializableData(serializableData, jsonObject))
    {
        return ZFObjectFromSerializableData(serializableData);
    }
    return zfautoObjectNull;
}
ZF_NAMESPACE_GLOBAL_BEGIN

/*
 * <ZFString myAttr="myAttrValue" >
 *     <zfstring category="value" value="123" />
 *     <zfstring refType="123" refData="123" />
 * </ZFString>
 *
 * {
 *     "@ZFString" : [
 *         {
 *            "@zfstring" : [],
 *            "category" : "value",
 *            "value" : "123"
 *         },
 *         {
 *            "@zfstring" : [],
 *            "refType" : "123",
 *            "refData" : "123"
 *         }
 *     ],
 *     "myAttr" : "myAttrValue"
 * }
 */

#define _ZFP_ZFJsonSerializeKey_classPrefix '@'

ZFSERIALIZABLEDATA_REFERENCE_TYPE_DEFINE(ZFSerializableDataRefType_json, serializableData, data, outErrorHintToAppend)
{
    ZFJsonItem jsonObject = ZFJsonFromInput(ZFInputCallbackForFileDescriptor(data));
    if(jsonObject.jsonType() == ZFJsonType::e_JsonNull)
    {
        ZFSerializableUtil::errorOccurred(outErrorHintToAppend,
            zfText("failed to load json object from \"%s\""), data);
        return zffalse;
    }
    return ZFJsonToSerializableData(serializableData, jsonObject);
}