├── CMakeLists.txt ├── LICENSE ├── README.md ├── include └── nlohmann │ └── json-qt.hpp └── tests ├── CMakeLists.txt └── test.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | 3 | if (DEFINED PROJECT_NAME) 4 | set(JSON_QT_STANDALONE OFF) 5 | else() 6 | set(JSON_QT_STANDALONE ON) 7 | endif() 8 | 9 | project(nlohmann_json_qt LANGUAGES CXX) 10 | 11 | option(JSON_QT_BUILD_TESTS "Build tests for nlohmann_json_qt" ${JSON_QT_STANDALONE}) 12 | 13 | set(CMAKE_CXX_STANDARD 11) 14 | set(CMAKE_CXX_STANDARD_REQUIRED 11) 15 | 16 | add_library(nlohmann_json_qt INTERFACE include/nlohmann/json-qt.hpp) 17 | 18 | find_package(Qt5Core REQUIRED) 19 | 20 | target_include_directories(nlohmann_json_qt INTERFACE include) 21 | target_link_libraries(nlohmann_json_qt INTERFACE Qt5::Core) 22 | target_sources(nlohmann_json_qt INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include/nlohmann/json-qt.hpp) 23 | 24 | if (JSON_QT_BUILD_TESTS) 25 | enable_testing() 26 | add_subdirectory(tests) 27 | endif() 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Dmitriy Purgin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nlohmann_json_qt 2 | A collection of helper functions for Qt to use with nlohmann/json 3 | 4 | Adds support for deserialization of the following Qt types from `basic_json`: 5 | 6 | * `QString` 7 | * `QUrl` 8 | * `QDateTime` with `Qt::ISODateWithMs` 9 | * `QVector` 10 | * `QList` 11 | * `QVariantList` 12 | * `QVariantMap` 13 | * A limited subset of values stored in `QVariant`: 14 | * `QVariantList` 15 | * `QVariantMap` 16 | * `QString` 17 | * `double` 18 | * `bool` 19 | * `int` 20 | * `unsigned int` 21 | * `long long int` 22 | * `unsigned long long int` 23 | * All other values are converted to a `null` JSON value. 24 | 25 | This is a header-only library. Add the header to your include paths or use CMake and link against `nlohmann_json_qt`. 26 | -------------------------------------------------------------------------------- /include/nlohmann/json-qt.hpp: -------------------------------------------------------------------------------- 1 | // Helper definitions for Qt types to use with nlohmann/json deserializer 2 | // Copyright (C) 2020 Dmitriy Purgin 3 | // 4 | // Licensed under the MIT license. See LICENSE for details. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | #ifndef NLOHMANN_JSON_QT_HPP 25 | #define NLOHMANN_JSON_QT_HPP 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | 39 | QT_BEGIN_NAMESPACE 40 | 41 | inline void from_json(const nlohmann::json &j, QString &string) 42 | { 43 | string = QString::fromStdString(j.get()); 44 | } 45 | 46 | inline void from_json(const nlohmann::json &j, QDateTime &dateTime) 47 | { 48 | dateTime = QDateTime::fromString(j.get(), Qt::ISODateWithMs); 49 | } 50 | 51 | inline void from_json(const nlohmann::json &j, QUrl &url) 52 | { 53 | url.setUrl(j.get()); 54 | } 55 | 56 | inline void from_json(const nlohmann::json &j, QVariant& variant) 57 | { 58 | if (j.is_null()) 59 | { 60 | variant = QVariant::fromValue(nullptr); 61 | } 62 | else if (j.is_number_unsigned()) 63 | { 64 | variant = QVariant::fromValue(j.get()); 65 | } 66 | else if (j.is_number_integer()) 67 | { 68 | variant = QVariant::fromValue(j.get()); 69 | } 70 | else if (j.is_number_float()) 71 | { 72 | variant = QVariant::fromValue(j.get()); 73 | } 74 | else if (j.is_string()) 75 | { 76 | variant = QVariant::fromValue(j.get()); 77 | } 78 | else if (j.is_boolean()) 79 | { 80 | variant = QVariant::fromValue(j.get()); 81 | } 82 | } 83 | 84 | template 85 | inline void from_json(const nlohmann::json &j, QVector &vector) 86 | { 87 | for (const auto &item : j) { 88 | vector.push_back(item.get()); 89 | } 90 | } 91 | 92 | template 93 | inline void from_json(const nlohmann::json &j, QList &list) 94 | { 95 | for (const auto &item : j) { 96 | list.push_back(item.get()); 97 | } 98 | } 99 | 100 | inline void to_json(nlohmann::json& j, const QVariant&); 101 | 102 | inline void to_json(nlohmann::json& j, const QVariantList& list) 103 | { 104 | j = nlohmann::json::array(); 105 | 106 | for (auto it = list.cbegin(); it != list.cend(); ++it) 107 | { 108 | nlohmann::json serialized; 109 | to_json(serialized, *it); 110 | j.push_back(serialized); 111 | } 112 | } 113 | 114 | inline void to_json(nlohmann::json& j, const QVariantMap& map) 115 | { 116 | j = nlohmann::json::object(); 117 | 118 | for (auto it = map.cbegin(); it != map.cend(); ++it) 119 | { 120 | nlohmann::json serialized; 121 | to_json(serialized, it.value()); 122 | j[it.key().toStdString()] = serialized; 123 | } 124 | } 125 | 126 | inline void to_json(nlohmann::json& j, const QVariant& variant) 127 | { 128 | auto type = static_cast(variant.type()); 129 | 130 | if (type == QMetaType::QVariantList) 131 | { 132 | to_json(j, variant.value()); 133 | } 134 | else if (type == QMetaType::QVariantMap) 135 | { 136 | to_json(j, variant.value()); 137 | } 138 | else if (type == QMetaType::QString) 139 | { 140 | j = variant.toString().toStdString(); 141 | } 142 | else if (type == QMetaType::Double) 143 | { 144 | j = variant.toDouble(); 145 | } 146 | else if (type == QMetaType::Bool) 147 | { 148 | j = variant.toBool(); 149 | } 150 | else if (type == QMetaType::Int) 151 | { 152 | j = variant.toInt(); 153 | } 154 | else if (type == QMetaType::UInt) 155 | { 156 | j = variant.toUInt(); 157 | } 158 | else if (type == QMetaType::LongLong) 159 | { 160 | j = variant.toLongLong(); 161 | } 162 | else if (type == QMetaType::ULongLong) 163 | { 164 | j = variant.toULongLong(); 165 | } 166 | else 167 | { 168 | j.clear(); 169 | } 170 | } 171 | 172 | QT_END_NAMESPACE 173 | 174 | #endif 175 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | include(FetchContent) 3 | 4 | if (NOT TARGET nlohmann_json) 5 | FetchContent_Declare(json 6 | GIT_REPOSITORY https://github.com/nlohmann/json.git 7 | GIT_TAG v3.9.1 8 | GIT_SHALLOW TRUE 9 | ) 10 | set(JSON_BuildTests OFF CACHE BOOL "") 11 | set(JSON_Install OFF CACHE BOOL "") 12 | FetchContent_MakeAvailable(json) 13 | endif() 14 | 15 | set(CMAKE_AUTOMOC TRUE) 16 | 17 | find_package(Qt5 COMPONENTS Core Test REQUIRED) 18 | 19 | add_executable(nlohmann_json_qt_test test.cpp) 20 | add_test(NAME nlohmann_json_qt_test COMMAND nlohmann_json_qt_test) 21 | 22 | target_link_libraries(nlohmann_json_qt_test 23 | PUBLIC 24 | Qt5::Core 25 | Qt5::Test 26 | nlohmann_json 27 | nlohmann_json_qt 28 | ) 29 | -------------------------------------------------------------------------------- /tests/test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020 Dmitriy Purgin 2 | // 3 | // Licensed under the MIT license. See LICENSE for details. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | Q_DECLARE_METATYPE(nlohmann::json) 32 | 33 | class NlohmannJsonQtTest : public QObject 34 | { 35 | Q_OBJECT 36 | 37 | template 38 | void run() 39 | { 40 | QFETCH(QByteArray, input); 41 | QFETCH(T, expected); 42 | 43 | auto json = nlohmann::json::parse(input.constBegin(), input.constEnd()); 44 | QCOMPARE(json.get(), expected); 45 | } 46 | 47 | private slots: 48 | void testBasicJsonToQString_data(); 49 | void testBasicJsonToQString(); 50 | 51 | void testBasicJsonToQDateTime_data(); 52 | void testBasicJsonToQDateTime(); 53 | 54 | void testBasicJsonToQUrl_data(); 55 | void testBasicJsonToQUrl(); 56 | 57 | void testBasicJsonToQVectorInt(); 58 | 59 | void testBasicJsonToQStringList(); 60 | 61 | void testBasicJsonToLongLong(); 62 | 63 | void testQVariantToNlohmannJson_data(); 64 | void testQVariantToNlohmannJson(); 65 | }; 66 | 67 | void NlohmannJsonQtTest::testBasicJsonToQString_data() 68 | { 69 | QTest::addColumn("input"); 70 | QTest::addColumn("expected"); 71 | 72 | QTest::addRow("Empty") << QByteArray{R"("")"} << QString{}; 73 | QTest::addRow("Latin1") << QByteArray{R"("foo")"} << QString{"foo"}; 74 | QTest::addRow("Unicode") << QByteArray{R"("\u00e4\u00fc\u0436\u0448")"} << QString{"äüжш"}; 75 | } 76 | 77 | void NlohmannJsonQtTest::testBasicJsonToQString() 78 | { 79 | run(); 80 | } 81 | 82 | void NlohmannJsonQtTest::testBasicJsonToQDateTime_data() 83 | { 84 | QTest::addColumn("input"); 85 | QTest::addColumn("expected"); 86 | 87 | QTest::addRow("ISO 8601 with timezone") 88 | << QByteArray{R"("2020-11-08T14:31:05+01:00")"} 89 | << QDateTime{{2020, 11, 8}, {14, 31, 5}, QTimeZone{3600}}; 90 | } 91 | 92 | void NlohmannJsonQtTest::testBasicJsonToQDateTime() 93 | { 94 | run(); 95 | } 96 | 97 | void NlohmannJsonQtTest::testBasicJsonToQUrl_data() 98 | { 99 | QTest::addColumn("input"); 100 | QTest::addColumn("expected"); 101 | 102 | QTest::addRow("Example") << QByteArray{R"("https://example.com/example")"} 103 | << QUrl{"https://example.com/example"}; 104 | } 105 | 106 | void NlohmannJsonQtTest::testBasicJsonToQUrl() 107 | { 108 | run(); 109 | } 110 | 111 | void NlohmannJsonQtTest::testBasicJsonToQVectorInt() 112 | { 113 | auto json = R"([-1, 0, 1, 12312, -140])"_json; 114 | QCOMPARE(json.get>(), QVector({-1, 0, 1, 12312, -140})); 115 | } 116 | 117 | void NlohmannJsonQtTest::testBasicJsonToQStringList() 118 | { 119 | auto json = R"(["foo", "bar", "", "342"])"_json; 120 | QCOMPARE(json.get(), 121 | QStringList{} << "foo" 122 | << "bar" 123 | << "" 124 | << "342"); 125 | } 126 | 127 | void NlohmannJsonQtTest::testBasicJsonToLongLong() 128 | { 129 | auto json = "8589934591"_json; 130 | QCOMPARE(json.get(), 0x1FFFFFFFFLL); 131 | QCOMPARE(json.get(), 0x1FFFFFFFFULL); 132 | } 133 | 134 | void NlohmannJsonQtTest::testQVariantToNlohmannJson_data() 135 | { 136 | QTest::addColumn("input"); 137 | QTest::addColumn("expected"); 138 | 139 | QTest::addRow("qlonglong") << QVariant{0x1FFFFFFFFLL} << "8589934591"_json; 140 | QTest::addRow("qulonglong") << QVariant{0x1FFFFFFFFULL} << "8589934591"_json; 141 | } 142 | 143 | void NlohmannJsonQtTest::testQVariantToNlohmannJson() 144 | { 145 | QFETCH(QVariant, input); 146 | QFETCH(nlohmann::json, expected); 147 | 148 | nlohmann::json actual; 149 | to_json(actual, input); 150 | QCOMPARE(actual, expected); 151 | } 152 | 153 | QTEST_APPLESS_MAIN(NlohmannJsonQtTest) 154 | 155 | #include "test.moc" 156 | --------------------------------------------------------------------------------