Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QJsonObject [] operator



  • Using some very simple JSON:

    {
        "client": "Manager",
        "clientversion": "0.1",
        "guid": "414a8189-4850-42c1-82eb-223d8f663e11",
        "message": {
            "mversion": "1.0",
            "type": "debug"
        },
        "operatingsystem": "Windows 10 (10.0)",
        "processid": 4352,
        "sdkversion": "1.2.1+965",
        "timezone": "-4",
        "wversion": "1.0"
    }
    

    If I parse this and get the QJsonObject representing the base object - everything works as expected when querying for the presence of a key using [], e.g:

    if( oBaseJsonObject["this_prop_does_not_exist"] == QJsonValue::Undefined )

    The above will evaluate to true.

    But when I child message object as below:

    if( oBaseJsonObject["message"] != QJsonValue::Undefined )
    {
        QJsonObject oMessageJsonObject = oBaseJsonObject["message"].toObject();
    }
    

    I obtain another valid JSON object - but the [] operator no longer works correctly (as far as I can tell.)

    Executing:

    if( oMessageJsonObject["this_prop_does_not_exist"] == QJsonValue::Undefined )

    Evaluates to false.

    If I obtain the value for the key that does not exist - I get an empty string.

    If I enumerate through the ::keys() collection on the oMessageJsonObject, the expected message and type keys evaluate properly and have their associated values.

    If I use the ::value( key ) method on the oMessageJsonObject - it will evaluate properly for the key that does not exist.

    Is this a bug in the [] operator or am I missing something. It works as expected on the first level, but not as I expected on the nested object. I'm no JSON expert so maybe there's some thing about treating nested objects as arrays and all keys are treated as empty/NULL values instead of Undefined...?

    Thanks,

    Hans

  • Lifetime Qt Champion

    @VRHans Why don't you use http://doc.qt.io/qt-5/qjsonobject.html#contains instead?
    Also you can use http://doc.qt.io/qt-5/qjsonvalue.html#isObject to check whether it is an object if it exists.



  • @jsulm I have a work around using ::value( key ) already, I was trying to figure out if this is a bug or I'm making assumptions about something in JSON where different behavior at different nesting levels IS expected behavior. Thanks though :)


  • Lifetime Qt Champion

    @VRHans Sounds like it could indeed be a bug. You can check on Qt bugtracker and file a bug there.



  • What type is oBaseJsonObject (please include all qualifiers)?

    Declaring oMessageJsonObject as const QJsonObject instead should fix your problem.

    Basically if you call operator[](QString) on a non-const QJsonObject the method called will be http://doc.qt.io/qt-5/qjsonobject.html#operator-5b-5d-2 and not http://doc.qt.io/qt-5/qjsonobject.html#operator-5b-5d

    This is the same problem you have in associative containers and is described in http://doc.qt.io/qt-5/qmap.html#details

    In general, we recommend that you use contains() and value() rather than operator for looking up a key in a map. The reason is that operator silently inserts an item into the map if no item exists with the same key (unless the map is const). For example, the following code snippet will create 1000 items in memory:

    // WRONG
    QMap<int, QWidget *> map;
    ...
    for (int i = 0; i < 1000; ++i) {
        if (map[i] == okButton)
            cout << "Found button at index " << i << endl;
    }
    

    To avoid this problem, replace map[i] with map.value(i) in the code above.



  • @VRonin said in QJsonObject [] operator:

    http://doc.qt.io/qt-5/qjsonobject.html#operator-5b-5d-2

    Totally makes sense - my mistake for not treating it like std::map (and other associative containers as you mentioned.)

    By design.

    Cheers,

    Hans

Log in to reply