Skip to content

Parsing JSON#

This page describes how to read JSON with aui::json. To convert JSON into your own structures, see Custom types and JSON.

Parsing#

AJson::fromString parses a string and returns an AJson tree. The result is a regular value type: copy it, move it, store it.

1
2
3
4
5
6
7
auto json = AJson::fromString(R"({"name":"Alex2772","year":2020,"tags":["a","b"],"girlfriend":null})");

EXPECT_EQ(json["name"].asString(), "Alex2772");
EXPECT_EQ(json["year"].asInt(), 2020);
EXPECT_EQ(json["tags"].asArray().size(), 2);
EXPECT_EQ(json["tags"][1].asString(), "b");
EXPECT_TRUE(json["girlfriend"].isNull());

Alternatively, AJson::fromStream reads from any IInputStream (file, socket, etc...) and AJson::fromBuffer reads from a byte buffer.

auto json = AJson::fromStream(AStringStream(AString(R"({"hello":"world"})")));
EXPECT_EQ(json["hello"].asString(), "world");

Accessing values#

operator[] accepts a string key for objects and an integer index for arrays. Use asInt(), asLongInt(), asNumber(), asBool(), asString(), asArray() and asObject() to extract the actual value.

Every as* accessor throws AJsonTypeMismatchException if the value is of another type. If you'd rather not deal with exceptions, use as*Opt() counterparts, which return an AOptional, and is*() checks.

1
2
3
4
5
6
7
8
auto json = AJson::fromString(R"({"year":2020})");

// optional accessors never throw
EXPECT_EQ(json["year"].asIntOpt(), 2020);
EXPECT_FALSE(json["year"].asStringOpt());

// regular accessors throw on type mismatch
EXPECT_THROW(json["year"].asString(), AJsonTypeMismatchException);

Checking if a key exists#

Warning

operator[] with a missing key does not fail. It appends an empty (isEmpty()) entry to the object. To look up a key without modifying the object, use contains or containsOpt.

1
2
3
4
5
6
7
const auto json = AJson::fromString(R"({"year":2020})");

EXPECT_TRUE(json.contains("year"));
EXPECT_FALSE(json.contains("name"));
if (auto year = json.containsOpt("year")) {
    EXPECT_EQ(year->asInt(), 2020);
}

Note the difference between isEmpty() (key is absent) and isNull() (key is present and set to null).

Handling errors#

Malformed input makes the parser throw AJsonParseException. All JSON exceptions derive from AJsonException, which in turn derives from AException.

1
2
3
4
5
6
7
try {
    AJson::fromString(R"({"array": [1,2,3})"); // missing closing bracket
    FAIL() << "expected AJsonParseException";
} catch (const AJsonParseException& e) {
    // e.getMessage() describes what went wrong
    EXPECT_FALSE(e.getMessage().empty());
}

Numbers#

JSON itself doesn't distinguish between integers and floating point numbers; aui::json does. Integers that fit into int are stored as int, bigger ones as int64_t, and numbers with a fraction or an exponent as double. asNumber() accepts any of them, asLongInt() accepts both integer kinds, and asInt() only the first one.