├── .github └── workflows │ └── build.yml ├── .gitignore ├── .qmake.conf ├── LICENSE ├── README.md ├── deploy.json ├── doc ├── Doxyfile ├── cborserializer.dox ├── doc.pro ├── doxme.py ├── gh_header.html ├── images │ └── GitHub_Logo.png ├── jsonserializer.dox ├── makedoc.sh ├── metawriters.dox ├── qtjsonserializer.dox ├── serializerbase.dox ├── typeconverter.dox └── typeextractor.dox ├── examples ├── examples.pro └── jsonserializer │ ├── Sample │ ├── Sample.pro │ ├── main.cpp │ ├── samplegadget.cpp │ ├── samplegadget.h │ ├── sampleobject.cpp │ └── sampleobject.h │ └── jsonserializer.pro ├── qtjsonserializer.pro ├── src ├── jsonserializer │ ├── cborserializer.cpp │ ├── cborserializer.h │ ├── cborserializer_p.h │ ├── exception.cpp │ ├── exception.h │ ├── exception_p.h │ ├── exceptioncontext.cpp │ ├── exceptioncontext_p.h │ ├── jsonserializer.cpp │ ├── jsonserializer.h │ ├── jsonserializer.pro │ ├── jsonserializer_p.h │ ├── metawriters.cpp │ ├── metawriters.h │ ├── metawriters_p.h │ ├── qjsonreggen.pri │ ├── qjsonreggen.py │ ├── qtjsonserializer_global.h │ ├── qtjsonserializer_helpertypes.h │ ├── serializerbase.cpp │ ├── serializerbase.h │ ├── serializerbase_p.h │ ├── typeconverter.cpp │ ├── typeconverter.h │ ├── typeconverters │ │ ├── bitarrayconverter.cpp │ │ ├── bitarrayconverter_p.h │ │ ├── bytearrayconverter.cpp │ │ ├── bytearrayconverter_p.h │ │ ├── cborconverter.cpp │ │ ├── cborconverter_p.h │ │ ├── datetimeconverter.cpp │ │ ├── datetimeconverter_p.h │ │ ├── enumconverter.cpp │ │ ├── enumconverter_p.h │ │ ├── gadgetconverter.cpp │ │ ├── gadgetconverter_p.h │ │ ├── geomconverter.cpp │ │ ├── geomconverter_p.h │ │ ├── legacygeomconverter.cpp │ │ ├── legacygeomconverter_p.h │ │ ├── listconverter.cpp │ │ ├── listconverter_p.h │ │ ├── localeconverter.cpp │ │ ├── localeconverter_p.h │ │ ├── mapconverter.cpp │ │ ├── mapconverter_p.h │ │ ├── multimapconverter.cpp │ │ ├── multimapconverter_p.h │ │ ├── objectconverter.cpp │ │ ├── objectconverter_p.h │ │ ├── pairconverter.cpp │ │ ├── pairconverter_p.h │ │ ├── smartpointerconverter.cpp │ │ ├── smartpointerconverter_p.h │ │ ├── stdchronodurationconverter.cpp │ │ ├── stdchronodurationconverter_p.h │ │ ├── stdoptionalconverter.cpp │ │ ├── stdoptionalconverter_p.h │ │ ├── stdtupleconverter.cpp │ │ ├── stdtupleconverter_p.h │ │ ├── stdvariantconverter.cpp │ │ ├── stdvariantconverter_p.h │ │ ├── typeconverters.pri │ │ ├── versionnumberconverter.cpp │ │ └── versionnumberconverter_p.h │ └── typeextractors.h └── src.pro ├── sync.profile └── tests ├── auto ├── auto.pro ├── cmake │ ├── CMakeLists.txt │ └── cmake.pro ├── jsonserializer │ ├── BitArrayConverterTest │ │ ├── BitArrayConverterTest.pro │ │ └── tst_bitarrayconverter.cpp │ ├── BytearrayConverterTest │ │ ├── BytearrayConverterTest.pro │ │ └── tst_bytearrayconverter.cpp │ ├── CborConverterTest │ │ ├── CborConverterTest.pro │ │ └── tst_cborconverter.cpp │ ├── ChronoDurationConverterTest │ │ ├── ChronoDurationConverterTest.pro │ │ └── tst_chronodurationconverter.cpp │ ├── DateTimeConverterTest │ │ ├── DateTimeConverterTest.pro │ │ └── tst_datetimeconverter.cpp │ ├── EnumConverterTest │ │ ├── EnumConverterTest.pro │ │ ├── testclass.cpp │ │ ├── testclass.h │ │ └── tst_enumconverter.cpp │ ├── GadgetConverterTest │ │ ├── GadgetConverterTest.pro │ │ ├── testgadget.cpp │ │ ├── testgadget.h │ │ └── tst_gadgetconverter.cpp │ ├── GeomConverterTest │ │ ├── GeomConverterTest.pro │ │ └── tst_geomconverter.cpp │ ├── LegacyGeomConverterTest │ │ ├── LegacyGeomConverterTest.pro │ │ └── tst_legacygeomconverter.cpp │ ├── ListConverterTest │ │ ├── ListConverterTest.pro │ │ └── tst_listconverter.cpp │ ├── LocaleConverterTest │ │ ├── LocaleConverterTest.pro │ │ └── tst_localeconverter.cpp │ ├── MapConverterTest │ │ ├── MapConverterTest.pro │ │ └── tst_mapconverter.cpp │ ├── MultiMapConverterTest │ │ ├── MultiMapConverterTest.pro │ │ └── tst_multimapconverter.cpp │ ├── ObjectConverterTest │ │ ├── ObjectConverterTest.pro │ │ ├── testobject.cpp │ │ ├── testobject.h │ │ └── tst_objectconverter.cpp │ ├── OptionalConverterTest │ │ ├── OptionalConverterTest.pro │ │ └── tst_optionalconverter.cpp │ ├── PairConverterTest │ │ ├── PairConverterTest.pro │ │ └── tst_pairconverter.cpp │ ├── SerializerTest │ │ ├── SerializerTest.pro │ │ ├── testconverter.cpp │ │ ├── testconverter.h │ │ └── tst_serializer.cpp │ ├── SmartPointerConverterTest │ │ ├── SmartPointerConverterTest.pro │ │ ├── testobject.cpp │ │ ├── testobject.h │ │ └── tst_smartpointerconverter.cpp │ ├── TupleConverterTest │ │ ├── TupleConverterTest.pro │ │ └── tst_tupleconverter.cpp │ ├── TypeConverterTestLib │ │ ├── TypeConverterTestLib.pro │ │ ├── dummyserializationhelper.cpp │ │ ├── dummyserializationhelper.h │ │ ├── multitypeconvertertestbase.cpp │ │ ├── multitypeconvertertestbase.h │ │ ├── opaquedummy.cpp │ │ ├── opaquedummy.h │ │ ├── typeconvertertestbase.cpp │ │ └── typeconvertertestbase.h │ ├── VariantConverterTest │ │ ├── VariantConverterTest.pro │ │ └── tst_variantconverter.cpp │ ├── VersionConverterTest │ │ ├── VersionConverterTest.pro │ │ └── tst_versionconverter.cpp │ ├── convlib.pri │ └── jsonserializer.pro └── testrun.pri ├── global └── global.cfg └── tests.pro /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: CI build 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | strategy: 8 | fail-fast: false 9 | matrix: 10 | version: 11 | - 5.14.1 12 | platform: 13 | - gcc_64 14 | - android 15 | - wasm_32 16 | - msvc2017_64 17 | - msvc2017 18 | - winrt_x64_msvc2017 19 | - winrt_x86_msvc2017 20 | - winrt_armv7_msvc2017 21 | - mingw73_64 22 | - mingw73_32 23 | - clang_64 24 | - ios 25 | converters: 26 | - enabled 27 | - disabled 28 | 29 | include: 30 | - platform: gcc_64 31 | os: ubuntu-latest 32 | - platform: android 33 | os: ubuntu-latest 34 | - platform: wasm_32 35 | os: ubuntu-latest 36 | emsdk: sdk-fastcomp-1.38.27-64bit 37 | - platform: msvc2017_64 38 | os: windows-latest 39 | - platform: msvc2017 40 | os: windows-latest 41 | - platform: winrt_x64_msvc2017 42 | os: windows-latest 43 | - platform: winrt_x86_msvc2017 44 | os: windows-latest 45 | - platform: winrt_armv7_msvc2017 46 | os: windows-2016 # not working with latest yet... 47 | - platform: mingw73_64 48 | os: windows-latest 49 | - platform: mingw73_32 50 | os: windows-latest 51 | - platform: clang_64 52 | os: macos-latest 53 | - platform: ios 54 | os: macos-latest 55 | 56 | - converters: disabled 57 | config: no_register_json_converters 58 | 59 | runs-on: ${{matrix.os}} 60 | steps: 61 | - uses: actions/checkout@v1 62 | with: 63 | submodules: recursive 64 | - uses: actions/setup-python@v1 65 | - name: actions/cache emsdk 66 | uses: actions/cache@v1 67 | if: matrix.platform == 'wasm_32' 68 | with: 69 | path: emsdk-cache 70 | key: ${{runner.os}}-emsdk-${{matrix.emsdk}} 71 | - uses: mymindstorm/setup-emsdk@v3 72 | if: matrix.platform == 'wasm_32' 73 | with: 74 | version: ${{matrix.emsdk}} 75 | actions-cache-folder: emsdk-cache 76 | - name: actions/cache qt 77 | uses: actions/cache@v1 78 | id: cache 79 | with: 80 | path: qt/${{matrix.version}}/${{matrix.platform}} 81 | key: qt-${{matrix.version}}-${{matrix.platform}}-direct 82 | - uses: Skycoder42/action-setup-qt@master 83 | id: qt 84 | with: 85 | version: ${{matrix.version}} 86 | platform: ${{matrix.platform}} 87 | cachedir: qt/${{matrix.version}}/${{matrix.platform}} 88 | - name: qmake 89 | run: | 90 | qmake CONFIG+=install_ok QT_PLATFORM=${{matrix.platform}} CONFIG+=${{matrix.config}} 91 | ${{steps.qt.outputs.make}} qmake_all 92 | - name: make module 93 | run: | 94 | ${{steps.qt.outputs.make}} 95 | ${{steps.qt.outputs.make}} INSTALL_ROOT="${{steps.qt.outputs.installdir}}" install 96 | - name: make tests 97 | if: matrix.converters == 'enabled' && steps.qt.outputs.tests == 'true' 98 | run: | 99 | ${{steps.qt.outputs.make}} all 100 | ${{steps.qt.outputs.make}} ${{steps.qt.outputs.testflags}} run-tests 101 | - name: make examples 102 | if: matrix.converters == 'enabled' && matrix.platform == 'gcc_64' 103 | run: | 104 | ${{steps.qt.outputs.make}} sub-examples 105 | cd examples && ${{steps.qt.outputs.make}} INSTALL_ROOT="${{steps.qt.outputs.installdir}}" install 106 | - name: make doc 107 | if: matrix.converters == 'enabled' && matrix.platform == 'gcc_64' 108 | run: | 109 | ${{steps.qt.outputs.make}} doxygen 110 | cd doc && ${{steps.qt.outputs.make}} INSTALL_ROOT="${{steps.qt.outputs.installdir}}" install 111 | - name: upload module to releases 112 | uses: Skycoder42/action-upload-release@master 113 | if: matrix.converters == 'enabled' && startsWith(github.ref, 'refs/tags/') 114 | with: 115 | repo_token: ${{secrets.GITHUB_TOKEN}} 116 | directory: ${{steps.qt.outputs.outdir}}/${{matrix.version}} 117 | asset_name: qtjsonserializer-${{matrix.platform}}-${{matrix.version}} 118 | tag: ${{github.ref}} 119 | overwrite: true 120 | - name: upload examples to releases 121 | uses: Skycoder42/action-upload-release@master 122 | if: matrix.converters == 'enabled' && matrix.platform == 'gcc_64' && startsWith(github.ref, 'refs/tags/') 123 | with: 124 | repo_token: ${{secrets.GITHUB_TOKEN}} 125 | directory: ${{steps.qt.outputs.outdir}}/${{matrix.version}}/${{matrix.platform}}/examples 126 | asset_name: qtjsonserializer-examples-${{matrix.version}} 127 | tag: ${{github.ref}} 128 | overwrite: true 129 | - name: upload doc to releases 130 | uses: Skycoder42/action-upload-release@master 131 | if: matrix.converters == 'enabled' && matrix.platform == 'gcc_64' && startsWith(github.ref, 'refs/tags/') 132 | with: 133 | repo_token: ${{secrets.GITHUB_TOKEN}} 134 | directory: ${{steps.qt.outputs.outdir}}/${{matrix.version}}/${{matrix.platform}}/doc 135 | asset_name: qtjsonserializer-doc-${{matrix.version}} 136 | tag: ${{github.ref}} 137 | overwrite: true 138 | 139 | deploy: 140 | if: startsWith(github.ref, 'refs/tags/') 141 | needs: [build] 142 | runs-on: ubuntu-latest 143 | steps: 144 | - uses: actions/setup-python@v1 145 | - uses: Skycoder42/action-deploy-qt@master 146 | with: 147 | token: ${{secrets.GITHUB_TOKEN}} 148 | version: 5.14.1 149 | host: ${{secrets.SSHFS_HOST}} 150 | key: ${{secrets.SSHFS_KEY}} 151 | port: ${{secrets.SSHFS_PORT}} 152 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | *~ 5 | *.autosave 6 | *.a 7 | *.core 8 | *.moc 9 | *.o 10 | *.obj 11 | *.orig 12 | *.rej 13 | *.so 14 | *.so.* 15 | *_pch.h.cpp 16 | *_resource.rc 17 | *.qm 18 | .#* 19 | *.*# 20 | core 21 | !core/ 22 | tags 23 | .DS_Store 24 | .directory 25 | *.debug 26 | Makefile* 27 | *.prl 28 | *.app 29 | moc_*.cpp 30 | ui_*.h 31 | qrc_*.cpp 32 | Thumbs.db 33 | *.res 34 | *.rc 35 | /.qmake.cache 36 | /.qmake.stash 37 | 38 | # qtcreator generated files 39 | *.pro.user* 40 | 41 | # xemacs temporary files 42 | *.flc 43 | 44 | # Vim temporary files 45 | .*.swp 46 | 47 | # Visual Studio generated files 48 | *.ib_pdb_index 49 | *.idb 50 | *.ilk 51 | *.pdb 52 | *.sln 53 | *.suo 54 | *.vcproj 55 | *vcproj.*.*.user 56 | *.ncb 57 | *.sdf 58 | *.opensdf 59 | *.vcxproj 60 | *vcxproj.* 61 | 62 | # MinGW generated files 63 | *.Debug 64 | *.Release 65 | 66 | # Python byte code 67 | *.pyc 68 | 69 | # Binaries 70 | # -------- 71 | *.dll 72 | *.exe 73 | 74 | -------------------------------------------------------------------------------- /.qmake.conf: -------------------------------------------------------------------------------- 1 | load(qt_build_config) 2 | 3 | CONFIG += warning_clean exceptions qt_module_build c++17 4 | DEFINES += QT_DEPRECATED_WARNINGS QT_ASCII_CAST_WARNINGS 5 | 6 | MODULE_VERSION = 4.0.3 7 | 8 | # had to be added because std::visit only works on macos 10.14 and above 9 | # remove again once Qt raises the value to 10.14! 10 | QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.14 11 | QMAKE_IOS_DEPLOYMENT_TARGET = 12.0 12 | 13 | LOGGING_RULES = qt.jsonserializer.*.debug=true;qt.jsonserializer.metawriters.*.debug=false;qt.jsonserializer.serializer.extractor.debug=false 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017, Felix Barz 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /deploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "QtJsonSerializer", 3 | "description": "A library to perform generic seralization and deserialization of QObjects.", 4 | "modules": [ "QtJsonSerializer" ], 5 | "dependencies": [], 6 | "excludes": [], 7 | "license": { 8 | "name": "BSD-3-Clause", 9 | "path": "LICENSE" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /doc/doc.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = aux 2 | 3 | OTHER_FILES += Doxyfile \ 4 | makedoc.sh \ 5 | doxme.py \ 6 | ../README.md \ 7 | *.dox \ 8 | snippets/*.cpp \ 9 | images/* 10 | 11 | mkpath($$OUT_PWD/qtjsonserializer) 12 | !exists($$OUT_PWD/qtjsonserializer.qch):write_file($$OUT_PWD/qtjsonserializer.qch, __NOTHING) 13 | 14 | docTarget.target = doxygen 15 | docTarget.commands = $$PWD/makedoc.sh "$$PWD" "$$MODULE_VERSION" "$$[QT_INSTALL_BINS]" "$$[QT_INSTALL_HEADERS]" "$$[QT_INSTALL_DOCS]" 16 | QMAKE_EXTRA_TARGETS += docTarget 17 | 18 | docInst1.path = $$[QT_INSTALL_DOCS] 19 | docInst1.files = $$OUT_PWD/qtjsonserializer.qch 20 | docInst1.CONFIG += no_check_exist 21 | docInst2.path = $$[QT_INSTALL_DOCS] 22 | docInst2.files = $$OUT_PWD/qtjsonserializer 23 | INSTALLS += docInst1 docInst2 24 | 25 | DISTFILES += \ 26 | qjsontypeconverter.dox 27 | -------------------------------------------------------------------------------- /doc/doxme.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # $1 The readme to be transformed 3 | # $pwd: dest dir 4 | 5 | import sys 6 | 7 | def readFirst(line, out): 8 | if line[0:2] != "# ": 9 | raise ValueError("Expected first line to start with '# '") 10 | # skip the first line 11 | out.write("[TOC]\n\n") 12 | 13 | readCounter = 0 14 | def readMore(line, out): 15 | global readCounter 16 | if line[0:2] == "##": 17 | out.write(line[1:] + " {{#qtjsonserializer_readme_label_{}}}\n".format(readCounter)) 18 | readCounter += 1 19 | else: 20 | out.write(line + "\n") 21 | 22 | #read args 23 | readme = sys.argv[1] 24 | doxme = "./README.md" 25 | 26 | inFile = open(readme, "r") 27 | outFile = open(doxme, "w") 28 | 29 | isFirst = True 30 | for line in inFile: 31 | if isFirst: 32 | readFirst(line[:-1], outFile) 33 | isFirst = False 34 | else: 35 | readMore(line[:-1], outFile) 36 | 37 | inFile.close(); 38 | outFile.close(); 39 | -------------------------------------------------------------------------------- /doc/gh_header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | $projectname: $title 10 | $title 11 | 12 | 13 | 14 | $treeview 15 | $search 16 | $mathjax 17 | 18 | $extrastylesheet 19 | 20 | 21 |
22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 38 | 39 | 40 | 41 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 |
33 |
$projectname 34 |  $projectnumber 35 |
36 |
$projectbrief
37 |
42 |
$projectbrief
43 |
$searchbox
54 | 55 | 56 | 57 |
58 | 59 | 60 | -------------------------------------------------------------------------------- /doc/images/GitHub_Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/QtJsonSerializer/c078fe1f2435e92df476bbf3e61765e838e0ad08/doc/images/GitHub_Logo.png -------------------------------------------------------------------------------- /doc/makedoc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # $1: $$SRCDIR 3 | # $2: $$VERSION 4 | # $3: $$[QT_INSTALL_BINS] 5 | # $4: $$[QT_INSTALL_HEADERS] 6 | # $5: $$[QT_INSTALL_DOCS] 7 | # $pwd: dest dir 8 | set -e 9 | 10 | scriptDir=$(dirname "$0") 11 | destDir="$(pwd)" 12 | srcDir=$1 13 | version=$2 14 | verTag=${version//./} 15 | qtBins=$3 16 | qtHeaders=$4 17 | qtDocs=$5 18 | doxyTemplate="$srcDir/Doxyfile" 19 | doxyRes=Doxyfile.generated 20 | readme="$destDir/README.md" 21 | doxme="$scriptDir/doxme.py" 22 | 23 | python3 "$doxme" "$srcDir/../README.md" 24 | 25 | cat "$doxyTemplate" > $doxyRes 26 | echo "PROJECT_NUMBER = \"$version\"" >> $doxyRes 27 | echo "INPUT += \"$readme\"" >> $doxyRes 28 | echo "USE_MDFILE_AS_MAINPAGE = \"$readme\"" >> $doxyRes 29 | echo "OUTPUT_DIRECTORY = \"$destDir\"" >> $doxyRes 30 | echo "QHP_NAMESPACE = \"de.skycoder42.qtjsonserializer.$verTag\"" >> $doxyRes 31 | echo "QHP_CUST_FILTER_NAME = \"JsonSerializer $version\"" >> $doxyRes 32 | echo "QHP_CUST_FILTER_ATTRS = \"qtjsonserializer $version\"" >> $doxyRes 33 | echo "QHG_LOCATION = \"$qtBins/qhelpgenerator\"" >> $doxyRes 34 | echo "INCLUDE_PATH += \"$qtHeaders\"" >> $doxyRes 35 | echo "GENERATE_TAGFILE = \"$destDir/qtjsonserializer/qtjsonserializer.tags\"" >> $doxyRes 36 | if [ "$DOXY_STYLE" ]; then 37 | echo "HTML_STYLESHEET = \"$DOXY_STYLE\"" >> $doxyRes 38 | fi 39 | if [ "$DOXY_STYLE_EXTRA" ]; then 40 | echo "HTML_EXTRA_STYLESHEET = \"$DOXY_STYLE_EXTRA\"" >> $doxyRes 41 | fi 42 | 43 | for tagFile in $(find "$qtDocs" -name *.tags); do 44 | if [ $(basename "$tagFile") != "qtjsonserializer.tags" ]; then 45 | echo "TAGFILES += \"$tagFile=https://doc.qt.io/qt-5\"" >> $doxyRes 46 | fi 47 | done 48 | 49 | cd "$srcDir" 50 | doxygen "$destDir/$doxyRes" 51 | -------------------------------------------------------------------------------- /doc/metawriters.dox: -------------------------------------------------------------------------------- 1 | /*! 2 | @namespace QtJsonSerializer::MetaWriters 3 | 4 | @brief Contains the writer classes required to support serialization of generic containers 5 | 6 | Qt already provides read access to such containers via the QSequentialIterable and 7 | QAssociativeIterable classes. However, they do support creating or writing to such containers. 8 | 9 | Therefore, until [QTBUG-79170](https://bugreports.qt.io/browse/QTBUG-79170) was fixed, the 10 | writer classes are needed to perform this task. 11 | 12 | As long as you only work with Qt containers, you will never use these classes. However, if 13 | you plan on using custom or std containers, you must register them via the writers. 14 | */ 15 | 16 | /*! 17 | @class QtJsonSerializer::MetaWriters::SequentialWriter 18 | 19 | The sequential writer is used to provide write access to such containers. They must first be 20 | registered via `Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE` and then via 21 | SequentialWriter::registerWriter. For most containers, you can simply use the generic variant 22 | of this method. If you have containers that are not supported by the generic variant, extend 23 | the writer instead and use the non-generic variant of the method. 24 | 25 | @sa MetaWriters::SequentialWriterFactory, MetaWriters::AssociativeWriter 26 | */ 27 | 28 | /*! 29 | @fn QtJsonSerializer::MetaWriters::SequentialWriter::registerWriter() 30 | 31 | @tparam TContainer The container class to register the writer for 32 | @tparam TClass The value held by the container to register the writer for 33 | 34 | This methods assumes a type of the format `TContainer` exists. Furthermore, the 35 | container must provide the following methods: 36 | 37 | - `TReturn reserve(int)` 38 | - `TReturn append(TClass)` 39 | 40 | @sa SequentialWriter::getWriter 41 | */ 42 | 43 | /*! 44 | @fn QtJsonSerializer::MetaWriters::SequentialWriter::registerWriter(int, SequentialWriterFactory*) 45 | 46 | @param metaTypeId The type to register the writer for 47 | @param factory A factory to create writer instances for the given type 48 | 49 | Use this method if the generic one does not work for you. You have to implement the 50 | SequentialWriter and provide a SequentialWriterFactory that generates it. 51 | 52 | @sa SequentialWriter::getWriter, SequentialWriterFactory 53 | */ 54 | 55 | /*! 56 | @class QtJsonSerializer::MetaWriters::AssociativeWriter 57 | 58 | The associative writer is used to provide write access to such containers. They must first be 59 | registered via `Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE` and then via 60 | AssociativeWriter::registerWriter. For most containers, you can simply use the generic variant 61 | of this method. If you have containers that are not supported by the generic variant, extend 62 | the writer instead and use the non-generic variant of the method. 63 | 64 | @sa MetaWriters::AssociativeWriterFactory, MetaWriters::SequentialWriter 65 | */ 66 | 67 | /*! 68 | @fn QtJsonSerializer::MetaWriters::AssociativeWriter::registerWriter() 69 | 70 | @tparam TContainer The container class to register the writer for 71 | @tparam TKey The type of keys used to access elements of the container 72 | @tparam TValue The type of elements held by the container 73 | 74 | This methods assumes a type of the format `TContainer` exists. Furthermore, the 75 | container must provide the following method: 76 | 77 | - `TReturn insert(TKey, TValue)` 78 | 79 | @sa AssociativeWriter::getWriter 80 | */ 81 | 82 | /*! 83 | @fn QtJsonSerializer::MetaWriters::AssociativeWriter::registerWriter(int, AssociativeWriterFactory*) 84 | 85 | @param metaTypeId The type to register the writer for 86 | @param factory A factory to create writer instances for the given type 87 | 88 | Use this method if the generic one does not work for you. You have to implement the 89 | AssociativeWriter and provide a AssociativeWriterFactory that generates it. 90 | 91 | @sa AssociativeWriter::getWriter, AssociativeWriterFactory 92 | */ 93 | -------------------------------------------------------------------------------- /doc/qtjsonserializer.dox: -------------------------------------------------------------------------------- 1 | /*! 2 | @namespace QtJsonSerializer 3 | 4 | @brief The QtJsonSerializer namespace holds all classes of the module 5 | 6 | The primary two classes you are going to use are 7 | - JsonSerializer 8 | - CborSerializer 9 | 10 | Others are mostly helperclasses or only relevant when creating your own converters 11 | */ 12 | 13 | /*! 14 | @fn QtJsonSerializer::registerTypes() 15 | 16 | This method is called automatically by the library when loaded, to register converters for all 17 | types supported by default. When build the library as a static library, you have to call it 18 | yourself instead. 19 | 20 | The types and converters that are registerd with this method are: 21 | 22 | The following types are already registered by default: 23 | 24 | Type | List-Converters | Map-Converters | Set-Converters 25 | --------------------|-------------------|-------------------|---------------- 26 | bool | yes | yes | yes 27 | char | yes | yes | yes 28 | signed char | yes | yes | yes 29 | unsigned char | yes | yes | yes 30 | short | yes | yes | yes 31 | unsigned short | yes | yes | yes 32 | int | yes | yes | yes 33 | unsigned int | yes | yes | yes 34 | long | yes | yes | yes 35 | unsigned long | yes | yes | yes 36 | long long | yes | yes | yes 37 | unsigned long long | yes | yes | yes 38 | float | yes | yes | yes 39 | double | yes | yes | yes 40 | QObject * | yes | yes | yes 41 | QChar | yes | yes | yes 42 | QString | yes | yes | yes 43 | QDate | yes | yes | yes 44 | QTime | yes | yes | yes 45 | QDateTime | yes | yes | yes 46 | QUrl | yes | yes | yes 47 | QUuid | yes | yes | yes 48 | QCborValue | yes | yes | yes 49 | QCborMap | yes | yes | yes 50 | QCborArray | yes | yes | yes 51 | QJsonValue | yes | yes | yes 52 | QJsonObject | yes | yes | yes 53 | QJsonArray | yes | yes | yes 54 | QMimeType | yes | yes | yes 55 | QVersionNumber | yes | yes | yes 56 | QLocale | yes | yes | yes5 57 | QRegularExpression | yes | yes | yes 58 | QSize | yes | no | no 59 | QPoint | yes | no | no 60 | QLine | yes | no | no 61 | QRect | yes | no | no 62 | QSizeF | yes | no | no 63 | QPointF | yes | no | no 64 | QLineF | yes | no | no 65 | QRectF | yes | no | no 66 | QByteArray | no | yes | yes 67 | 68 | @sa SerializerBase::registerListConverters, SerializerBase::registerSetConverters, 69 | SerializerBase::registerMapConverters, SerializerBase::registerBasicConverters, 70 | SerializerBase::registerPointerConverters, SerializerBase::registerPairConverters, 71 | SerializerBase::registerTupleConverters, SerializerBase::registerOptionalConverters, 72 | SerializerBase::registerVariantConverters 73 | */ 74 | -------------------------------------------------------------------------------- /doc/typeextractor.dox: -------------------------------------------------------------------------------- 1 | /*! 2 | @class QtJsonSerializer::TypeExtractor 3 | 4 | @note This class is only relevant if you plan on creating your own TypeConverter 5 | 6 | This interface is used by custom TypeConverter classes to get data from a generic container in 7 | a non-generic fashion. For example, an extractor for `QPair` allows the converters to 8 | access the `first` and `second` elements of the pair as QVariant, without having to know the 9 | actual types of T1 and T2. 10 | 11 | When creating extractors, they are typlically generic themselves, as a generic extractor is 12 | registered to provide the non generic API. The following code is a basic sample for a QPair 13 | converter. Further details about the methods can be found here. 14 | 15 | @code{.cpp} 16 | 17 | template 18 | class QPairExtractor final : public QtJsonSerializer::TypeExtractor 19 | { 20 | public: 21 | using Type = QPair; 22 | 23 | QByteArray baseType() const final { 24 | return QByteArrayLiteral("QPair"); 25 | } 26 | 27 | QList subtypes() const final { 28 | return {qMetaTypeId(), qMetaTypeId()}; 29 | } 30 | 31 | QVariant extract(const QVariant &value, int index) const final { 32 | const auto vPair = value.value(); 33 | switch (index) { 34 | case 0: 35 | return QVariant::fromValue(vPair.first); 36 | case 1: 37 | return QVariant::fromValue(vPair.second); 38 | default: 39 | return {}; 40 | } 41 | } 42 | 43 | void emplace(QVariant &target, const QVariant &value, int index) const final { 44 | Q_ASSERT(target.userType() == qMetaTypeId()); 45 | const auto vPair = reinterpret_cast(target.data()); 46 | switch (index) { 47 | case 0: 48 | vPair->first = value.value(); 49 | break; 50 | case 1: 51 | vPair->second = value.value(); 52 | break; 53 | default: 54 | break; 55 | } 56 | } 57 | }; 58 | @endcode 59 | 60 | @sa TypeConverter, TypeConverter::SerializationHelper, 61 | TypeConverter::SerializationHelper::extractor, SerializerBase::registerExtractor 62 | */ 63 | 64 | /*! 65 | @fn QtJsonSerializer::TypeExtractor::baseType 66 | 67 | @returns The base type identifier 68 | 69 | The base type should be a simple string representing the generic type this extractor provides. 70 | It must be the same for any generic instance created, independent of the generic type, i.e. a 71 | `QPair` extractor could for example return `QPair` or `pair` etc. 72 | 73 | When creating a converter that uses this extractor, you can easily check if your converter 74 | supports a certain type by checking this base type: 75 | 76 | @code{.cpp} 77 | bool MyConverter::canConvert(int metaTypeId) const { 78 | const auto extractor = helper()->extractor(metaTypeId); 79 | return extractor && extractor->baseType() == "QPair"; 80 | } 81 | @endcode 82 | 83 | @sa TypeConverter::canConvert 84 | */ 85 | 86 | /*! 87 | @fn QtJsonSerializer::TypeExtractor::subtypes 88 | 89 | @returns The ordered list of subtypes 90 | 91 | This list must contain the type ids of all elements contained in the container, in the same 92 | order as they are accessed by extract() and emplace(). For example, for a `QPair`, the 93 | type ids would be `qMetaTypeId()` and `qMetaTypeId()`. 94 | 95 | You can use these in your custom converter to pass a type id to the 96 | TypeConverter::SerializationHelper::serializeSubtype and 97 | TypeConverter::SerializationHelper::serializeSubtype methods when handling elements of the 98 | contained data. 99 | */ 100 | 101 | /*! 102 | @fn QtJsonSerializer::TypeExtractor::extract 103 | 104 | @param value The data to extract subdata from 105 | @param index An optional index, if the value holds more than one subvalue 106 | @returns The subvalue extract from value 107 | 108 | Use this method in your custom converters TypeConverter::serialize to get data out of a generic 109 | container. If a value is supported by the extractor, you can get the subvalues via this method. 110 | For simple containers (such as std::optional), you can ignore the index, as there is only one 111 | value. For more complex types, such as `QPair`, use the index to access the elements. 112 | 113 | The type of each value returned by a certain index will match the type at the same index from 114 | subtypes(). The subtypes list will also tell you, how many elements there are in the generic 115 | type. 116 | 117 | To, for example, access the value of `second` of a `QPair` and then serialize it, the 118 | following code can be used 119 | 120 | @code{.cpp} 121 | const auto extractor = helper()->extractor(metaTypeId); 122 | const auto tIds = extractor->subtypes(); 123 | const auto subData = extractor->extract(data, 1); 124 | const auto serData = helper()->serializeSubtype(tIds[1], subData); 125 | @endcode 126 | 127 | @sa TypeConverter::serialize, TypeExtractor::subtypes 128 | */ 129 | 130 | /*! 131 | @fn QtJsonSerializer::TypeExtractor::emplace 132 | 133 | @param target The data to emplace the subdata into 134 | @param value The subvalue to emplace into the target 135 | @param index An optional index, if the value holds more than one subvalue 136 | 137 | Use this method in your custom converters TypeConverter::deserialize to get data into a 138 | generic container. If a value is supported by the extractor, you can set the subvalues via this 139 | method. For simple containers (such as std::optional), you can ignore the index, as there is 140 | only one value. For more complex types, such as `QPair`, use the index to access the 141 | elements. 142 | 143 | The type of each value expected by a certain index will match the type at the same index from 144 | subtypes(). The subtypes list will also tell you, how many elements there are in the generic 145 | type. 146 | 147 | To, for example, emplace the value of `first` of a `QPair` after deserialize it, the 148 | following code can be used 149 | 150 | @code{.cpp} 151 | QVariant pairData{propertyType, nullptr}; 152 | const auto extractor = helper()->extractor(metaTypeId); 153 | const auto tIds = extractor->subtypes(); 154 | const auto deserData = helper()->deserializeSubtype(tIds[0], data); 155 | extractor->emplace(pairData, deserData, 0); 156 | @endcode 157 | 158 | @sa TypeConverter::deserialize, TypeExtractor::subtypes 159 | */ 160 | -------------------------------------------------------------------------------- /examples/examples.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS = jsonserializer 4 | -------------------------------------------------------------------------------- /examples/jsonserializer/Sample/Sample.pro: -------------------------------------------------------------------------------- 1 | QT = core jsonserializer 2 | 3 | CONFIG += console 4 | CONFIG -= app_bundle 5 | 6 | TARGET = Sample 7 | 8 | HEADERS += \ 9 | sampleobject.h \ 10 | samplegadget.h 11 | 12 | SOURCES += main.cpp \ 13 | sampleobject.cpp \ 14 | samplegadget.cpp 15 | 16 | target.path = $$[QT_INSTALL_EXAMPLES]/jsonserializer/$$TARGET 17 | !install_ok: INSTALLS += target 18 | -------------------------------------------------------------------------------- /examples/jsonserializer/Sample/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace QtJsonSerializer; 5 | 6 | #include "sampleobject.h" 7 | 8 | #define JSON_PRINT(x) QJsonDocument(x).toJson().constData() 9 | 10 | int main(int argc, char *argv[]) 11 | { 12 | QCoreApplication a(argc, argv); 13 | 14 | //to actually work polymorphic, we must register: 15 | qRegisterMetaType(); 16 | 17 | JsonSerializer serializer; 18 | 19 | qDebug() << "Serializing SampleGadget:"; 20 | SampleGadget gadget; 21 | gadget.base = {42, 13}; 22 | gadget.rawData = QJsonObject({ 23 | {QStringLiteral("someData"), false} 24 | }); 25 | auto json = serializer.serialize(gadget); 26 | qDebug() << JSON_PRINT(json); 27 | 28 | qDebug() << "\nAnd deserializing data back:"; 29 | auto deser = serializer.deserialize(json); 30 | qDebug() << "base:" << deser.base; 31 | qDebug() << "rawData:" << JSON_PRINT(deser.rawData); 32 | 33 | qDebug() << "\nNow the test object, with the previous gadget as child:"; 34 | auto obj = new SampleObject(qApp); 35 | obj->id = 10; 36 | obj->title = QStringLiteral("Example"); 37 | obj->flags = SampleObject::ValueA | SampleObject::ValueB; 38 | obj->scores = {0.0, 6.66, 47.11}; 39 | obj->secret = QStringLiteral("Very secret string, not serialized"); 40 | obj->gadget = gadget; 41 | json = serializer.serialize(obj); 42 | qDebug() << JSON_PRINT(json); 43 | 44 | qDebug() << "\nAnd serialized with string flags and a child"; 45 | serializer.setEnumAsString(true); 46 | obj->child = new SampleObject(obj); 47 | json = serializer.serialize(obj); 48 | qDebug() << JSON_PRINT(json); 49 | 50 | qDebug() << "\nSerialize a polymorphic object type now:"; 51 | obj = new SuperSampleObject(qApp); 52 | obj->id = 55; 53 | obj->title = QStringLiteral("Super Example"); 54 | json = serializer.serialize(obj); 55 | qDebug() << JSON_PRINT(json); 56 | 57 | qDebug() << "\nFinally, deserialize the polymorphic type again"; 58 | obj = serializer.deserialize(json);//serialize as SampleObject 59 | qDebug() << "SampleObject pointer to:" << obj; 60 | 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /examples/jsonserializer/Sample/samplegadget.cpp: -------------------------------------------------------------------------------- 1 | #include "samplegadget.h" 2 | 3 | SampleGadget::SampleGadget() : 4 | base(), 5 | rawData() 6 | {} 7 | 8 | bool SampleGadget::operator !=(const SampleGadget &other) const 9 | { 10 | return base != other.base || 11 | rawData != other.rawData; 12 | } 13 | -------------------------------------------------------------------------------- /examples/jsonserializer/Sample/samplegadget.h: -------------------------------------------------------------------------------- 1 | #ifndef SAMPLEGADGET_H 2 | #define SAMPLEGADGET_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class SampleGadget 9 | { 10 | Q_GADGET 11 | 12 | Q_PROPERTY(QPoint base MEMBER base) 13 | Q_PROPERTY(QJsonObject rawData MEMBER rawData) 14 | 15 | public: 16 | SampleGadget(); 17 | 18 | QPoint base; 19 | QJsonObject rawData; 20 | 21 | bool operator !=(const SampleGadget &other) const; 22 | }; 23 | 24 | Q_DECLARE_METATYPE(SampleGadget) 25 | 26 | #endif // SAMPLEGADGET_H 27 | -------------------------------------------------------------------------------- /examples/jsonserializer/Sample/sampleobject.cpp: -------------------------------------------------------------------------------- 1 | #include "sampleobject.h" 2 | 3 | SampleObject::SampleObject(QObject *parent) : 4 | QObject{parent} 5 | {} 6 | 7 | SampleObject::SuperFlags SampleObject::getFlags() const 8 | { 9 | return flags; 10 | } 11 | 12 | void SampleObject::setFlags(SuperFlags value) 13 | { 14 | flags = value; 15 | } 16 | 17 | SuperSampleObject::SuperSampleObject(QObject *parent) : 18 | SampleObject(parent), 19 | working(true) 20 | {} 21 | -------------------------------------------------------------------------------- /examples/jsonserializer/Sample/sampleobject.h: -------------------------------------------------------------------------------- 1 | #ifndef SAMPLEOBJECT_H 2 | #define SAMPLEOBJECT_H 3 | 4 | #include 5 | #include "samplegadget.h" 6 | 7 | class SampleObject : public QObject 8 | { 9 | Q_OBJECT 10 | 11 | Q_PROPERTY(int id MEMBER id) 12 | Q_PROPERTY(QString title MEMBER title) 13 | Q_PROPERTY(SuperFlags flags READ getFlags WRITE setFlags) 14 | Q_PROPERTY(QList scores MEMBER scores) 15 | Q_PROPERTY(SampleObject* child MEMBER child) 16 | Q_PROPERTY(SampleGadget gadget MEMBER gadget) 17 | Q_PROPERTY(QString secret MEMBER secret STORED false) 18 | 19 | public: 20 | enum SuperFlag { 21 | ValueA = 0x01, 22 | ValueB = 0x02, 23 | ValueC = 0x04 24 | }; 25 | Q_DECLARE_FLAGS(SuperFlags, SuperFlag) 26 | Q_FLAG(SuperFlags) 27 | 28 | Q_INVOKABLE SampleObject(QObject *parent = nullptr); 29 | 30 | int id = 0; 31 | QString title; 32 | SuperFlags flags = nullptr; 33 | QList scores; 34 | SampleObject *child = nullptr; 35 | SampleGadget gadget; 36 | QString secret; 37 | 38 | private: 39 | SuperFlags getFlags() const; 40 | void setFlags(SampleObject::SuperFlags value); 41 | }; 42 | 43 | class SuperSampleObject : public SampleObject 44 | { 45 | Q_OBJECT 46 | Q_CLASSINFO("polymorphic", "true") 47 | 48 | Q_PROPERTY(bool working MEMBER working) 49 | 50 | public: 51 | Q_INVOKABLE SuperSampleObject(QObject *parent = nullptr); 52 | 53 | bool working; 54 | }; 55 | 56 | Q_DECLARE_METATYPE(SampleObject*) 57 | Q_DECLARE_METATYPE(SuperSampleObject*) 58 | Q_DECLARE_OPERATORS_FOR_FLAGS(SampleObject::SuperFlags) 59 | 60 | #endif // SAMPLEOBJECT_H 61 | -------------------------------------------------------------------------------- /examples/jsonserializer/jsonserializer.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | QT_FOR_CONFIG += core 3 | 4 | SUBDIRS += \ 5 | Sample 6 | -------------------------------------------------------------------------------- /qtjsonserializer.pro: -------------------------------------------------------------------------------- 1 | load(qt_parts) 2 | 3 | SUBDIRS += doc 4 | 5 | doxygen.target = doxygen 6 | doxygen.CONFIG += recursive 7 | doxygen.recurse_target = doxygen 8 | doxygen.recurse += doc 9 | QMAKE_EXTRA_TARGETS += doxygen lrelease 10 | 11 | runtests.target = run-tests 12 | runtests.CONFIG = recursive 13 | runtests.recurse_target = run-tests 14 | runtests.recurse += sub_tests sub_src 15 | QMAKE_EXTRA_TARGETS += runtests 16 | 17 | DISTFILES += .qmake.conf \ 18 | sync.profile 19 | -------------------------------------------------------------------------------- /src/jsonserializer/cborserializer_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_CBORSERIALIZER_P_H 2 | #define QTJSONSERIALIZER_CBORSERIALIZER_P_H 3 | 4 | #include "cborserializer.h" 5 | #include "serializerbase_p.h" 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace QtJsonSerializer { 13 | 14 | class Q_JSONSERIALIZER_EXPORT CborSerializerPrivate : public SerializerBasePrivate 15 | { 16 | Q_DECLARE_PUBLIC(CborSerializer) 17 | 18 | public: 19 | using ExtendedTags = CborSerializer::ExtendedTags; 20 | using CustomTags = CborSerializer::CustomTags; 21 | 22 | mutable QReadWriteLock typeTagsLock {}; 23 | QHash typeTags {}; 24 | bool handleSpecialNumbers = false; 25 | 26 | QVariant deserializeCborValue(int propertyType, const QCborValue &value) const override; 27 | 28 | QVariant deserializePositiveBignum(const QByteArray &data) const; 29 | QVariant deserializeNegativeBignum(const QByteArray &data) const; 30 | qreal deserializeDecimal(const QCborArray &data) const; 31 | qreal deserializeBigfloat(const QCborArray &data) const; 32 | qreal deserializeRationaleNumber(const QCborArray &data) const; 33 | }; 34 | 35 | Q_DECLARE_LOGGING_CATEGORY(logCbor) 36 | 37 | } 38 | 39 | #endif // QTJSONSERIALIZER_CBORSERIALIZER_P_H 40 | -------------------------------------------------------------------------------- /src/jsonserializer/exception.cpp: -------------------------------------------------------------------------------- 1 | #include "exception.h" 2 | #include "exception_p.h" 3 | #include "exceptioncontext_p.h" 4 | using namespace QtJsonSerializer; 5 | 6 | Exception::Exception(const QByteArray &what) : 7 | d{new ExceptionPrivate{what}} 8 | {} 9 | 10 | const char *Exception::what() const noexcept 11 | { 12 | return d->what.constData(); 13 | } 14 | 15 | QByteArray Exception::message() const 16 | { 17 | return d->message; 18 | } 19 | 20 | Exception::PropertyTrace Exception::propertyTrace() const 21 | { 22 | return d->trace; 23 | } 24 | 25 | void Exception::raise() const 26 | { 27 | throw *this; 28 | } 29 | 30 | ExceptionBase *Exception::clone() const 31 | { 32 | auto exc = new Exception(QByteArray()); 33 | exc->d = d; 34 | return exc; 35 | } 36 | 37 | SerializationException::SerializationException(const QByteArray &what) : 38 | Exception{"Failed to serialize with error: " + what} 39 | {} 40 | 41 | void SerializationException::raise() const 42 | { 43 | throw *this; 44 | } 45 | 46 | ExceptionBase *SerializationException::clone() const 47 | { 48 | auto exc = new SerializationException(QByteArray()); 49 | exc->d = d; 50 | return exc; 51 | } 52 | 53 | DeserializationException::DeserializationException(const QByteArray &what) : 54 | Exception{"Failed to deserialize with error: " + what} 55 | {} 56 | 57 | void DeserializationException::raise() const 58 | { 59 | throw *this; 60 | } 61 | 62 | ExceptionBase *DeserializationException::clone() const 63 | { 64 | auto exc = new DeserializationException(QByteArray()); 65 | exc->d = d; 66 | return exc; 67 | } 68 | 69 | 70 | 71 | ExceptionPrivate::ExceptionPrivate(QByteArray msg) : 72 | message{std::move(msg)}, 73 | trace{ExceptionContext::currentContext()} 74 | { 75 | //construct the whole trace 76 | what = "what: " + message + "\nProperty Trace:"; 77 | if(trace.isEmpty()) 78 | what += " "; 79 | else { 80 | for(const auto &p : qAsConst(trace)) 81 | what += "\n\t" + p.first + " (Type: " + p.second + ")"; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/jsonserializer/exception.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_EXCEPTION_H 2 | #define QTJSONSERIALIZER_EXCEPTION_H 3 | 4 | #include "QtJsonSerializer/qtjsonserializer_global.h" 5 | #include 6 | #include 7 | #include 8 | 9 | #if !defined(QT_NO_EXCEPTIONS) && QT_CONFIG(future) 10 | #include 11 | namespace QtJsonSerializer { 12 | //! The exception base class to use for this module 13 | using ExceptionBase = QException; 14 | } 15 | #else 16 | #include 17 | namespace QtJsonSerializer { 18 | //! The exception base class to use for this module 19 | using ExceptionBase = std::exception; 20 | } 21 | #endif 22 | 23 | namespace QtJsonSerializer { 24 | 25 | class ExceptionPrivate; 26 | //! Exception thrown by QJsonSerializer if something goes wrong 27 | class Q_JSONSERIALIZER_EXPORT Exception : public ExceptionBase 28 | { 29 | public: 30 | //! The type of a stack of a property trace (name, type) 31 | using PropertyTrace = QStack>; 32 | 33 | //! Constructor with error message 34 | Exception(const QByteArray &what); 35 | 36 | //! @inherit{std::exception::what} 37 | const char *what() const noexcept final; 38 | 39 | //! Returns the error message, without the property trace 40 | QByteArray message() const; 41 | //! Returns the property trace 42 | PropertyTrace propertyTrace() const; 43 | 44 | //! @inherit{QException::raise} 45 | virtual void raise() const override; 46 | //! @inherit{QException::clone} 47 | virtual ExceptionBase *clone() const override; 48 | 49 | protected: 50 | //! @private 51 | QSharedPointer d; 52 | }; 53 | 54 | //! Exception thrown by the serializers if something goes wrong while serializing 55 | class Q_JSONSERIALIZER_EXPORT SerializationException : public Exception 56 | { 57 | public: 58 | //! Constructor with error message 59 | SerializationException(const QByteArray &what); 60 | 61 | void raise() const override; 62 | ExceptionBase *clone() const override; 63 | }; 64 | 65 | //! Exception thrown by the serializers if something goes wrong while deserializing 66 | class Q_JSONSERIALIZER_EXPORT DeserializationException : public Exception 67 | { 68 | public: 69 | //! Constructor with error message 70 | DeserializationException(const QByteArray &what); 71 | 72 | void raise() const override; 73 | ExceptionBase *clone() const override; 74 | }; 75 | 76 | } 77 | 78 | #endif // QTJSONSERIALIZER_EXCEPTION_H 79 | -------------------------------------------------------------------------------- /src/jsonserializer/exception_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_EXCEPTION_P_H 2 | #define QTJSONSERIALIZER_EXCEPTION_P_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "exception.h" 6 | 7 | namespace QtJsonSerializer { 8 | 9 | class Q_JSONSERIALIZER_EXPORT ExceptionPrivate 10 | { 11 | Q_DISABLE_COPY(ExceptionPrivate) 12 | public: 13 | ExceptionPrivate(QByteArray message); 14 | 15 | QByteArray message; 16 | Exception::PropertyTrace trace; 17 | QByteArray what; 18 | }; 19 | 20 | } 21 | 22 | #endif // QTJSONSERIALIZER_EXCEPTION_P_H 23 | -------------------------------------------------------------------------------- /src/jsonserializer/exceptioncontext.cpp: -------------------------------------------------------------------------------- 1 | #include "exceptioncontext_p.h" 2 | using namespace QtJsonSerializer; 3 | 4 | Q_LOGGING_CATEGORY(QtJsonSerializer::logExceptCtx, "qt.jsonserializer.private.exceptioncontext") 5 | 6 | QThreadStorage ExceptionContext::contextStore; 7 | 8 | ExceptionContext::ExceptionContext(const QMetaProperty &property) 9 | { 10 | contextStore.localData().push({ 11 | property.name(), 12 | property.isEnumType() ? 13 | property.enumerator().name() : 14 | property.typeName() 15 | }); 16 | } 17 | 18 | ExceptionContext::ExceptionContext(int propertyType, const QByteArray &hint) 19 | { 20 | contextStore.localData().push({ 21 | hint.isNull() ? QByteArray("") : hint, 22 | QMetaTypeName(propertyType) 23 | }); 24 | } 25 | 26 | ExceptionContext::~ExceptionContext() 27 | { 28 | auto &context = contextStore.localData(); 29 | if (context.isEmpty()) 30 | qCWarning(logExceptCtx) << "Corrupted context store"; 31 | else 32 | context.pop(); 33 | } 34 | 35 | SerializationException::PropertyTrace ExceptionContext::currentContext() 36 | { 37 | return contextStore.localData(); 38 | } 39 | 40 | int ExceptionContext::currentDepth() 41 | { 42 | return contextStore.localData().size(); 43 | } 44 | -------------------------------------------------------------------------------- /src/jsonserializer/exceptioncontext_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_EXCEPTIONCONTEXT_P_H 2 | #define QTJSONSERIALIZER_EXCEPTIONCONTEXT_P_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "exception.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace QtJsonSerializer { 12 | 13 | class Q_JSONSERIALIZER_EXPORT ExceptionContext 14 | { 15 | public: 16 | ExceptionContext(const QMetaProperty &property); 17 | ExceptionContext(int propertyType, const QByteArray &hint); 18 | ~ExceptionContext(); 19 | 20 | static SerializationException::PropertyTrace currentContext(); 21 | static int currentDepth(); 22 | 23 | private: 24 | static QThreadStorage contextStore; 25 | }; 26 | 27 | Q_DECLARE_LOGGING_CATEGORY(logExceptCtx) 28 | 29 | } 30 | 31 | #endif // QTJSONSERIALIZER_EXCEPTIONCONTEXT_P_H 32 | -------------------------------------------------------------------------------- /src/jsonserializer/jsonserializer.cpp: -------------------------------------------------------------------------------- 1 | #include "jsonserializer.h" 2 | #include "jsonserializer_p.h" 3 | 4 | #include 5 | using namespace QtJsonSerializer; 6 | 7 | JsonSerializer::JsonSerializer(QObject *parent) : 8 | SerializerBase{*new JsonSerializerPrivate{}, parent} 9 | {} 10 | 11 | QJsonValue JsonSerializer::serialize(const QVariant &data) const 12 | { 13 | return serializeVariant(data.userType(), data).toJsonValue(); 14 | } 15 | 16 | void JsonSerializer::serializeTo(QIODevice *device, const QVariant &data, QJsonDocument::JsonFormat format) const 17 | { 18 | if (!device->isOpen() || !device->isWritable()) 19 | throw SerializationException{"QIODevice must be open and writable!"}; 20 | QJsonDocument doc; 21 | const auto jData = serialize(data); 22 | if (jData.isArray()) 23 | doc = QJsonDocument{jData.toArray()}; 24 | else if (jData.isObject()) 25 | doc = QJsonDocument{jData.toObject()}; 26 | else 27 | throw SerializationException{"Only objects or arrays can be written to a device!"}; 28 | device->write(doc.toJson(format)); 29 | } 30 | 31 | QByteArray JsonSerializer::serializeTo(const QVariant &data, QJsonDocument::JsonFormat format) const 32 | { 33 | QBuffer buffer; 34 | if (!buffer.open(QIODevice::WriteOnly)) 35 | throw SerializationException{"Failed to write to bytearray buffer with error: " + buffer.errorString().toUtf8()}; 36 | serializeTo(&buffer, data, format); 37 | buffer.close(); 38 | return buffer.data(); 39 | } 40 | 41 | QVariant JsonSerializer::deserialize(const QJsonValue &json, int metaTypeId, QObject *parent) const 42 | { 43 | return deserializeVariant(metaTypeId, QCborValue::fromJsonValue(json), parent); 44 | } 45 | 46 | QVariant JsonSerializer::deserializeFrom(QIODevice *device, int metaTypeId, QObject *parent) const 47 | { 48 | if (!device->isOpen() || !device->isReadable()) 49 | throw DeserializationException{"QIODevice must be open and readable!"}; 50 | QJsonParseError error; 51 | auto doc = QJsonDocument::fromJson(device->readAll(), &error); 52 | if (error.error != QJsonParseError::NoError) 53 | throw DeserializationException{"Failed to read file as JSON with error: " + error.errorString().toUtf8()}; 54 | if (doc.isArray()) 55 | return deserialize(doc.array(), metaTypeId, parent); 56 | else if (doc.isObject()) 57 | return deserialize(doc.object(), metaTypeId, parent); 58 | else if (doc.isNull()) 59 | return deserialize(QJsonValue::Null, metaTypeId, parent); 60 | else 61 | return QVariant{}; 62 | } 63 | 64 | QVariant JsonSerializer::deserializeFrom(const QByteArray &data, int metaTypeId, QObject *parent) const 65 | { 66 | QBuffer buffer(const_cast(&data)); 67 | if (!buffer.open(QIODevice::ReadOnly)) 68 | throw DeserializationException{"Failed to read from bytearray buffer with error: " + buffer.errorString().toUtf8()}; 69 | auto res = deserializeFrom(&buffer, metaTypeId, parent); 70 | buffer.close(); 71 | return res; 72 | } 73 | 74 | JsonSerializer::ByteArrayFormat JsonSerializer::byteArrayFormat() const 75 | { 76 | Q_D(const JsonSerializer); 77 | return d->byteArrayFormat; 78 | } 79 | 80 | bool JsonSerializer::validateBase64() const 81 | { 82 | Q_D(const JsonSerializer); 83 | return d->validateBase64; 84 | } 85 | 86 | std::variant JsonSerializer::serializeGeneric(const QVariant &value) const 87 | { 88 | return serialize(value); 89 | } 90 | 91 | QVariant JsonSerializer::deserializeGeneric(const std::variant &value, int metaTypeId, QObject *parent) const 92 | { 93 | return deserialize(std::get(value), metaTypeId, parent); 94 | } 95 | 96 | void JsonSerializer::setByteArrayFormat(JsonSerializer::ByteArrayFormat byteArrayFormat) 97 | { 98 | Q_D(JsonSerializer); 99 | if(d->byteArrayFormat == byteArrayFormat) 100 | return; 101 | 102 | d->byteArrayFormat = byteArrayFormat; 103 | emit byteArrayFormatChanged(d->byteArrayFormat, {}); 104 | } 105 | 106 | void JsonSerializer::setValidateBase64(bool validateBase64) 107 | { 108 | Q_D(JsonSerializer); 109 | if(d->validateBase64 == validateBase64) 110 | return; 111 | 112 | d->validateBase64 = validateBase64; 113 | emit validateBase64Changed(d->validateBase64, {}); 114 | } 115 | 116 | bool JsonSerializer::jsonMode() const 117 | { 118 | return true; 119 | } 120 | 121 | QCborTag JsonSerializer::typeTag(int metaTypeId) const 122 | { 123 | Q_D(const JsonSerializer); 124 | if (metaTypeId == QMetaType::QByteArray) { 125 | switch (d->byteArrayFormat) { 126 | case ByteArrayFormat::Base64: 127 | return static_cast(QCborKnownTags::ExpectedBase64); 128 | case ByteArrayFormat::Base64url: 129 | return static_cast(QCborKnownTags::ExpectedBase64url); 130 | case ByteArrayFormat::Base16: 131 | return static_cast(QCborKnownTags::ExpectedBase16); 132 | default: 133 | Q_UNREACHABLE(); 134 | } 135 | } else 136 | return TypeConverter::NoTag; 137 | } 138 | 139 | QList JsonSerializer::typesForTag(QCborTag tag) const 140 | { 141 | Q_UNUSED(tag) 142 | return {}; 143 | } 144 | -------------------------------------------------------------------------------- /src/jsonserializer/jsonserializer.pro: -------------------------------------------------------------------------------- 1 | TARGET = QtJsonSerializer 2 | 3 | QT = core core-private 4 | 5 | HEADERS += \ 6 | cborserializer.h \ 7 | cborserializer_p.h \ 8 | exception.h \ 9 | exception_p.h \ 10 | exceptioncontext_p.h \ 11 | jsonserializer.h \ 12 | jsonserializer_p.h \ 13 | metawriters.h \ 14 | metawriters_p.h \ 15 | qtjsonserializer_global.h \ 16 | qtjsonserializer_helpertypes.h \ 17 | serializerbase.h \ 18 | serializerbase_p.h \ 19 | typeconverter.h \ 20 | typeextractors.h 21 | 22 | SOURCES += \ 23 | cborserializer.cpp \ 24 | exception.cpp \ 25 | exceptioncontext.cpp \ 26 | jsonserializer.cpp \ 27 | metawriters.cpp \ 28 | serializerbase.cpp \ 29 | typeconverter.cpp 30 | 31 | include(typeconverters/typeconverters.pri) 32 | 33 | no_register_json_converters: DEFINES += NO_REGISTER_JSON_CONVERTERS 34 | else: include(qjsonreggen.pri) 35 | 36 | load(qt_module) 37 | 38 | win32 { 39 | QMAKE_TARGET_COMPANY = "Skycoder42" 40 | QMAKE_TARGET_PRODUCT = "QtJsonSerializer" 41 | QMAKE_TARGET_COPYRIGHT = "Felix Barz" 42 | } else:mac { 43 | QMAKE_TARGET_BUNDLE_PREFIX = "de.skycoder42." 44 | } 45 | 46 | DISTFILES += \ 47 | typesplit.pri 48 | -------------------------------------------------------------------------------- /src/jsonserializer/jsonserializer_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_JSONSERIALIZER_P_H 2 | #define QTJSONSERIALIZER_JSONSERIALIZER_P_H 3 | 4 | #include "jsonserializer.h" 5 | #include "serializerbase_p.h" 6 | 7 | namespace QtJsonSerializer { 8 | 9 | class Q_JSONSERIALIZER_EXPORT JsonSerializerPrivate : public SerializerBasePrivate 10 | { 11 | Q_DECLARE_PUBLIC(JsonSerializer) 12 | 13 | public: 14 | using ByteArrayFormat = JsonSerializer::ByteArrayFormat; 15 | ByteArrayFormat byteArrayFormat = ByteArrayFormat::Base64; 16 | bool validateBase64 = true; 17 | }; 18 | 19 | } 20 | 21 | #endif // QTJSONSERIALIZER_JSONSERIALIZER_P_H 22 | -------------------------------------------------------------------------------- /src/jsonserializer/metawriters_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_METAWRITERS_P_H 2 | #define QTJSONSERIALIZER_METAWRITERS_P_H 3 | 4 | #include "metawriters.h" 5 | 6 | #include 7 | 8 | namespace QtJsonSerializer::MetaWriters { 9 | 10 | class MetaWritersPrivate 11 | { 12 | public: 13 | static QReadWriteLock sequenceLock; 14 | static QHash sequenceFactories; 15 | static QHash sequenceInfoCache; 16 | 17 | static QReadWriteLock associationLock; 18 | static QHash associationFactories; 19 | static QHash associationInfoCache; 20 | 21 | static SequentialWriter::SequenceInfo tryParseSequenceInfo(int metaTypeId); 22 | static AssociativeWriter::AssociationInfo tryParseAssociationInfo(int metaTypeId); 23 | }; 24 | 25 | Q_DECLARE_LOGGING_CATEGORY(logSeqWriter) 26 | Q_DECLARE_LOGGING_CATEGORY(logAsocWriter) 27 | 28 | 29 | 30 | namespace Implementations { 31 | 32 | class SequentialWriterFactoryQStringList : public SequentialWriterFactory 33 | { 34 | public: 35 | QSharedPointer create(void *data) const final { 36 | return QSharedPointer>::create(reinterpret_cast(data)); 37 | } 38 | }; 39 | 40 | class SequentialWriterFactoryQByteArrayList : public SequentialWriterFactory 41 | { 42 | public: 43 | QSharedPointer create(void *data) const final { 44 | return QSharedPointer>::create(reinterpret_cast(data)); 45 | } 46 | }; 47 | 48 | class SequentialWriterFactoryQVariantList : public SequentialWriterFactory 49 | { 50 | public: 51 | QSharedPointer create(void *data) const final { 52 | return QSharedPointer>::create(reinterpret_cast(data)); 53 | } 54 | }; 55 | 56 | 57 | 58 | class AssociativeWriterFactoryQVariantMap : public AssociativeWriterFactory 59 | { 60 | public: 61 | QSharedPointer create(void *data) const final { 62 | return QSharedPointer>::create(reinterpret_cast(data)); 63 | } 64 | }; 65 | 66 | class AssociativeWriterFactoryQVariantHash : public AssociativeWriterFactory 67 | { 68 | public: 69 | QSharedPointer create(void *data) const final { 70 | return QSharedPointer>::create(reinterpret_cast(data)); 71 | } 72 | }; 73 | 74 | } 75 | 76 | } 77 | 78 | #endif // QTJSONSERIALIZER_METAWRITERS_P_H 79 | -------------------------------------------------------------------------------- /src/jsonserializer/qjsonreggen.pri: -------------------------------------------------------------------------------- 1 | DISTFILES += \ 2 | $$PWD/qjsonreggen.py 3 | 4 | JSON_TYPES = \ 5 | bool \ 6 | char \ 7 | "signed char" \ 8 | uchar \ 9 | short \ 10 | ushort \ 11 | int \ 12 | uint \ 13 | long \ 14 | ulong \ 15 | qlonglong \ 16 | qulonglong \ 17 | float \ 18 | double \ 19 | QObject* \ 20 | QChar \ 21 | QString \ 22 | QDate \ 23 | QTime \ 24 | QDateTime \ 25 | QUrl \ 26 | QUuid \ 27 | QCborValue \ 28 | QCborMap \ 29 | QCborArray \ 30 | QJsonValue \ 31 | QJsonObject \ 32 | QJsonArray \ 33 | QMimeType \ 34 | QVersionNumber \ 35 | QLocale \ 36 | QRegularExpression \ 37 | QSize \ 38 | QPoint \ 39 | QLine \ 40 | QRect \ 41 | QSizeF \ 42 | QPointF \ 43 | QLineF \ 44 | QRectF \ 45 | QByteArray 46 | 47 | QSize.modes = list 48 | QPoint.modes = list 49 | QLine.modes = list 50 | QRect.modes = list 51 | QSizeF.modes = list 52 | QPointF.modes = list 53 | QLineF.modes = list 54 | QRectF.modes = list 55 | QByteArray.modes = map set 56 | 57 | isEmpty(QT_JSONSERIALIZER_REGGEN_DIR): QT_JSONSERIALIZER_REGGEN_DIR = $$OUT_PWD/.reggen 58 | debug_and_release { 59 | CONFIG(debug, debug|release): QT_JSONSERIALIZER_REGGEN_DIR = $$QT_JSONSERIALIZER_REGGEN_DIR/debug 60 | CONFIG(release, debug|release): QT_JSONSERIALIZER_REGGEN_DIR = $$QT_JSONSERIALIZER_REGGEN_DIR/release 61 | } 62 | mkpath($$QT_JSONSERIALIZER_REGGEN_DIR) 63 | 64 | isEmpty(QT_JSONSERIALIZER_TYPESPLIT_PY) { 65 | win32: QT_JSONSERIALIZER_TYPESPLIT_PY = python 66 | QT_JSONSERIALIZER_TYPESPLIT_PY += $$shell_quote($$PWD/qjsonreggen.py) 67 | } 68 | 69 | for(type, JSON_TYPES) { 70 | type_base = $$replace(type, "\\W", "_") 71 | target_base = qjsonconverterreg_$${type_base}.cpp 72 | target_path = $$absolute_path($$target_base, $$QT_JSONSERIALIZER_REGGEN_DIR) 73 | $${target_path}.name = $$target_path 74 | $${target_path}.depends = $$PWD/qjsonreggen.py $$PWD/qjsonreggen.pri 75 | $${target_path}.commands = $$QT_JSONSERIALIZER_TYPESPLIT_PY $$shell_quote($$target_path) $$shell_quote($$type) $$eval($${type_base}.modes) 76 | QMAKE_EXTRA_TARGETS += $$target_path 77 | GENERATED_SOURCES += $$target_path 78 | } 79 | 80 | escaped_types = 81 | for(type, JSON_TYPES): escaped_types += $$shell_quote($$type) 82 | target_path = $$absolute_path(qjsonconverterreg_hook.cpp, $$QT_JSONSERIALIZER_REGGEN_DIR) 83 | $${target_path}.name = $$target_path 84 | $${target_path}.depends = $$PWD/qjsonreggen.py $$PWD/qjsonreggen.pri 85 | $${target_path}.commands = $$QT_JSONSERIALIZER_TYPESPLIT_PY super $$shell_quote($$target_path) $$escaped_types 86 | QMAKE_EXTRA_TARGETS += $$target_path 87 | GENERATED_SOURCES += $$target_path 88 | -------------------------------------------------------------------------------- /src/jsonserializer/qjsonreggen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Syntax: qjsonreggen.py ... 3 | # Syntax: qjsonreggen.py super ... 4 | 5 | import sys 6 | import re 7 | from enum import Enum 8 | 9 | class Mode(Enum): 10 | ALL = 0 11 | LIST = 1 12 | MAP = 2 13 | SET = 3 14 | POINTER = 4 15 | POINTER_LIST = 5 16 | 17 | 18 | def escaped(name): 19 | return re.sub(r"\W", "_", name, re.ASCII) 20 | 21 | 22 | def mode_fn(mode): 23 | if mode == Mode.ALL: 24 | return "registerBasicConverters" 25 | elif mode == Mode.LIST: 26 | return "registerListConverters" 27 | elif mode == Mode.MAP: 28 | return "registerMapConverters" 29 | elif mode == Mode.SET: 30 | return "registerSetConverters" 31 | elif mode == Mode.POINTER: 32 | return "registerPointerConverters" 33 | elif mode == Mode.POINTER_LIST: 34 | return "registerPointerListConverters" 35 | 36 | 37 | def create_hook(file_name, class_name, *modes): 38 | if len(modes) == 0: 39 | modes = ["all"] 40 | 41 | with open(file_name, "w") as file: 42 | file.write('#include "qtjsonserializer_global.h"\n') 43 | file.write('#include "serializerbase.h"\n') 44 | file.write("#include \n\n") 45 | 46 | file.write("#define QT_JSON_SERIALIZER_NAMED(T) #T\n\n") 47 | 48 | file.write("namespace QtJsonSerializer::__private::converter_hooks {\n\n") 49 | 50 | file.write("void register_{}_converters() {{\n".format(escaped(class_name))) 51 | for mode_name in modes: 52 | mode = Mode[mode_name.upper()] 53 | if mode == Mode.MAP: 54 | file.write("\tSerializerBase::{}();\n".format(mode_fn(mode), class_name)) 55 | else: 56 | file.write("\tSerializerBase::{}<{}>();\n".format(mode_fn(mode), class_name)) 57 | file.write("}\n\n") 58 | 59 | file.write("}\n") 60 | 61 | 62 | def create_super_hook(file_name, *class_names): 63 | with open(file_name, "w") as file: 64 | file.write('#include "qtjsonserializer_global.h"\n\n') 65 | 66 | file.write("namespace QtJsonSerializer::__private::converter_hooks {\n\n") 67 | for class_name in class_names: 68 | file.write("void register_{}_converters();\n".format(escaped(class_name))) 69 | file.write("\n}\n\n") 70 | 71 | file.write("namespace QtJsonSerializer {\n\n") 72 | file.write("void registerTypes() {\n") 73 | file.write("\tstatic bool wasCalled = false;\n") 74 | file.write("\tif(wasCalled)\n") 75 | file.write("\t\treturn;\n") 76 | file.write("\twasCalled = true;\n") 77 | for class_name in class_names: 78 | file.write("\tQtJsonSerializer::__private::converter_hooks::register_{}_converters();\n".format(escaped(class_name))) 79 | file.write("}\n\n") 80 | file.write("}\n") 81 | 82 | 83 | if __name__ == "__main__": 84 | if sys.argv[1] == "super": 85 | create_super_hook(sys.argv[2], *sys.argv[3:]) 86 | else: 87 | create_hook(sys.argv[1], sys.argv[2], *sys.argv[3:]) 88 | -------------------------------------------------------------------------------- /src/jsonserializer/qtjsonserializer_global.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_GLOBAL_H 2 | #define QTJSONSERIALIZER_GLOBAL_H 3 | 4 | #include 5 | 6 | #ifndef QT_STATIC 7 | # if defined(QT_BUILD_JSONSERIALIZER_LIB) 8 | # define Q_JSONSERIALIZER_EXPORT Q_DECL_EXPORT 9 | # else 10 | # define Q_JSONSERIALIZER_EXPORT Q_DECL_IMPORT 11 | # endif 12 | #else 13 | # define Q_JSONSERIALIZER_EXPORT 14 | #endif 15 | 16 | namespace QtJsonSerializer { 17 | 18 | //! Method to register all type converters for basic Qt types 19 | Q_JSONSERIALIZER_EXPORT void registerTypes(); 20 | 21 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 22 | #define QMetaTypeName(X) QMetaType::typeName(X) 23 | #else 24 | #define QMetaTypeName(X) QMetaType(X).name() 25 | #endif 26 | 27 | } 28 | 29 | //! @file qtjsonserializer_global.h The QtJsonSerializer library header file 30 | #endif // QTJSONSERIALIZER_GLOBAL_H 31 | -------------------------------------------------------------------------------- /src/jsonserializer/serializerbase_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_SERIALIZERBASE_P_H 2 | #define QTJSONSERIALIZER_SERIALIZERBASE_P_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "serializerbase.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | namespace QtJsonSerializer { 14 | 15 | class Q_JSONSERIALIZER_EXPORT SerializerBasePrivate : public QObjectPrivate 16 | { 17 | Q_DECLARE_PUBLIC(SerializerBase) 18 | 19 | public: 20 | using ValidationFlag = SerializerBase::ValidationFlag; 21 | using ValidationFlags = SerializerBase::ValidationFlags; 22 | using Polymorphing = SerializerBase::Polymorphing; 23 | using MultiMapMode = SerializerBase::MultiMapMode; 24 | 25 | template 26 | class ThreadSafeStore { 27 | public: 28 | ThreadSafeStore() = default; 29 | ThreadSafeStore(std::initializer_list>> initData); 30 | 31 | QSharedPointer get(int metaTypeId) const; 32 | void add(int metaTypeId, const QSharedPointer &converter); 33 | 34 | void clear(); 35 | 36 | private: 37 | mutable QReadWriteLock _lock {}; 38 | QHash> _store; 39 | }; 40 | 41 | template 42 | struct ConverterStore { 43 | mutable QReadWriteLock lock {}; 44 | QList> store; 45 | QAtomicInt factoryOffset = 0; 46 | 47 | ConverterStore() = default; 48 | ConverterStore(std::initializer_list> initData); 49 | 50 | void insertSorted(const QSharedPointer &converter); 51 | void insertSorted(const QSharedPointer &converter, QWriteLocker &locker); 52 | }; 53 | 54 | static ThreadSafeStore extractors; 55 | 56 | static QReadWriteLock typeConverterFactoryLock; 57 | static QList typeConverterFactories; 58 | 59 | bool allowNull = false; 60 | bool keepObjectName = false; 61 | bool enumAsString = false; 62 | bool versionAsString = false; 63 | bool dateAsTimeStamp = false; 64 | bool useBcp47Locale = true; 65 | ValidationFlags validationFlags = ValidationFlag::StandardValidation; 66 | Polymorphing polymorphing = Polymorphing::Enabled; 67 | MultiMapMode multiMapMode = MultiMapMode::Map; 68 | bool ignoreStoredAttribute = false; 69 | 70 | mutable ConverterStore typeConverters; 71 | mutable ThreadSafeStore serCache; 72 | mutable ThreadSafeStore deserCache; 73 | 74 | template 75 | void insertSorted(const QSharedPointer &converter, QList> &list) const; 76 | 77 | QSharedPointer findSerConverter(int propertyType) const; 78 | QSharedPointer findDeserConverter(int &propertyType, QCborTag tag, QCborValue::Type type) const; 79 | void updateConverterStore() const; 80 | 81 | int getEnumId(QMetaEnum metaEnum, bool ser) const; 82 | virtual QCborValue serializeValue(int propertyType, const QVariant &value) const; 83 | virtual QVariant deserializeCborValue(int propertyType, const QCborValue &value) const; 84 | virtual QVariant deserializeJsonValue(int propertyType, const QCborValue &value) const; 85 | }; 86 | 87 | Q_DECLARE_LOGGING_CATEGORY(logSerializer) 88 | Q_DECLARE_LOGGING_CATEGORY(logSerializerExtractor) 89 | 90 | template 91 | SerializerBasePrivate::ThreadSafeStore::ThreadSafeStore(std::initializer_list>> initData) 92 | : _store{std::move(initData)} 93 | {} 94 | 95 | template 96 | QSharedPointer SerializerBasePrivate::ThreadSafeStore::get(int metaTypeId) const 97 | { 98 | QReadLocker _{&_lock}; 99 | return _store.value(metaTypeId, nullptr); 100 | } 101 | 102 | template 103 | void SerializerBasePrivate::ThreadSafeStore::add(int metaTypeId, const QSharedPointer &converter) 104 | { 105 | QWriteLocker _{&_lock}; 106 | _store.insert(metaTypeId, converter); 107 | } 108 | 109 | template 110 | void SerializerBasePrivate::ThreadSafeStore::clear() 111 | { 112 | QWriteLocker _{&_lock}; 113 | _store.clear(); 114 | } 115 | 116 | template 117 | SerializerBasePrivate::ConverterStore::ConverterStore(std::initializer_list> initData) 118 | : store{std::move(initData)} 119 | { 120 | #ifndef QT_NO_DEBUG 121 | for (auto i = 1; i < store.size(); ++i) 122 | Q_ASSERT(store[i]->priority() <= store[i - 1]->priority()); 123 | #endif 124 | } 125 | 126 | template 127 | void SerializerBasePrivate::ConverterStore::insertSorted(const QSharedPointer &converter) 128 | { 129 | QWriteLocker _{&lock}; 130 | insertSorted(converter, _); 131 | } 132 | 133 | template 134 | void SerializerBasePrivate::ConverterStore::insertSorted(const QSharedPointer &converter, QWriteLocker &locker) 135 | { 136 | Q_UNUSED(locker) 137 | for (auto it = store.begin(); it != store.end(); ++it) { 138 | if ((*it)->priority() < converter->priority()) { 139 | store.insert(it, converter); 140 | return; 141 | } 142 | } 143 | // not inserted -> add to end 144 | store.append(converter); 145 | } 146 | 147 | } 148 | 149 | #endif // QTJSONSERIALIZER_SERIALIZERBASE_P_H 150 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverter.cpp: -------------------------------------------------------------------------------- 1 | #include "typeconverter.h" 2 | #include "serializerbase_p.h" 3 | using namespace QtJsonSerializer; 4 | 5 | namespace QtJsonSerializer { 6 | 7 | class TypeConverterPrivate 8 | { 9 | public: 10 | int priority = TypeConverter::Standard; 11 | const TypeConverter::SerializationHelper *helper = nullptr; 12 | }; 13 | 14 | } 15 | 16 | 17 | 18 | TypeConverter::TypeConverter() : 19 | d{new TypeConverterPrivate{}} 20 | {} 21 | 22 | TypeConverter::~TypeConverter() = default; 23 | 24 | int TypeConverter::priority() const 25 | { 26 | return d->priority; 27 | } 28 | 29 | void TypeConverter::setPriority(int priority) 30 | { 31 | d->priority = priority; 32 | } 33 | 34 | const TypeConverter::SerializationHelper *TypeConverter::helper() const 35 | { 36 | return d->helper; 37 | } 38 | 39 | void TypeConverter::setHelper(const TypeConverter::SerializationHelper *helper) 40 | { 41 | d->helper = helper; 42 | } 43 | 44 | QList TypeConverter::allowedCborTags(int metaTypeId) const 45 | { 46 | Q_UNUSED(metaTypeId) 47 | return {}; 48 | } 49 | 50 | int TypeConverter::guessType(QCborTag tag, QCborValue::Type dataType) const 51 | { 52 | Q_UNUSED(tag) 53 | Q_UNUSED(dataType) 54 | return QMetaType::UnknownType; 55 | } 56 | 57 | TypeConverter::DeserializationCapabilityResult TypeConverter::canDeserialize(int &metaTypeId, QCborTag tag, QCborValue::Type dataType) const 58 | { 59 | const auto asJson = helper()->jsonMode(); 60 | const auto strict = helper()->getProperty("validationFlags") 61 | .value() 62 | .testFlag(SerializerBase::ValidationFlag::StrictBasicTypes); 63 | 64 | // case A: a metaTypeId is present 65 | if (metaTypeId != QMetaType::UnknownType) { 66 | // first: verify the given metatype is supported 67 | if (!canConvert(metaTypeId)) 68 | return DeserializationCapabilityResult::Negative; 69 | 70 | // second: verify the tag if not in json mode 71 | if (!asJson) { 72 | // if either we are in strict mode or a tag is given, the tag is verified 73 | if (strict || tag != NoTag) { 74 | // If there is a list of allowed tags, the given tag must be in it 75 | auto aTags = allowedCborTags(metaTypeId); 76 | // also, add the type specific override tag if set 77 | if (const auto xTag = helper()->typeTag(metaTypeId); xTag != NoTag) 78 | aTags.append(xTag); 79 | if (!aTags.isEmpty()) { 80 | if (!aTags.contains(tag)) 81 | return DeserializationCapabilityResult::WrongTag; 82 | // otherwise, if in strict mode, an empty allowed tag list means the tag must not be set 83 | } else if (strict && tag != NoTag) 84 | return DeserializationCapabilityResult::WrongTag; 85 | } 86 | } 87 | 88 | // third: verify the datatype, based on type and tag 89 | auto aTypes = allowedCborTypes(metaTypeId, tag); 90 | // if in json mode, convert the supported types to their json equivalent 91 | if (asJson) 92 | mapTypesToJson(aTypes); 93 | // then verify them 94 | if (!aTypes.contains(dataType)) 95 | return DeserializationCapabilityResult::Negative; 96 | 97 | return DeserializationCapabilityResult::Positive; 98 | // case B: no metaTypeId is present, we are in cbor mode and have a tag 99 | } else if (!asJson && tag != NoTag){ 100 | // try to guess the id from tag and type 101 | metaTypeId = guessType(tag, dataType); 102 | if (metaTypeId != QMetaType::UnknownType) 103 | return DeserializationCapabilityResult::Guessed; 104 | else 105 | return DeserializationCapabilityResult::Negative; 106 | // otherwise: cannot convert 107 | } else 108 | return DeserializationCapabilityResult::Negative; 109 | } 110 | 111 | QVariant TypeConverter::deserializeJson(int propertyType, const QCborValue &value, QObject *parent) const 112 | { 113 | return deserializeCbor(propertyType, value, parent); 114 | } 115 | 116 | void TypeConverter::mapTypesToJson(QList &typeList) const 117 | { 118 | auto hasDouble = false; 119 | auto hasInt = false; 120 | for (auto &type : typeList) { 121 | switch (type) { 122 | case QCborValue::Double: 123 | hasDouble = true; 124 | break; 125 | case QCborValue::Integer: 126 | hasInt = true; 127 | break; 128 | case QCborValue::ByteArray: 129 | case QCborValue::DateTime: 130 | case QCborValue::Url: 131 | case QCborValue::RegularExpression: 132 | case QCborValue::Uuid: 133 | type = QCborValue::String; 134 | break; 135 | default: 136 | break; 137 | } 138 | } 139 | 140 | if (hasInt && !hasDouble) 141 | typeList.append(QCborValue::Double); 142 | if (hasDouble && !hasInt) 143 | typeList.append(QCborValue::Integer); 144 | } 145 | 146 | 147 | 148 | TypeConverter::SerializationHelper::SerializationHelper() = default; 149 | 150 | TypeConverter::SerializationHelper::~SerializationHelper() = default; 151 | 152 | 153 | 154 | TypeConverterFactory::TypeConverterFactory() = default; 155 | 156 | TypeConverterFactory::~TypeConverterFactory() = default; 157 | 158 | 159 | 160 | TypeExtractor::TypeExtractor() = default; 161 | 162 | TypeExtractor::~TypeExtractor() = default; 163 | 164 | QList TypeExtractor::subtypes() const 165 | { 166 | return {}; 167 | } 168 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/bitarrayconverter.cpp: -------------------------------------------------------------------------------- 1 | #include "bitarrayconverter_p.h" 2 | #include "cborserializer.h" 3 | #include 4 | using namespace QtJsonSerializer; 5 | using namespace QtJsonSerializer::TypeConverters; 6 | 7 | bool BitArrayConverter::canConvert(int metaTypeId) const 8 | { 9 | return metaTypeId == QMetaType::QBitArray; 10 | } 11 | 12 | QList BitArrayConverter::allowedCborTags(int metaTypeId) const 13 | { 14 | Q_UNUSED(metaTypeId) 15 | return {static_cast(CborSerializer::BitArray)}; 16 | } 17 | 18 | QList BitArrayConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const 19 | { 20 | Q_UNUSED(metaTypeId) 21 | Q_UNUSED(tag) 22 | return {QCborValue::ByteArray}; 23 | } 24 | 25 | int BitArrayConverter::guessType(QCborTag tag, QCborValue::Type dataType) const 26 | { 27 | if (tag == static_cast(CborSerializer::BitArray) && 28 | dataType == QCborValue::ByteArray) 29 | return QMetaType::QBitArray; 30 | else 31 | return QMetaType::UnknownType; 32 | } 33 | 34 | QCborValue BitArrayConverter::serialize(int propertyType, const QVariant &value) const 35 | { 36 | Q_UNUSED(propertyType) 37 | const auto bitArray = value.value(); 38 | if (bitArray.isEmpty()) 39 | return {static_cast(CborSerializer::BitArray), QByteArray{}}; 40 | else { 41 | const auto byteLen = bitArray.size() % 8 == 0 ? 42 | bitArray.size() / 8 : 43 | (bitArray.size() / 8) + 1; 44 | QByteArray cData(byteLen + 1, 0); 45 | cData[0] = static_cast(bitArray.size() % 8); 46 | memcpy(cData.data() + 1, bitArray.bits(), static_cast(byteLen)); 47 | return {static_cast(CborSerializer::BitArray), cData}; 48 | } 49 | } 50 | 51 | QVariant BitArrayConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const 52 | { 53 | Q_UNUSED(propertyType) 54 | Q_UNUSED(parent) 55 | 56 | const auto cData = (value.isTag() ? value.taggedValue() : value).toByteArray(); 57 | if (cData.isEmpty()) 58 | return QBitArray{}; 59 | else { 60 | const auto byteLen = cData.size() - 1; 61 | const auto sSize = static_cast(cData[0]); 62 | if (sSize == 0) 63 | return QBitArray::fromBits(cData.data() + 1, byteLen * 8); 64 | else 65 | return QBitArray::fromBits(cData.data() + 1, (byteLen - 1) * 8 + sSize); 66 | } 67 | } 68 | 69 | QVariant BitArrayConverter::deserializeJson(int propertyType, const QCborValue &value, QObject *parent) const 70 | { 71 | return deserializeCbor(propertyType, 72 | QByteArray::fromBase64(value.toString().toUtf8(), QByteArray::Base64UrlEncoding), 73 | parent); 74 | } 75 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/bitarrayconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_BITARRAYCONVERTER_H 2 | #define QTJSONSERIALIZER_BITARRAYCONVERTER_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | namespace QtJsonSerializer::TypeConverters { 8 | 9 | class Q_JSONSERIALIZER_EXPORT BitArrayConverter : public TypeConverter 10 | { 11 | public: 12 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(BitArrayConverter) 13 | bool canConvert(int metaTypeId) const override; 14 | QList allowedCborTags(int metaTypeId) const override; 15 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 16 | int guessType(QCborTag tag, QCborValue::Type dataType) const override; 17 | QCborValue serialize(int propertyType, const QVariant &value) const override; 18 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 19 | QVariant deserializeJson(int propertyType, const QCborValue &value, QObject *parent) const override; 20 | }; 21 | 22 | } 23 | 24 | #endif // QTJSONSERIALIZER_BITARRAYCONVERTER_H 25 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/bytearrayconverter.cpp: -------------------------------------------------------------------------------- 1 | #include "bytearrayconverter_p.h" 2 | #include "exception.h" 3 | #include "jsonserializer.h" 4 | 5 | #include 6 | #include 7 | using namespace QtJsonSerializer; 8 | using namespace QtJsonSerializer::TypeConverters; 9 | 10 | bool BytearrayConverter::canConvert(int metaTypeId) const 11 | { 12 | return metaTypeId == QMetaType::QByteArray; 13 | } 14 | 15 | QList BytearrayConverter::allowedCborTags(int metaTypeId) const 16 | { 17 | Q_UNUSED(metaTypeId) 18 | return { 19 | NoTag, 20 | static_cast(QCborKnownTags::ExpectedBase64), 21 | static_cast(QCborKnownTags::ExpectedBase64url), 22 | static_cast(QCborKnownTags::ExpectedBase16), 23 | }; 24 | } 25 | 26 | QList BytearrayConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const 27 | { 28 | Q_UNUSED(metaTypeId) 29 | Q_UNUSED(tag) 30 | return {QCborValue::ByteArray}; 31 | } 32 | 33 | int BytearrayConverter::guessType(QCborTag tag, QCborValue::Type dataType) const 34 | { 35 | Q_UNUSED(dataType) 36 | switch (tag) { 37 | case static_cast(QCborKnownTags::ExpectedBase64): 38 | case static_cast(QCborKnownTags::ExpectedBase64url): 39 | case static_cast(QCborKnownTags::ExpectedBase16): 40 | return QMetaType::QByteArray; 41 | default: 42 | return QMetaType::UnknownType; 43 | } 44 | } 45 | 46 | QCborValue BytearrayConverter::serialize(int propertyType, const QVariant &value) const 47 | { 48 | Q_UNUSED(propertyType) 49 | return value.toByteArray(); 50 | } 51 | 52 | QVariant BytearrayConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const 53 | { 54 | Q_UNUSED(propertyType) 55 | Q_UNUSED(parent) 56 | return (value.isTag() ? value.taggedValue() : value).toByteArray(); 57 | } 58 | 59 | QVariant BytearrayConverter::deserializeJson(int propertyType, const QCborValue &value, QObject *parent) const 60 | { 61 | Q_UNUSED(propertyType) 62 | Q_UNUSED(parent) 63 | 64 | const auto mode = helper()->getProperty("byteArrayFormat").value(); 65 | const auto strValue = value.toString(); 66 | if (helper()->getProperty("validateBase64").toBool()) { 67 | switch (mode) { 68 | case JsonSerializer::ByteArrayFormat::Base64: { 69 | if ((strValue.size() % 4) != 0) 70 | throw DeserializationException("String has invalid length for base64 encoding"); 71 | static const QRegularExpression regex(QStringLiteral(R"__(^[a-zA-Z0-9+\/]*(={0,2})$)__")); 72 | if (!regex.match(strValue).hasMatch()) 73 | throw DeserializationException("String contains unallowed symbols for base64 encoding"); 74 | break; 75 | } 76 | case JsonSerializer::ByteArrayFormat::Base64url: { 77 | static const QRegularExpression regex(QStringLiteral(R"__(^[a-zA-Z0-9\-_]*$)__")); 78 | if (!regex.match(strValue).hasMatch()) 79 | throw DeserializationException("String contains unallowed symbols for base64url encoding"); 80 | break; 81 | } 82 | case JsonSerializer::ByteArrayFormat::Base16: { 83 | if ((strValue.size() % 2) != 0) 84 | throw DeserializationException("String has invalid length for base16 encoding"); 85 | static const QRegularExpression regex(QStringLiteral(R"__(^[a-fA-F0-9]*$)__")); 86 | if (!regex.match(strValue).hasMatch()) 87 | throw DeserializationException("String contains unallowed symbols for base16 encoding"); 88 | break; 89 | } 90 | default: 91 | Q_UNREACHABLE(); 92 | } 93 | } 94 | 95 | switch (mode) { 96 | case JsonSerializer::ByteArrayFormat::Base64: 97 | return QByteArray::fromBase64(strValue.toUtf8(), QByteArray::Base64Encoding); 98 | case JsonSerializer::ByteArrayFormat::Base64url: 99 | return QByteArray::fromBase64(strValue.toUtf8(), QByteArray::Base64UrlEncoding); 100 | case JsonSerializer::ByteArrayFormat::Base16: 101 | return QByteArray::fromHex(strValue.toUtf8()); 102 | default: 103 | Q_UNREACHABLE(); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/bytearrayconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_BYTEARRAYCONVERTER_P_H 2 | #define QTJSONSERIALIZER_BYTEARRAYCONVERTER_P_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | namespace QtJsonSerializer::TypeConverters { 8 | 9 | class Q_JSONSERIALIZER_EXPORT BytearrayConverter : public TypeConverter 10 | { 11 | public: 12 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(BytearrayConverter) 13 | bool canConvert(int metaTypeId) const override; 14 | QList allowedCborTags(int metaTypeId) const override; 15 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 16 | int guessType(QCborTag tag, QCborValue::Type dataType) const override; 17 | QCborValue serialize(int propertyType, const QVariant &value) const override; 18 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 19 | QVariant deserializeJson(int propertyType, const QCborValue &value, QObject *parent) const override; 20 | }; 21 | 22 | } 23 | 24 | #endif // QTJSONSERIALIZER_BYTEARRAYCONVERTER_P_H 25 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/cborconverter.cpp: -------------------------------------------------------------------------------- 1 | #include "cborconverter_p.h" 2 | #include "exception.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace QtJsonSerializer; 9 | using namespace QtJsonSerializer::TypeConverters; 10 | 11 | bool CborConverter::canConvert(int metaTypeId) const 12 | { 13 | static const QSet metaTypes { 14 | QMetaType::QCborValue, 15 | QMetaType::QCborMap, 16 | QMetaType::QCborArray, 17 | QMetaType::QCborSimpleType, 18 | QMetaType::QJsonValue, 19 | QMetaType::QJsonObject, 20 | QMetaType::QJsonArray, 21 | QMetaType::QJsonDocument, 22 | }; 23 | return metaTypes.contains(metaTypeId); 24 | } 25 | 26 | QList CborConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const 27 | { 28 | Q_UNUSED(tag) 29 | switch (metaTypeId) { 30 | case QMetaType::QCborValue:{ 31 | QList types; 32 | const auto metaEnum = QMetaEnum::fromType(); 33 | types.reserve(metaEnum.keyCount()); 34 | for (auto i = 0; i < metaEnum.keyCount(); ++i) { 35 | if (const auto value = metaEnum.value(i); value != QCborValue::Invalid) 36 | types.append(static_cast(value)); 37 | } 38 | return types; 39 | } 40 | case QMetaType::QJsonValue: 41 | return { 42 | QCborValue::Null, 43 | QCborValue::True, 44 | QCborValue::False, 45 | QCborValue::Double, 46 | QCborValue::String, 47 | QCborValue::Array, 48 | QCborValue::Map 49 | }; 50 | case QMetaType::QCborSimpleType: 51 | return { 52 | QCborValue::SimpleType, 53 | QCborValue::True, 54 | QCborValue::False, 55 | QCborValue::Null, 56 | QCborValue::Undefined 57 | }; 58 | case QMetaType::QCborMap: 59 | case QMetaType::QJsonObject: 60 | return {QCborValue::Map}; 61 | case QMetaType::QCborArray: 62 | case QMetaType::QJsonArray: 63 | return {QCborValue::Array}; 64 | case QMetaType::QJsonDocument: 65 | return {QCborValue::Map, QCborValue::Array, QCborValue::Null}; 66 | default: 67 | Q_UNREACHABLE(); 68 | } 69 | } 70 | 71 | QCborValue CborConverter::serialize(int propertyType, const QVariant &value) const 72 | { 73 | switch (propertyType) { 74 | case QMetaType::QCborValue: 75 | case QMetaType::QCborSimpleType: 76 | case QMetaType::QCborMap: 77 | case QMetaType::QCborArray: 78 | return value.value(); 79 | case QMetaType::QJsonValue: 80 | case QMetaType::QJsonObject: 81 | case QMetaType::QJsonArray: 82 | case QMetaType::QJsonDocument: 83 | return QCborValue::fromJsonValue(value.toJsonValue()); 84 | default: 85 | throw SerializationException{"Unsupported type"}; 86 | } 87 | } 88 | 89 | QVariant CborConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const 90 | { 91 | Q_UNUSED(parent) 92 | switch (propertyType) { 93 | case QMetaType::QJsonValue: 94 | return QVariant::fromValue(value.toJsonValue()); 95 | case QMetaType::QJsonObject: 96 | return QVariant::fromValue(value.toJsonValue().toObject()); 97 | case QMetaType::QJsonArray: 98 | return QVariant::fromValue(value.toJsonValue().toArray()); 99 | case QMetaType::QJsonDocument: { 100 | const auto jValue = value.toJsonValue(); 101 | switch (jValue.type()) { 102 | case QJsonValue::Array: 103 | return QVariant::fromValue(QJsonDocument{jValue.toArray()}); 104 | case QJsonValue::Object: 105 | return QVariant::fromValue(QJsonDocument{jValue.toObject()}); 106 | default: 107 | return QVariant::fromValue(QJsonDocument{}); 108 | } 109 | } 110 | case QMetaType::QCborValue: 111 | case QMetaType::QCborSimpleType: 112 | case QMetaType::QCborMap: 113 | case QMetaType::QCborArray: 114 | return QVariant::fromValue(value); 115 | default: 116 | throw DeserializationException{"Unsupported type"}; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/cborconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_CBORCONVERTER_H 2 | #define QTJSONSERIALIZER_CBORCONVERTER_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | namespace QtJsonSerializer::TypeConverters { 8 | 9 | class Q_JSONSERIALIZER_EXPORT CborConverter : public TypeConverter 10 | { 11 | public: 12 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(CborConverter) 13 | bool canConvert(int metaTypeId) const override; 14 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 15 | QCborValue serialize(int propertyType, const QVariant &value) const override; 16 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 17 | }; 18 | 19 | } 20 | 21 | #endif // QTJSONSERIALIZER_CBORCONVERTER_H 22 | 23 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/datetimeconverter.cpp: -------------------------------------------------------------------------------- 1 | #include "datetimeconverter_p.h" 2 | #include "exception.h" 3 | #include "cborserializer.h" 4 | #include 5 | using namespace QtJsonSerializer; 6 | using namespace QtJsonSerializer::TypeConverters; 7 | 8 | bool DateTimeConverter::canConvert(int metaTypeId) const 9 | { 10 | static const QSet types { 11 | QMetaType::QDateTime, 12 | QMetaType::QDate, 13 | QMetaType::QTime 14 | }; 15 | return types.contains(metaTypeId); 16 | } 17 | 18 | QList DateTimeConverter::allowedCborTags(int metaTypeId) const 19 | { 20 | switch (metaTypeId) { 21 | case QMetaType::QDateTime: 22 | return {static_cast(QCborKnownTags::DateTimeString), static_cast(QCborKnownTags::UnixTime_t)}; 23 | case QMetaType::QDate: 24 | return {static_cast(QCborKnownTags::DateTimeString), static_cast(CborSerializer::Date)}; 25 | case QMetaType::QTime: 26 | return {static_cast(QCborKnownTags::DateTimeString), static_cast(CborSerializer::Time)}; 27 | default: 28 | return {}; 29 | } 30 | } 31 | 32 | QList DateTimeConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const 33 | { 34 | switch (tag) { 35 | case static_cast(QCborKnownTags::UnixTime_t): 36 | return {QCborValue::Integer}; 37 | case static_cast(QCborKnownTags::DateTimeString): 38 | case static_cast(CborSerializer::Date): 39 | case static_cast(CborSerializer::Time): 40 | return {QCborValue::String}; 41 | default: 42 | if (metaTypeId == QMetaType::QDateTime) 43 | return {QCborValue::String, QCborValue::Integer}; 44 | else 45 | return {QCborValue::String}; 46 | } 47 | } 48 | 49 | int DateTimeConverter::guessType(QCborTag tag, QCborValue::Type dataType) const 50 | { 51 | switch (tag) { 52 | case static_cast(QCborKnownTags::DateTimeString): 53 | if (dataType == QCborValue::String) 54 | return QMetaType::QDateTime; 55 | else 56 | break; 57 | case static_cast(QCborKnownTags::UnixTime_t): 58 | if (dataType == QCborValue::Integer) 59 | return QMetaType::QDateTime; 60 | else 61 | break; 62 | case static_cast(CborSerializer::Date): 63 | if (dataType == QCborValue::String) 64 | return QMetaType::QDate; 65 | else 66 | break; 67 | case static_cast(CborSerializer::Time): 68 | if (dataType == QCborValue::String) 69 | return QMetaType::QTime; 70 | else 71 | break; 72 | default: 73 | break; 74 | } 75 | 76 | return QMetaType::UnknownType; 77 | } 78 | 79 | QCborValue DateTimeConverter::serialize(int propertyType, const QVariant &value) const 80 | { 81 | switch (propertyType) { 82 | case QMetaType::QDateTime: 83 | if (helper()->getProperty("dateAsTimeStamp").toBool()) 84 | return {QCborKnownTags::UnixTime_t, value.toDateTime().toUTC().toSecsSinceEpoch()}; 85 | else 86 | return QCborValue{value.toDateTime()}; 87 | case QMetaType::QDate: 88 | return {static_cast(CborSerializer::Date), value.toDate().toString(Qt::ISODate)}; 89 | case QMetaType::QTime: 90 | return {static_cast(CborSerializer::Time), value.toTime().toString(Qt::ISODateWithMs)}; 91 | default: 92 | throw SerializationException{"Invalid property type"}; 93 | } 94 | } 95 | 96 | QVariant DateTimeConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const 97 | { 98 | Q_UNUSED(parent) 99 | const auto cValue = (value.isTag() ? value.taggedValue() : value); 100 | switch (propertyType) { 101 | case QMetaType::QDateTime: 102 | return value.toDateTime(); 103 | case QMetaType::QDate: 104 | if (value.tag() == QCborKnownTags::DateTimeString) 105 | return value.toDateTime().date(); 106 | else 107 | return QDate::fromString(cValue.toString(), Qt::ISODate); 108 | case QMetaType::QTime: 109 | if (value.tag() == QCborKnownTags::DateTimeString) 110 | return value.toDateTime().time(); 111 | else 112 | return QTime::fromString(cValue.toString(), Qt::ISODateWithMs); 113 | default: 114 | throw SerializationException{"Invalid property type"}; 115 | } 116 | } 117 | 118 | QVariant DateTimeConverter::deserializeJson(int propertyType, const QCborValue &value, QObject *parent) const 119 | { 120 | if (propertyType == QMetaType::QDateTime && 121 | value.type() == QCborValue::String) 122 | return deserializeCbor(propertyType, {QCborKnownTags::DateTimeString, value}, parent); 123 | else 124 | return deserializeCbor(propertyType, value, parent); 125 | } 126 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/datetimeconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_DATETIMECONVERTER_H 2 | #define QTJSONSERIALIZER_DATETIMECONVERTER_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | #include 8 | 9 | namespace QtJsonSerializer::TypeConverters { 10 | 11 | class Q_JSONSERIALIZER_EXPORT DateTimeConverter : public TypeConverter 12 | { 13 | public: 14 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(DateTimeConverter) 15 | bool canConvert(int metaTypeId) const override; 16 | QList allowedCborTags(int metaTypeId) const override; 17 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 18 | int guessType(QCborTag tag, QCborValue::Type dataType) const override; 19 | QCborValue serialize(int propertyType, const QVariant &value) const override; 20 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 21 | QVariant deserializeJson(int propertyType, const QCborValue &value, QObject *parent) const override; 22 | }; 23 | 24 | } 25 | 26 | #endif // QTJSONSERIALIZER_DATETIMECONVERTER_H 27 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/enumconverter.cpp: -------------------------------------------------------------------------------- 1 | #include "enumconverter_p.h" 2 | #include "exception.h" 3 | #include "cborserializer.h" 4 | 5 | #include 6 | using namespace QtJsonSerializer; 7 | using namespace QtJsonSerializer::TypeConverters; 8 | 9 | namespace { 10 | 11 | Q_NORETURN inline void throwSer(QByteArray &&what, bool ser) 12 | { 13 | if (ser) 14 | throw SerializationException{std::move(what)}; 15 | else 16 | throw DeserializationException{std::move(what)}; 17 | } 18 | 19 | } 20 | 21 | EnumConverter::EnumConverter() 22 | { 23 | setPriority(TypeConverter::Low); 24 | } 25 | 26 | bool EnumConverter::canConvert(int metaTypeId) const 27 | { 28 | return QMetaType(metaTypeId).flags().testFlag(QMetaType::IsEnumeration) || 29 | testForEnum(metaTypeId); // NOTE check once in a while if still needed 30 | } 31 | 32 | QList EnumConverter::allowedCborTags(int metaTypeId) const 33 | { 34 | const auto metaEnum = getEnum(metaTypeId, false); 35 | if (metaEnum.isFlag()) 36 | return {static_cast(CborSerializer::Flags)}; 37 | else 38 | return {static_cast(CborSerializer::Enum)}; 39 | } 40 | 41 | QList EnumConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const 42 | { 43 | Q_UNUSED(metaTypeId) 44 | Q_UNUSED(tag) 45 | return {QCborValue::Integer, QCborValue::String}; 46 | } 47 | 48 | QCborValue EnumConverter::serialize(int propertyType, const QVariant &value) const 49 | { 50 | const auto metaEnum = getEnum(propertyType, true); 51 | const auto tag = static_cast(metaEnum.isFlag() ? CborSerializer::Flags : CborSerializer::Enum); 52 | if (helper()->getProperty("enumAsString").toBool()) { 53 | if (metaEnum.isFlag()) 54 | return {tag, QString::fromUtf8(metaEnum.valueToKeys(value.toInt()))}; 55 | else 56 | return {tag, QString::fromUtf8(metaEnum.valueToKey(value.toInt()))}; 57 | } else 58 | return {tag, value.toInt()}; 59 | } 60 | 61 | QVariant EnumConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const 62 | { 63 | Q_UNUSED(parent) 64 | const auto metaEnum = getEnum(propertyType, false); 65 | auto cValue = value.isTag() ? value.taggedValue() : value; 66 | if (cValue.isString()) { 67 | auto result = -1; 68 | auto ok = false; 69 | if (metaEnum.isFlag()) 70 | result = metaEnum.keysToValue(qUtf8Printable(cValue.toString()), &ok); 71 | else 72 | result = metaEnum.keyToValue(qUtf8Printable(cValue.toString()), &ok); 73 | if (ok) 74 | return result; 75 | else if(metaEnum.isFlag() && cValue.toString().isEmpty()) 76 | return 0; 77 | else { 78 | throw DeserializationException{QByteArray{"Invalid value for enum type \""} + 79 | metaEnum.name() + 80 | "\": " + 81 | cValue.toString().toUtf8()}; 82 | } 83 | } else { 84 | const auto intValue = cValue.toInteger(); 85 | if (!metaEnum.isFlag() && metaEnum.valueToKey(intValue) == nullptr) { 86 | throw DeserializationException{"Invalid integer value. Not a valid enum/flags element: " + 87 | QByteArray::number(intValue)}; 88 | } 89 | return static_cast(intValue); 90 | } 91 | } 92 | 93 | QVariant EnumConverter::deserializeJson(int propertyType, const QCborValue &value, QObject *parent) const 94 | { 95 | if (value.isDouble()) { 96 | double intpart; 97 | if (std::modf(value.toDouble(), &intpart) != 0.0) { 98 | throw DeserializationException{"Invalid value (double) for enum type found: " + 99 | QByteArray::number(value.toDouble())}; 100 | } 101 | } 102 | return deserializeCbor(propertyType, value, parent); 103 | } 104 | 105 | bool EnumConverter::testForEnum(int metaTypeId) const 106 | { 107 | try { 108 | getEnum(metaTypeId, true); 109 | return true; 110 | } catch (Exception &) { 111 | return false; 112 | } 113 | } 114 | 115 | QMetaEnum EnumConverter::getEnum(int metaTypeId, bool ser) const 116 | { 117 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 118 | const auto mo = QMetaType::metaObjectForType(metaTypeId); 119 | #else 120 | const auto mo = QMetaType(metaTypeId).metaObject(); 121 | #endif 122 | if (!mo) 123 | throwSer(QByteArray{"Unable to get metaobject for type "} + QMetaTypeName(metaTypeId), ser); 124 | const auto enumName = QString::fromUtf8(QMetaTypeName(metaTypeId)) 125 | .split(QStringLiteral("::")) 126 | .last() 127 | .toUtf8(); 128 | auto mIndex = mo->indexOfEnumerator(enumName.data()); 129 | if (mIndex < 0) { 130 | throwSer(QByteArray{"Unable to get QMetaEnum for type "} + 131 | QMetaTypeName(metaTypeId) + 132 | QByteArray{" using the owning meta object "} + 133 | mo->className(), 134 | ser); 135 | } 136 | 137 | return mo->enumerator(mIndex); 138 | } 139 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/enumconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_ENUMCONVERTER_H 2 | #define QTJSONSERIALIZER_ENUMCONVERTER_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | #include 8 | 9 | namespace QtJsonSerializer::TypeConverters { 10 | 11 | class Q_JSONSERIALIZER_EXPORT EnumConverter : public TypeConverter 12 | { 13 | public: 14 | EnumConverter(); 15 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(EnumConverter) 16 | bool canConvert(int metaTypeId) const override; 17 | QList allowedCborTags(int metaTypeId) const override; 18 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 19 | QCborValue serialize(int propertyType, const QVariant &value) const override; 20 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 21 | QVariant deserializeJson(int propertyType, const QCborValue &value, QObject *parent) const override; 22 | 23 | private: 24 | bool testForEnum(int metaTypeId) const; 25 | QMetaEnum getEnum(int metaTypeId, bool ser) const; 26 | }; 27 | 28 | } 29 | 30 | #endif // QTJSONSERIALIZER_ENUMCONVERTER_H 31 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/gadgetconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_GADGETCONVERTER_P_H 2 | #define QTJSONSERIALIZER_GADGETCONVERTER_P_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | namespace QtJsonSerializer::TypeConverters { 8 | 9 | class Q_JSONSERIALIZER_EXPORT GadgetConverter : public TypeConverter 10 | { 11 | public: 12 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(GadgetConverter) 13 | bool canConvert(int metaTypeId) const override; 14 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 15 | QCborValue serialize(int propertyType, const QVariant &value) const override; 16 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 17 | }; 18 | 19 | } 20 | 21 | #endif // QTJSONSERIALIZER_GADGETCONVERTER_P_H 22 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/geomconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_GEOMCONVERTER_P_H 2 | #define QTJSONSERIALIZER_GEOMCONVERTER_P_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace QtJsonSerializer::TypeConverters { 14 | 15 | class Q_JSONSERIALIZER_EXPORT GeomConverter : public TypeConverter 16 | { 17 | public: 18 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(GeomConverter) 19 | bool canConvert(int metaTypeId) const override; 20 | QList allowedCborTags(int metaTypeId) const override; 21 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 22 | int guessType(QCborTag tag, QCborValue::Type dataType) const override; 23 | QCborValue serialize(int propertyType, const QVariant &value) const override; 24 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 25 | 26 | private: 27 | QCborValue serializeSize(const std::variant &size) const; 28 | QCborValue serializePoint(const std::variant &point) const; 29 | QCborValue serializeLine(const std::variant &line) const; 30 | QCborValue serializeRect(const std::variant &rect) const; 31 | 32 | template 33 | TSize deserializeSize(const QCborArray &array) const; 34 | template 35 | TPoint deserializePoint(const QCborArray &array) const; 36 | template 37 | TLine deserializeLine(const QCborArray &array) const; 38 | template 39 | TRect deserializeRect(const QCborArray &array) const; 40 | template 41 | TValue extract(const QCborValue &value) const; 42 | }; 43 | 44 | template <> 45 | int GeomConverter::extract(const QCborValue &value) const; 46 | 47 | template <> 48 | qreal GeomConverter::extract(const QCborValue &value) const; 49 | 50 | } 51 | 52 | #endif // QTJSONSERIALIZER_GEOMCONVERTER_P_H 53 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/legacygeomconverter.cpp: -------------------------------------------------------------------------------- 1 | #include "legacygeomconverter_p.h" 2 | #include "exception.h" 3 | 4 | #include 5 | using namespace QtJsonSerializer; 6 | using namespace QtJsonSerializer::TypeConverters; 7 | 8 | LegacyGeomConverter::LegacyGeomConverter() 9 | { 10 | setPriority(Priority::VeryLow); 11 | } 12 | 13 | bool LegacyGeomConverter::canConvert(int metaTypeId) const 14 | { 15 | static const QVector types { 16 | QMetaType::QSize, 17 | QMetaType::QSizeF, 18 | QMetaType::QPoint, 19 | QMetaType::QPointF, 20 | QMetaType::QLine, 21 | QMetaType::QLineF, 22 | QMetaType::QRect, 23 | QMetaType::QRectF, 24 | }; 25 | return types.contains(metaTypeId); 26 | } 27 | 28 | QList LegacyGeomConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const 29 | { 30 | Q_UNUSED(metaTypeId) 31 | Q_UNUSED(tag) 32 | return {QCborValue::Map}; 33 | } 34 | 35 | QCborValue LegacyGeomConverter::serialize(int propertyType, const QVariant &value) const 36 | { 37 | Q_UNUSED(propertyType) 38 | Q_UNUSED(value) 39 | throw SerializationException{"The QJsonLegacyGeomConverter cannot serialize data"}; 40 | } 41 | 42 | QVariant LegacyGeomConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const 43 | { 44 | Q_UNUSED(propertyType) 45 | Q_UNUSED(value) 46 | Q_UNUSED(parent) 47 | throw DeserializationException{"The QJsonLegacyGeomConverter cannot deserialize CBOR data"}; 48 | } 49 | 50 | QVariant LegacyGeomConverter::deserializeJson(int propertyType, const QCborValue &value, QObject *parent) const 51 | { 52 | Q_UNUSED(parent) 53 | const auto map = value.toMap(); 54 | switch (propertyType) { 55 | case QMetaType::QSize: 56 | return deserializeSize(map); 57 | case QMetaType::QSizeF: 58 | return deserializeSize(map); 59 | case QMetaType::QPoint: 60 | return deserializePoint(map); 61 | case QMetaType::QPointF: 62 | return deserializePoint(map); 63 | case QMetaType::QLine: 64 | return deserializeLine(map); 65 | case QMetaType::QLineF: 66 | return deserializeLine(map); 67 | case QMetaType::QRect: 68 | return deserializeRect(map); 69 | case QMetaType::QRectF: 70 | return deserializeRect(map); 71 | default: 72 | throw DeserializationException{"Invalid type id"}; 73 | } 74 | } 75 | 76 | template 77 | TSize LegacyGeomConverter::deserializeSize(const QCborMap &map) const 78 | { 79 | using TW = std::decay_t; 80 | using TH = std::decay_t; 81 | if (map.size() != 2 || 82 | !map.contains(QStringLiteral("width")) || 83 | !map.contains(QStringLiteral("height"))) 84 | throw DeserializationException("JSON object has no width or height properties or does have extra properties"); 85 | return { 86 | extract(map[QStringLiteral("width")]), 87 | extract(map[QStringLiteral("height")]) 88 | }; 89 | } 90 | 91 | template 92 | TPoint LegacyGeomConverter::deserializePoint(const QCborMap &map) const 93 | { 94 | using TX = std::decay_t; 95 | using TY = std::decay_t; 96 | if (map.size() != 2 || 97 | !map.contains(QStringLiteral("x")) || 98 | !map.contains(QStringLiteral("y"))) 99 | throw DeserializationException("JSON object has no x or y properties or does have extra properties"); 100 | return { 101 | extract(map[QStringLiteral("x")]), 102 | extract(map[QStringLiteral("y")]) 103 | }; 104 | } 105 | 106 | template 107 | TLine LegacyGeomConverter::deserializeLine(const QCborMap &map) const 108 | { 109 | using TP1 = std::decay_t; 110 | using TP2 = std::decay_t; 111 | if (map.size() != 2 || 112 | !map.contains(QStringLiteral("p1")) || 113 | !map.contains(QStringLiteral("p2"))) 114 | throw DeserializationException("JSON object has no p1 or p2 properties or does have extra properties"); 115 | return { 116 | helper()->deserializeSubtype(qMetaTypeId(), map[QStringLiteral("p1")], nullptr, "p1").template value(), 117 | helper()->deserializeSubtype(qMetaTypeId(), map[QStringLiteral("p2")], nullptr, "p2").template value() 118 | }; 119 | } 120 | 121 | template 122 | TRect LegacyGeomConverter::deserializeRect(const QCborMap &map) const 123 | { 124 | using TTL = std::decay_t; 125 | using TBR = std::decay_t; 126 | if (map.size() != 2 || 127 | !map.contains(QStringLiteral("topLeft")) || 128 | !map.contains(QStringLiteral("bottomRight"))) 129 | throw DeserializationException("JSON object has no topLeft or bottomRight properties or does have extra properties"); 130 | return { 131 | helper()->deserializeSubtype(qMetaTypeId(), map[QStringLiteral("topLeft")], nullptr, "topLeft").template value(), 132 | helper()->deserializeSubtype(qMetaTypeId(), map[QStringLiteral("bottomRight")], nullptr, "bottomRight").template value() 133 | }; 134 | } 135 | 136 | template<> 137 | int LegacyGeomConverter::extract(const QCborValue &value) const 138 | { 139 | if (!value.isInteger()) 140 | throw DeserializationException{"Expected integer, but got type " + QByteArray::number(value.type())}; 141 | return static_cast(value.toInteger()); 142 | } 143 | 144 | template<> 145 | qreal LegacyGeomConverter::extract(const QCborValue &value) const 146 | { 147 | if (!value.isDouble() && !value.isInteger()) 148 | throw DeserializationException{"Expected double, but got type " + QByteArray::number(value.type())}; 149 | return value.toDouble(); 150 | } 151 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/legacygeomconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_LEGACYGEOMCONVERTER_P_H 2 | #define QTJSONSERIALIZER_LEGACYGEOMCONVERTER_P_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace QtJsonSerializer::TypeConverters { 14 | 15 | class Q_JSONSERIALIZER_EXPORT LegacyGeomConverter : public TypeConverter 16 | { 17 | public: 18 | LegacyGeomConverter(); 19 | 20 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(LegacyGeomConverter) 21 | bool canConvert(int metaTypeId) const override; 22 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 23 | QCborValue serialize(int propertyType, const QVariant &value) const override; 24 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 25 | QVariant deserializeJson(int propertyType, const QCborValue &value, QObject *parent) const override; 26 | 27 | private: 28 | template 29 | TSize deserializeSize(const QCborMap &map) const; 30 | template 31 | TPoint deserializePoint(const QCborMap &map) const; 32 | template 33 | TLine deserializeLine(const QCborMap &map) const; 34 | template 35 | TRect deserializeRect(const QCborMap &map) const; 36 | template 37 | TValue extract(const QCborValue &value) const; 38 | }; 39 | 40 | template <> 41 | int LegacyGeomConverter::extract(const QCborValue &value) const; 42 | 43 | template <> 44 | qreal LegacyGeomConverter::extract(const QCborValue &value) const; 45 | 46 | } 47 | 48 | #endif // QTJSONSERIALIZER_LEGACYGEOMCONVERTER_P_H 49 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/listconverter.cpp: -------------------------------------------------------------------------------- 1 | #include "listconverter_p.h" 2 | #include "exception.h" 3 | #include "cborserializer.h" 4 | #include "metawriters.h" 5 | 6 | #include 7 | using namespace QtJsonSerializer; 8 | using namespace QtJsonSerializer::TypeConverters; 9 | using namespace QtJsonSerializer::MetaWriters; 10 | 11 | bool ListConverter::canConvert(int metaTypeId) const 12 | { 13 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 14 | return QVariant{metaTypeId, nullptr}.canConvert(QMetaType::QVariantList) && 15 | SequentialWriter::canWrite(metaTypeId); 16 | #else 17 | return QVariant{QMetaType(metaTypeId), nullptr}.canConvert(QMetaType(QMetaType::QVariantList)) && 18 | SequentialWriter::canWrite(metaTypeId); 19 | #endif 20 | } 21 | 22 | QList ListConverter::allowedCborTags(int metaTypeId) const 23 | { 24 | const auto isSet = SequentialWriter::getInfo(metaTypeId).isSet; 25 | QList tags { 26 | NoTag, 27 | static_cast(CborSerializer::Homogeneous) 28 | }; 29 | if (isSet) 30 | tags.append(static_cast(CborSerializer::Set)); 31 | return tags; 32 | } 33 | 34 | QList ListConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const 35 | { 36 | Q_UNUSED(metaTypeId) 37 | Q_UNUSED(tag) 38 | return {QCborValue::Array}; 39 | } 40 | 41 | QCborValue ListConverter::serialize(int propertyType, const QVariant &value) const 42 | { 43 | const auto info = SequentialWriter::getInfo(propertyType); 44 | 45 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 46 | if (!value.canConvert(QMetaType::QVariantList)) { 47 | #else 48 | if (!value.canConvert(QMetaType(QMetaType::QVariantList))) { 49 | #endif 50 | throw SerializationException(QByteArray("Given type ") + 51 | QMetaTypeName(propertyType) + 52 | QByteArray(" cannot be processed via QSequentialIterable - make shure to register the container type via Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE")); 53 | } 54 | 55 | QCborArray array; 56 | auto index = 0; 57 | for (const auto &element : value.value()) 58 | array.append(helper()->serializeSubtype(info.type, element, "[" + QByteArray::number(index++) + "]")); 59 | if (info.isSet) 60 | return {static_cast(CborSerializer::Set), array}; 61 | else 62 | return array; 63 | } 64 | 65 | QVariant ListConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const 66 | { 67 | //generate the list 68 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 69 | QVariant list{propertyType, nullptr}; 70 | #else 71 | QVariant list{QMetaType(propertyType), nullptr}; 72 | #endif 73 | auto writer = SequentialWriter::getWriter(list); 74 | if (!writer) { 75 | throw DeserializationException(QByteArray("Given type ") + 76 | QMetaTypeName(propertyType) + 77 | QByteArray(" cannot be accessed via QSequentialWriter - make shure to register it via QJsonSerializerBase::registerListConverters or QJsonSerializerBase::registerSetConverters")); 78 | } 79 | 80 | const auto info = writer->info(); 81 | const auto array = (value.isTag() ? value.taggedValue() : value).toArray(); 82 | auto index = 0; 83 | writer->reserve(static_cast(array.size())); 84 | for (auto element : array) 85 | writer->add(helper()->deserializeSubtype(info.type, element, parent, "[" + QByteArray::number(index++) + "]")); 86 | return list; 87 | } 88 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/listconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_LISTCONVERTER_P_H 2 | #define QTJSONSERIALIZER_LISTCONVERTER_P_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | namespace QtJsonSerializer::TypeConverters { 8 | 9 | class Q_JSONSERIALIZER_EXPORT ListConverter : public TypeConverter 10 | { 11 | public: 12 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(ListConverter) 13 | bool canConvert(int metaTypeId) const override; 14 | QList allowedCborTags(int metaTypeId) const override; 15 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 16 | QCborValue serialize(int propertyType, const QVariant &value) const override; 17 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 18 | }; 19 | 20 | } 21 | 22 | #endif // QTJSONSERIALIZER_LISTCONVERTER_P_H 23 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/localeconverter.cpp: -------------------------------------------------------------------------------- 1 | #include "localeconverter_p.h" 2 | #include "exception.h" 3 | #include "cborserializer.h" 4 | 5 | #include 6 | using namespace QtJsonSerializer; 7 | using namespace QtJsonSerializer::TypeConverters; 8 | 9 | bool LocaleConverter::canConvert(int metaTypeId) const 10 | { 11 | return metaTypeId == QMetaType::QLocale; 12 | } 13 | 14 | QList LocaleConverter::allowedCborTags(int metaTypeId) const 15 | { 16 | Q_UNUSED(metaTypeId) 17 | return { 18 | static_cast(CborSerializer::LocaleISO), 19 | static_cast(CborSerializer::LocaleBCP47), 20 | }; 21 | } 22 | 23 | QList LocaleConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const 24 | { 25 | Q_UNUSED(metaTypeId) 26 | Q_UNUSED(tag) 27 | return {QCborValue::String}; 28 | } 29 | 30 | int LocaleConverter::guessType(QCborTag tag, QCborValue::Type dataType) const 31 | { 32 | return allowedCborTags(QMetaType::UnknownType).contains(tag) && 33 | dataType == QCborValue::String; 34 | } 35 | 36 | QCborValue LocaleConverter::serialize(int propertyType, const QVariant &value) const 37 | { 38 | Q_UNUSED(propertyType) 39 | if (helper()->getProperty("useBcp47Locale").toBool()) 40 | return {static_cast(CborSerializer::LocaleBCP47), value.toLocale().bcp47Name()}; 41 | else 42 | return {static_cast(CborSerializer::LocaleISO), value.toLocale().name()}; 43 | } 44 | 45 | QVariant LocaleConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const 46 | { 47 | Q_UNUSED(propertyType) 48 | Q_UNUSED(parent) 49 | 50 | const auto strValue = (value.isTag() ? value.taggedValue() : value).toString(); 51 | QLocale locale{strValue}; 52 | if (locale == QLocale::c()) { 53 | if (strValue.toUpper() == QLatin1Char('C') || 54 | strValue.isEmpty()) 55 | return QLocale::c(); 56 | else 57 | throw DeserializationException("String cannot be interpreted as locale"); 58 | } else 59 | return locale; 60 | } 61 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/localeconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_LOCALECONVERTER_P_H 2 | #define QTJSONSERIALIZER_LOCALECONVERTER_P_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | namespace QtJsonSerializer::TypeConverters { 8 | 9 | class Q_JSONSERIALIZER_EXPORT LocaleConverter : public TypeConverter 10 | { 11 | public: 12 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(LocaleConverter) 13 | bool canConvert(int metaTypeId) const override; 14 | QList allowedCborTags(int metaTypeId) const override; 15 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 16 | int guessType(QCborTag tag, QCborValue::Type dataType) const override; 17 | QCborValue serialize(int propertyType, const QVariant &value) const override; 18 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 19 | }; 20 | 21 | } 22 | 23 | #endif // QTJSONSERIALIZER_LOCALECONVERTER_P_H 24 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/mapconverter.cpp: -------------------------------------------------------------------------------- 1 | #include "mapconverter_p.h" 2 | #include "exception.h" 3 | #include "cborserializer.h" 4 | #include "metawriters.h" 5 | 6 | #include 7 | using namespace QtJsonSerializer; 8 | using namespace QtJsonSerializer::TypeConverters; 9 | using namespace QtJsonSerializer::MetaWriters; 10 | 11 | bool MapConverter::canConvert(int metaTypeId) const 12 | { 13 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 14 | const QVariant tValue{metaTypeId, nullptr}; 15 | return (tValue.canConvert(QMetaType::QVariantMap) || 16 | tValue.canConvert(QMetaType::QVariantHash)) && 17 | AssociativeWriter::canWrite(metaTypeId); 18 | 19 | #else 20 | const QVariant tValue{QMetaType(metaTypeId), nullptr}; 21 | return (tValue.canConvert(QMetaType(QMetaType::QVariantMap)) || 22 | tValue.canConvert(QMetaType(QMetaType::QVariantHash))) && 23 | AssociativeWriter::canWrite(metaTypeId); 24 | 25 | #endif 26 | } 27 | 28 | QList MapConverter::allowedCborTags(int metaTypeId) const 29 | { 30 | Q_UNUSED(metaTypeId) 31 | return {NoTag, static_cast(CborSerializer::ExplicitMap)}; 32 | } 33 | 34 | QList MapConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const 35 | { 36 | Q_UNUSED(metaTypeId) 37 | Q_UNUSED(tag) 38 | return {QCborValue::Map}; 39 | } 40 | 41 | QCborValue MapConverter::serialize(int propertyType, const QVariant &value) const 42 | { 43 | const auto info = AssociativeWriter::getInfo(propertyType); 44 | 45 | // verify is readable 46 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 47 | if (!value.canConvert(QMetaType::QVariantMap) && 48 | !value.canConvert(QMetaType::QVariantHash)) { 49 | #else 50 | if (!value.canConvert(QMetaType(QMetaType::QVariantMap)) && 51 | !value.canConvert(QMetaType(QMetaType::QVariantHash))) { 52 | #endif 53 | throw SerializationException(QByteArray("Given type ") + 54 | QMetaTypeName(propertyType) + 55 | QByteArray(" cannot be processed via QAssociativeIterable - make shure to register the container type via Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE")); 56 | } 57 | 58 | // write from map to cbor 59 | const auto iterable = value.value(); 60 | QCborMap cborMap; 61 | for (auto it = iterable.begin(), end = iterable.end(); it != end; ++it) { 62 | const QByteArray keyStr = "[" + it.key().toString().toUtf8() + "]"; 63 | cborMap.insert(helper()->serializeSubtype(info.keyType, it.key(), keyStr + ".key"), 64 | helper()->serializeSubtype(info.valueType, it.value(), keyStr + ".value")); 65 | } 66 | return cborMap; 67 | } 68 | 69 | QVariant MapConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const 70 | { 71 | //generate the map 72 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 73 | QVariant map{propertyType, nullptr}; 74 | #else 75 | QVariant map{QMetaType(propertyType), nullptr}; 76 | #endif 77 | auto writer = AssociativeWriter::getWriter(map); 78 | if (!writer) { 79 | throw DeserializationException(QByteArray("Given type ") + 80 | QMetaTypeName(propertyType) + 81 | QByteArray(" cannot be accessed via QAssociativeWriter - make shure to register it via QJsonSerializerBase::registerMapConverters")); 82 | } 83 | 84 | // write from cbor into the map 85 | const auto info = writer->info(); 86 | const auto cborMap = (value.isTag() ? value.taggedValue() : value).toMap(); 87 | for (const auto entry : cborMap) { 88 | const QByteArray keyStr = "[" + entry.first.toVariant().toString().toUtf8() + "]"; 89 | writer->add(helper()->deserializeSubtype(info.keyType, entry.first, parent, keyStr + ".key"), 90 | helper()->deserializeSubtype(info.valueType, entry.second, parent, keyStr + ".value")); 91 | } 92 | return map; 93 | } 94 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/mapconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_MAPCONVERTER_P_H 2 | #define QTJSONSERIALIZER_MAPCONVERTER_P_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | namespace QtJsonSerializer::TypeConverters { 8 | 9 | class Q_JSONSERIALIZER_EXPORT MapConverter : public TypeConverter 10 | { 11 | public: 12 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(MapConverter) 13 | bool canConvert(int metaTypeId) const override; 14 | QList allowedCborTags(int metaTypeId) const override; 15 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 16 | QCborValue serialize(int propertyType, const QVariant &value) const override; 17 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 18 | }; 19 | 20 | } 21 | 22 | #endif // QTJSONSERIALIZER_MAPCONVERTER_P_H 23 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/multimapconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_MULTIMAPCONVERTER_P_H 2 | #define QTJSONSERIALIZER_MULTIMAPCONVERTER_P_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | namespace QtJsonSerializer::TypeConverters { 8 | 9 | class Q_JSONSERIALIZER_EXPORT MultiMapConverter : public TypeConverter 10 | { 11 | public: 12 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(MultiMapConverter) 13 | bool canConvert(int metaTypeId) const override; 14 | QList allowedCborTags(int metaTypeId) const override; 15 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 16 | QCborValue serialize(int propertyType, const QVariant &value) const override; 17 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 18 | }; 19 | 20 | } 21 | 22 | #endif // QTJSONSERIALIZER_MULTIMAPCONVERTER_P_H 23 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/objectconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_OBJECTCONVERTER_P_H 2 | #define QTJSONSERIALIZER_OBJECTCONVERTER_P_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | #include 8 | 9 | namespace QtJsonSerializer::TypeConverters { 10 | 11 | class Q_JSONSERIALIZER_EXPORT ObjectConverter : public TypeConverter 12 | { 13 | public: 14 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(ObjectConverter) 15 | bool canConvert(int metaTypeId) const override; 16 | QList allowedCborTags(int metaTypeId) const override; 17 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 18 | int guessType(QCborTag tag, QCborValue::Type dataType) const override; 19 | QCborValue serialize(int propertyType, const QVariant &value) const override; 20 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 21 | 22 | private: 23 | bool polyMetaObject(QObject *object) const; 24 | 25 | QObject *deserializeGenericObject(const QCborArray &value, QObject *parent) const; 26 | QObject *deserializeConstructedObject(const QCborValue &value, QObject *parent) const; 27 | void deserializeProperties(const QMetaObject *metaObject, QObject *object, const QCborMap &value, bool isPoly = false) const; 28 | }; 29 | 30 | Q_DECLARE_LOGGING_CATEGORY(logObjConverter) 31 | 32 | } 33 | 34 | #endif // QTJSONSERIALIZER_OBJECTCONVERTER_P_H 35 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/pairconverter.cpp: -------------------------------------------------------------------------------- 1 | #include "pairconverter_p.h" 2 | #include "exception.h" 3 | #include "cborserializer.h" 4 | 5 | #include 6 | using namespace QtJsonSerializer; 7 | using namespace QtJsonSerializer::TypeConverters; 8 | 9 | bool PairConverter::canConvert(int metaTypeId) const 10 | { 11 | const auto extractor = helper()->extractor(metaTypeId); 12 | return extractor && extractor->baseType() == "pair"; 13 | } 14 | 15 | QList PairConverter::allowedCborTags(int metaTypeId) const 16 | { 17 | Q_UNUSED(metaTypeId) 18 | return {NoTag, static_cast(CborSerializer::Pair)}; 19 | } 20 | 21 | QList PairConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const 22 | { 23 | Q_UNUSED(metaTypeId) 24 | Q_UNUSED(tag) 25 | return {QCborValue::Array}; 26 | } 27 | 28 | QCborValue PairConverter::serialize(int propertyType, const QVariant &value) const 29 | { 30 | const auto extractor = helper()->extractor(propertyType); 31 | if (!extractor) { 32 | throw SerializationException(QByteArray("Failed to get extractor for type ") + 33 | QMetaTypeName(propertyType) + 34 | QByteArray(". Make shure to register pair types via QJsonSerializer::registerPairConverters")); 35 | } 36 | 37 | const auto subTypes = extractor->subtypes(); 38 | return { 39 | static_cast(CborSerializer::Pair), 40 | QCborArray { 41 | helper()->serializeSubtype(subTypes[0], extractor->extract(value, 0), "first"), 42 | helper()->serializeSubtype(subTypes[1], extractor->extract(value, 1), "second") 43 | } 44 | }; 45 | } 46 | 47 | QVariant PairConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const 48 | { 49 | const auto extractor = helper()->extractor(propertyType); 50 | if (!extractor) { 51 | throw DeserializationException(QByteArray("Failed to get extractor for type ") + 52 | QMetaTypeName(propertyType) + 53 | QByteArray(". Make shure to register pair types via QJsonSerializer::registerPairConverters")); 54 | } 55 | 56 | const auto array = (value.isTag() ? value.taggedValue() : value).toArray(); 57 | if (array.size() != 2) 58 | throw DeserializationException("CBOR/JSON array must have exactly 2 elements to be read as a pair"); 59 | 60 | const auto subTypes = extractor->subtypes(); 61 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 62 | QVariant resPair{propertyType, nullptr}; 63 | #else 64 | QVariant resPair{QMetaType(propertyType), nullptr}; 65 | #endif 66 | extractor->emplace(resPair, helper()->deserializeSubtype(subTypes[0], array[0], parent, "first"), 0); 67 | extractor->emplace(resPair, helper()->deserializeSubtype(subTypes[1], array[1], parent, "second"), 1); 68 | return resPair; 69 | } 70 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/pairconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_PAIRCONVERTER_P_H 2 | #define QTJSONSERIALIZER_PAIRCONVERTER_P_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | namespace QtJsonSerializer::TypeConverters { 8 | 9 | class Q_JSONSERIALIZER_EXPORT PairConverter : public TypeConverter 10 | { 11 | public: 12 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(PairConverter) 13 | bool canConvert(int metaTypeId) const override; 14 | QList allowedCborTags(int metaTypeId) const override; 15 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 16 | QCborValue serialize(int propertyType, const QVariant &value) const override; 17 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 18 | }; 19 | 20 | } 21 | 22 | #endif // QTJSONSERIALIZER_PAIRCONVERTER_P_H 23 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/smartpointerconverter.cpp: -------------------------------------------------------------------------------- 1 | #include "smartpointerconverter_p.h" 2 | #include "exception.h" 3 | using namespace QtJsonSerializer; 4 | using namespace QtJsonSerializer::TypeConverters; 5 | 6 | bool SmartPointerConverter::canConvert(int metaTypeId) const 7 | { 8 | const auto extractor = helper()->extractor(metaTypeId); 9 | return extractor && (extractor->baseType() == "pointer" || 10 | extractor->baseType() == "qpointer"); 11 | } 12 | 13 | QList SmartPointerConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const 14 | { 15 | Q_UNUSED(metaTypeId) 16 | Q_UNUSED(tag) 17 | QList types; 18 | const auto metaEnum = QMetaEnum::fromType(); 19 | types.reserve(metaEnum.keyCount()); 20 | for (auto i = 0; i < metaEnum.keyCount(); ++i) { 21 | if (const auto value = metaEnum.value(i); value != QCborValue::Invalid) 22 | types.append(static_cast(value)); 23 | } 24 | return types; 25 | } 26 | 27 | QCborValue SmartPointerConverter::serialize(int propertyType, const QVariant &value) const 28 | { 29 | const auto extractor = helper()->extractor(propertyType); 30 | if (!extractor) { 31 | throw SerializationException(QByteArray("Failed to get extractor for type ") + 32 | QMetaTypeName(propertyType) + 33 | QByteArray(". Make shure to register std::optional types via QJsonSerializer::registerPointerConverters")); 34 | } 35 | 36 | return helper()->serializeSubtype(extractor->subtypes()[0], 37 | extractor->extract(value), 38 | "data"); 39 | } 40 | 41 | QVariant SmartPointerConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const 42 | { 43 | const auto extractor = helper()->extractor(propertyType); 44 | if (!extractor) { 45 | throw DeserializationException(QByteArray("Failed to get extractor for type ") + 46 | QMetaTypeName(propertyType) + 47 | QByteArray(". Make shure to register std::optional types via QJsonSerializer::registerPointerConverters")); 48 | } 49 | 50 | auto result = helper()->deserializeSubtype(extractor->subtypes()[0], 51 | value, 52 | extractor->baseType() == "qpointer" ? parent : nullptr, 53 | "data"); 54 | extractor->emplace(result, result); 55 | return result; 56 | } 57 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/smartpointerconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_SMARTPOINTERCONVERTER_H 2 | #define QTJSONSERIALIZER_SMARTPOINTERCONVERTER_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | namespace QtJsonSerializer::TypeConverters { 8 | 9 | class Q_JSONSERIALIZER_EXPORT SmartPointerConverter : public TypeConverter 10 | { 11 | public: 12 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(SmartPointerConverter) 13 | bool canConvert(int metaTypeId) const override; 14 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 15 | QCborValue serialize(int propertyType, const QVariant &value) const override; 16 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 17 | }; 18 | 19 | } 20 | 21 | #endif // QTJSONSERIALIZER_SMARTPOINTERCONVERTER_H 22 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/stdchronodurationconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_STDCHRONODURATIONCONVERTER_P_H 2 | #define QTJSONSERIALIZER_STDCHRONODURATIONCONVERTER_P_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | #include "exception.h" 7 | 8 | #include 9 | 10 | namespace QtJsonSerializer::TypeConverters { 11 | 12 | class Q_JSONSERIALIZER_EXPORT StdChronoDurationConverter : public TypeConverter 13 | { 14 | public: 15 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(StdChronoDurationConverter) 16 | bool canConvert(int metaTypeId) const override; 17 | QList allowedCborTags(int metaTypeId) const override; 18 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 19 | int guessType(QCborTag tag, QCborValue::Type dataType) const override; 20 | QCborValue serialize(int propertyType, const QVariant &value) const override; 21 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 22 | 23 | private: 24 | using MetaDuration = std::variant; 30 | 31 | QCborTag tagForType(int metaTypeId) const; 32 | MetaDuration parseValue(int propertyType, const QCborValue &value, const SerializationHelper *localHelper) const; 33 | 34 | template 35 | TDuration create(const QCborValue &value) const { 36 | return TDuration{static_cast((value.isTag() ? value.taggedValue() : value).toInteger())}; 37 | } 38 | 39 | template 40 | TDuration cast(const MetaDuration &duration) const { 41 | return std::visit([](const auto &dur) { 42 | if (std::is_convertible_v, TDuration>) 43 | return std::chrono::duration_cast(dur); 44 | else { 45 | throw DeserializationException{QByteArray{"Unable to upcast from deserialized "} + 46 | QMetaTypeName(qMetaTypeId>()) + 47 | QByteArray{" to the requested "} + 48 | QMetaTypeName(qMetaTypeId())}; 49 | } 50 | }, duration); 51 | } 52 | }; 53 | 54 | } 55 | 56 | #endif // QTJSONSERIALIZER_STDCHRONODURATIONCONVERTER_P_H 57 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/stdoptionalconverter.cpp: -------------------------------------------------------------------------------- 1 | #include "stdoptionalconverter_p.h" 2 | #include "exception.h" 3 | 4 | #include 5 | using namespace QtJsonSerializer; 6 | using namespace QtJsonSerializer::TypeConverters; 7 | 8 | // WORKAROUND for now, nullptr is used instead of nullopt, as nullopt_t cannot be registered as metatype 9 | 10 | bool StdOptionalConverter::canConvert(int metaTypeId) const 11 | { 12 | const auto extractor = helper()->extractor(metaTypeId); 13 | return extractor && extractor->baseType() == "optional"; 14 | } 15 | 16 | QList StdOptionalConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const 17 | { 18 | Q_UNUSED(metaTypeId) 19 | Q_UNUSED(tag) 20 | QList types; 21 | const auto metaEnum = QMetaEnum::fromType(); 22 | types.reserve(metaEnum.keyCount()); 23 | for (auto i = 0; i < metaEnum.keyCount(); ++i) { 24 | if (const auto value = metaEnum.value(i); value != QCborValue::Invalid) 25 | types.append(static_cast(value)); 26 | } 27 | return types; 28 | } 29 | 30 | QCborValue StdOptionalConverter::serialize(int propertyType, const QVariant &value) const 31 | { 32 | const auto extractor = helper()->extractor(propertyType); 33 | if (!extractor) { 34 | throw SerializationException(QByteArray("Failed to get extractor for type ") + 35 | QMetaTypeName(propertyType) + 36 | QByteArray(". Make shure to register std::optional types via QJsonSerializer::registerOptionalConverters")); 37 | } 38 | 39 | const auto cValue = extractor->extract(value); 40 | if (cValue.userType() == QMetaType::Nullptr) 41 | return QCborValue::Null; 42 | else 43 | return helper()->serializeSubtype(extractor->subtypes()[0], cValue, "value"); 44 | } 45 | 46 | QVariant StdOptionalConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const 47 | { 48 | const auto extractor = helper()->extractor(propertyType); 49 | if (!extractor) { 50 | throw DeserializationException(QByteArray("Failed to get extractor for type ") + 51 | QMetaTypeName(propertyType) + 52 | QByteArray(". Make shure to register std::optional types via QJsonSerializer::registerOptionalConverters")); 53 | } 54 | 55 | QVariant result; 56 | if (value.isNull()) 57 | result = QVariant::fromValue(nullptr); 58 | else 59 | result = helper()->deserializeSubtype(extractor->subtypes()[0], value, parent, "value"); 60 | extractor->emplace(result, result); 61 | return result; 62 | } 63 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/stdoptionalconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_STDOPTIONALCONVERTER_P_H 2 | #define QTJSONSERIALIZER_STDOPTIONALCONVERTER_P_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | namespace QtJsonSerializer::TypeConverters { 8 | 9 | class Q_JSONSERIALIZER_EXPORT StdOptionalConverter : public TypeConverter 10 | { 11 | public: 12 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(StdOptionalConverter) 13 | bool canConvert(int metaTypeId) const override; 14 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 15 | QCborValue serialize(int propertyType, const QVariant &value) const override; 16 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 17 | }; 18 | 19 | } 20 | 21 | #endif // QTJSONSERIALIZER_STDOPTIONALCONVERTER_P_H 22 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/stdtupleconverter.cpp: -------------------------------------------------------------------------------- 1 | #include "stdtupleconverter_p.h" 2 | #include "exception.h" 3 | #include "cborserializer.h" 4 | 5 | #include 6 | using namespace QtJsonSerializer; 7 | using namespace QtJsonSerializer::TypeConverters; 8 | 9 | bool StdTupleConverter::canConvert(int metaTypeId) const 10 | { 11 | const auto extractor = helper()->extractor(metaTypeId); 12 | return extractor && extractor->baseType() == "tuple"; 13 | } 14 | 15 | QList StdTupleConverter::allowedCborTags(int metaTypeId) const 16 | { 17 | Q_UNUSED(metaTypeId) 18 | return {static_cast(CborSerializer::Tuple)}; 19 | } 20 | 21 | QList StdTupleConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const 22 | { 23 | Q_UNUSED(metaTypeId) 24 | Q_UNUSED(tag) 25 | return {QCborValue::Array}; 26 | } 27 | 28 | QCborValue StdTupleConverter::serialize(int propertyType, const QVariant &value) const 29 | { 30 | const auto extractor = helper()->extractor(propertyType); 31 | if (!extractor) { 32 | throw SerializationException(QByteArray("Failed to get extractor for type ") + 33 | QMetaTypeName(propertyType) + 34 | QByteArray(". Make shure to register std::tuple types via QJsonSerializer::registerTupleConverters")); 35 | } 36 | 37 | const auto metaTypes = extractor->subtypes(); 38 | QCborArray array; 39 | auto max = metaTypes.size(); 40 | for(auto i = 0; i < max; ++i) 41 | array.append(helper()->serializeSubtype(metaTypes[i], extractor->extract(value, i), "<" + QByteArray::number(i) + ">")); 42 | return {static_cast(CborSerializer::Tuple), array}; 43 | } 44 | 45 | QVariant StdTupleConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const 46 | { 47 | const auto extractor = helper()->extractor(propertyType); 48 | if (!extractor) { 49 | throw DeserializationException(QByteArray("Failed to get extractor for type ") + 50 | QMetaTypeName(propertyType) + 51 | QByteArray(". Make shure to register std::tuple types via QJsonSerializer::registerTupleConverters")); 52 | } 53 | 54 | const auto metaTypes = extractor->subtypes(); 55 | const auto cArray = (value.isTag() ? value.taggedValue() : value).toArray(); 56 | if (cArray.size() != metaTypes.size()) 57 | throw DeserializationException{"Expected array with " + QByteArray::number(metaTypes.size()) + 58 | " elements, but got " + QByteArray::number(cArray.size()) + " instead"}; 59 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 60 | QVariant tuple{propertyType, nullptr}; 61 | #else 62 | QVariant tuple{QMetaType(propertyType), nullptr}; 63 | #endif 64 | auto max = metaTypes.size(); 65 | for(auto i = 0; i < max; ++i) 66 | extractor->emplace(tuple, helper()->deserializeSubtype(metaTypes[i], cArray[i], parent, "<" + QByteArray::number(i) + ">"), i); 67 | return tuple; 68 | } 69 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/stdtupleconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_STDTUPLECONVERTER_P_H 2 | #define QTJSONSERIALIZER_STDTUPLECONVERTER_P_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | namespace QtJsonSerializer::TypeConverters { 8 | 9 | class Q_JSONSERIALIZER_EXPORT StdTupleConverter : public TypeConverter 10 | { 11 | public: 12 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(StdTupleConverter) 13 | bool canConvert(int metaTypeId) const override; 14 | QList allowedCborTags(int metaTypeId) const override; 15 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 16 | QCborValue serialize(int propertyType, const QVariant &value) const override; 17 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 18 | }; 19 | 20 | } 21 | 22 | #endif // QTJSONSERIALIZER_STDTUPLECONVERTER_P_H 23 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/stdvariantconverter.cpp: -------------------------------------------------------------------------------- 1 | #include "stdvariantconverter_p.h" 2 | #include "exception.h" 3 | using namespace QtJsonSerializer; 4 | using namespace QtJsonSerializer::TypeConverters; 5 | 6 | bool StdVariantConverter::canConvert(int metaTypeId) const 7 | { 8 | const auto extractor = helper()->extractor(metaTypeId); 9 | return extractor && extractor->baseType() == "variant"; 10 | } 11 | 12 | QList StdVariantConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const 13 | { 14 | Q_UNUSED(metaTypeId) 15 | Q_UNUSED(tag) 16 | QList types; 17 | const auto metaEnum = QMetaEnum::fromType(); 18 | types.reserve(metaEnum.keyCount()); 19 | for (auto i = 0; i < metaEnum.keyCount(); ++i) { 20 | if (const auto value = metaEnum.value(i); value != QCborValue::Invalid) 21 | types.append(static_cast(value)); 22 | } 23 | return types; 24 | } 25 | 26 | QCborValue StdVariantConverter::serialize(int propertyType, const QVariant &value) const 27 | { 28 | const auto extractor = helper()->extractor(propertyType); 29 | if (!extractor) { 30 | throw SerializationException(QByteArray("Failed to get extractor for type ") + 31 | QMetaTypeName(propertyType) + 32 | QByteArray(". Make shure to register std::variant types via QJsonSerializer::registerVariantConverters")); 33 | } 34 | 35 | const auto metaTypes = extractor->subtypes(); 36 | const auto cValue = extractor->extract(value); 37 | const auto mIndex = metaTypes.indexOf(cValue.userType()); 38 | if (mIndex == -1) { 39 | throw SerializationException(QByteArray("Invalid value given for type ") + 40 | QMetaTypeName(propertyType) + 41 | QByteArray(" - was ") + 42 | value.typeName() + 43 | QByteArray(", which is not a type of the given variant")); 44 | } 45 | return helper()->serializeSubtype(metaTypes[mIndex], cValue, QByteArray{"<"} + QMetaTypeName(metaTypes[mIndex]) + QByteArray{">"}); 46 | } 47 | 48 | QVariant StdVariantConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const 49 | { 50 | const auto extractor = helper()->extractor(propertyType); 51 | if (!extractor) { 52 | throw DeserializationException(QByteArray("Failed to get extractor for type ") + 53 | QMetaTypeName(propertyType) + 54 | QByteArray(". Make shure to register std::variant types via QJsonSerializer::registerVariantConverters")); 55 | } 56 | 57 | // try all types until one succeeds 58 | for (auto metaType : extractor->subtypes()) { 59 | // ignore exceptions and try with the next type 60 | try { 61 | auto result = helper()->deserializeSubtype(metaType, value, parent, QByteArray{"<"} + QMetaTypeName(metaType) + QByteArray{">"}); 62 | extractor->emplace(result, result); 63 | return result; 64 | } catch (DeserializationException &) {} 65 | } 66 | 67 | throw DeserializationException(QByteArray("Failed to deserialze value to ") + 68 | QMetaTypeName(propertyType) + 69 | QByteArray(" because all possible sub-type converters rejected the passed value.")); 70 | } 71 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/stdvariantconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_STDVARIANTCONVERTER_P_H 2 | #define QTJSONSERIALIZER_STDVARIANTCONVERTER_P_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | namespace QtJsonSerializer::TypeConverters { 8 | 9 | class Q_JSONSERIALIZER_EXPORT StdVariantConverter : public TypeConverter 10 | { 11 | public: 12 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(StdVariantConverter) 13 | bool canConvert(int metaTypeId) const override; 14 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 15 | QCborValue serialize(int propertyType, const QVariant &value) const override; 16 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 17 | }; 18 | 19 | } 20 | 21 | #endif // QTJSONSERIALIZER_STDVARIANTCONVERTER_P_H 22 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/typeconverters.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/bitarrayconverter_p.h \ 3 | $$PWD/bytearrayconverter_p.h \ 4 | $$PWD/cborconverter_p.h \ 5 | $$PWD/datetimeconverter_p.h \ 6 | $$PWD/enumconverter_p.h \ 7 | $$PWD/gadgetconverter_p.h \ 8 | $$PWD/geomconverter_p.h \ 9 | $$PWD/legacygeomconverter_p.h \ 10 | $$PWD/listconverter_p.h \ 11 | $$PWD/localeconverter_p.h \ 12 | $$PWD/mapconverter_p.h \ 13 | $$PWD/multimapconverter_p.h \ 14 | $$PWD/objectconverter_p.h \ 15 | $$PWD/pairconverter_p.h \ 16 | $$PWD/smartpointerconverter_p.h \ 17 | $$PWD/stdchronodurationconverter_p.h \ 18 | $$PWD/stdoptionalconverter_p.h \ 19 | $$PWD/stdtupleconverter_p.h \ 20 | $$PWD/stdvariantconverter_p.h \ 21 | $$PWD/versionnumberconverter_p.h 22 | 23 | SOURCES += \ 24 | $$PWD/bitarrayconverter.cpp \ 25 | $$PWD/bytearrayconverter.cpp \ 26 | $$PWD/cborconverter.cpp \ 27 | $$PWD/datetimeconverter.cpp \ 28 | $$PWD/enumconverter.cpp \ 29 | $$PWD/gadgetconverter.cpp \ 30 | $$PWD/geomconverter.cpp \ 31 | $$PWD/legacygeomconverter.cpp \ 32 | $$PWD/listconverter.cpp \ 33 | $$PWD/localeconverter.cpp \ 34 | $$PWD/mapconverter.cpp \ 35 | $$PWD/multimapconverter.cpp \ 36 | $$PWD/objectconverter.cpp \ 37 | $$PWD/pairconverter.cpp \ 38 | $$PWD/smartpointerconverter.cpp \ 39 | $$PWD/stdchronodurationconverter.cpp \ 40 | $$PWD/stdoptionalconverter.cpp \ 41 | $$PWD/stdtupleconverter.cpp \ 42 | $$PWD/stdvariantconverter.cpp \ 43 | $$PWD/versionnumberconverter.cpp 44 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/versionnumberconverter.cpp: -------------------------------------------------------------------------------- 1 | #include "versionnumberconverter_p.h" 2 | #include "exception.h" 3 | #include "cborserializer.h" 4 | 5 | #include 6 | using namespace QtJsonSerializer; 7 | using namespace QtJsonSerializer::TypeConverters; 8 | 9 | Q_LOGGING_CATEGORY(QtJsonSerializer::TypeConverters::logVersionConverter, "qt.jsonserializer.converter.versionnumber") 10 | 11 | bool VersionNumberConverter::canConvert(int metaTypeId) const 12 | { 13 | return metaTypeId == qMetaTypeId(); 14 | } 15 | 16 | QList VersionNumberConverter::allowedCborTags(int metaTypeId) const 17 | { 18 | Q_UNUSED(metaTypeId) 19 | return {static_cast(CborSerializer::VersionNumber)}; 20 | } 21 | 22 | QList VersionNumberConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const 23 | { 24 | Q_UNUSED(metaTypeId) 25 | Q_UNUSED(tag) 26 | return {QCborValue::Array, QCborValue::String}; 27 | } 28 | 29 | int VersionNumberConverter::guessType(QCborTag tag, QCborValue::Type dataType) const 30 | { 31 | if (tag == static_cast(CborSerializer::VersionNumber) && 32 | allowedCborTypes(QMetaType::UnknownType, tag).contains(dataType)) 33 | return qMetaTypeId(); 34 | else 35 | return QMetaType::UnknownType; 36 | } 37 | 38 | QCborValue VersionNumberConverter::serialize(int propertyType, const QVariant &value) const 39 | { 40 | Q_UNUSED(propertyType) 41 | const auto version = value.value(); 42 | if (helper()->getProperty("versionAsString").toBool()) 43 | return {static_cast(CborSerializer::VersionNumber), version.toString()}; 44 | else { 45 | QCborArray array; 46 | for (const auto segment : version.segments()) 47 | array.append(segment); 48 | return {static_cast(CborSerializer::VersionNumber), array}; 49 | } 50 | } 51 | 52 | QVariant VersionNumberConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const 53 | { 54 | Q_UNUSED(propertyType) 55 | Q_UNUSED(parent) 56 | const auto cValue = (value.isTag() ? value.taggedValue() : value); 57 | if (cValue.type() == QCborValue::Array) { 58 | const auto cArray = cValue.toArray(); 59 | QVector segments; 60 | segments.reserve(static_cast(cArray.size())); 61 | auto i = 0; 62 | for (const auto cElem : cArray) { 63 | if (!cElem.isInteger()) { 64 | throw DeserializationException{"Segment at position " + QByteArray::number(i) + 65 | " is not an integer - a version number must be integers only!"}; 66 | } 67 | segments.append(static_cast(cElem.toInteger())); 68 | ++i; 69 | } 70 | return QVariant::fromValue(QVersionNumber{std::move(segments)}); 71 | } else if (cValue.type() == QCborValue::String) { 72 | const auto strValue = cValue.toString(); 73 | if (!strValue.isEmpty()) { 74 | int suffixIndex = -1; 75 | const auto version = QVersionNumber::fromString(strValue, &suffixIndex); 76 | if (version.isNull()) 77 | throw DeserializationException("Invalid version number, no segments found"); 78 | if (suffixIndex < strValue.size()) 79 | qCWarning(logVersionConverter) << "Parsed QVersionNumber with suffix - suffixes are discarded!"; 80 | return QVariant::fromValue(version); 81 | } else 82 | return QVariant::fromValue(QVersionNumber{}); 83 | } else 84 | throw DeserializationException{"Invalid type id"}; 85 | } 86 | -------------------------------------------------------------------------------- /src/jsonserializer/typeconverters/versionnumberconverter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONSERIALIZER_VERSIONNUMBERCONVERTER_P_H 2 | #define QTJSONSERIALIZER_VERSIONNUMBERCONVERTER_P_H 3 | 4 | #include "qtjsonserializer_global.h" 5 | #include "typeconverter.h" 6 | 7 | #include 8 | 9 | namespace QtJsonSerializer::TypeConverters { 10 | 11 | class Q_JSONSERIALIZER_EXPORT VersionNumberConverter : public TypeConverter 12 | { 13 | public: 14 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(VersionNumberConverter) 15 | bool canConvert(int metaTypeId) const override; 16 | QList allowedCborTags(int metaTypeId) const override; 17 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 18 | int guessType(QCborTag tag, QCborValue::Type dataType) const override; 19 | QCborValue serialize(int propertyType, const QVariant &value) const override; 20 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 21 | }; 22 | 23 | Q_DECLARE_LOGGING_CATEGORY(logVersionConverter) 24 | 25 | } 26 | 27 | #endif // QTJSONSERIALIZER_VERSIONNUMBERCONVERTER_P_H 28 | -------------------------------------------------------------------------------- /src/src.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += jsonserializer 4 | 5 | QMAKE_EXTRA_TARGETS += run-tests 6 | -------------------------------------------------------------------------------- /sync.profile: -------------------------------------------------------------------------------- 1 | %modules = ( 2 | "QtJsonSerializer" => "$basedir/src/jsonserializer", 3 | ); 4 | 5 | $publicclassregexp = "^QtJsonSerializer::(?!__private::|MetaWriters::Implementations::|TypeExtractors::|Exception).+"; 6 | -------------------------------------------------------------------------------- /tests/auto/auto.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += cmake jsonserializer 4 | 5 | cmake.CONFIG += no_run-tests_target 6 | prepareRecursiveTarget(run-tests) 7 | QMAKE_EXTRA_TARGETS += run-tests 8 | -------------------------------------------------------------------------------- /tests/auto/cmake/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required(VERSION 2.8) 3 | 4 | project(qmake_cmake_files) 5 | 6 | enable_testing() 7 | 8 | find_package(Qt5Core REQUIRED) 9 | 10 | include("${_Qt5CTestMacros}") 11 | 12 | test_module_includes( 13 | JsonSerializer QJsonSerializer 14 | ) 15 | -------------------------------------------------------------------------------- /tests/auto/cmake/cmake.pro: -------------------------------------------------------------------------------- 1 | 2 | # Cause make to do nothing. 3 | TEMPLATE = subdirs 4 | 5 | CMAKE_QT_MODULES_UNDER_TEST = jsonserializer 6 | 7 | CONFIG += ctest_testcase 8 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/BitArrayConverterTest/BitArrayConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_bitarrayconverter 8 | 9 | include(../convlib.pri) 10 | 11 | SOURCES += \ 12 | tst_bitarrayconverter.cpp 13 | 14 | include(../../testrun.pri) 15 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/BitArrayConverterTest/tst_bitarrayconverter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "typeconvertertestbase.h" 5 | 6 | #include 7 | using namespace QtJsonSerializer; 8 | using namespace QtJsonSerializer::TypeConverters; 9 | 10 | class BitarrayConverterTest : public TypeConverterTestBase 11 | { 12 | Q_OBJECT 13 | 14 | protected: 15 | TypeConverter *converter() override; 16 | void addConverterData() override; 17 | void addMetaData() override; 18 | void addCommonSerData() override; 19 | 20 | private: 21 | BitArrayConverter _converter; 22 | 23 | QBitArray generateAlternating(int len, int width = 2) const; 24 | }; 25 | 26 | TypeConverter *BitarrayConverterTest::converter() 27 | { 28 | return &_converter; 29 | } 30 | 31 | void BitarrayConverterTest::addConverterData() 32 | { 33 | QTest::newRow("bitarray") << static_cast(TypeConverter::Standard); 34 | } 35 | 36 | void BitarrayConverterTest::addMetaData() 37 | { 38 | QTest::newRow("tagged") << static_cast(QMetaType::QBitArray) 39 | << static_cast(CborSerializer::BitArray) 40 | << QCborValue::ByteArray 41 | << true 42 | << TypeConverter::DeserializationCapabilityResult::Positive; 43 | QTest::newRow("guessed") << static_cast(QMetaType::UnknownType) 44 | << static_cast(CborSerializer::BitArray) 45 | << QCborValue::ByteArray 46 | << false 47 | << TypeConverter::DeserializationCapabilityResult::Guessed; 48 | QTest::newRow("invalid.type") << static_cast(QMetaType::QByteArray) 49 | << static_cast(CborSerializer::BitArray) 50 | << QCborValue::ByteArray 51 | << false 52 | << TypeConverter::DeserializationCapabilityResult::Negative; 53 | QTest::newRow("invalid.tag") << static_cast(QMetaType::QBitArray) 54 | << static_cast(QCborKnownTags::ExpectedBase64url) 55 | << QCborValue::ByteArray 56 | << true 57 | << TypeConverter::DeserializationCapabilityResult::WrongTag; 58 | QTest::newRow("invalid.data") << static_cast(QMetaType::QBitArray) 59 | << static_cast(CborSerializer::BitArray) 60 | << QCborValue::String 61 | << true 62 | << TypeConverter::DeserializationCapabilityResult::Negative; 63 | } 64 | 65 | void BitarrayConverterTest::addCommonSerData() 66 | { 67 | QTest::newRow("aligned") << QVariantHash{} 68 | << TestQ{} 69 | << static_cast(nullptr) 70 | << static_cast(QMetaType::QBitArray) 71 | << QVariant{generateAlternating(24)} 72 | << QCborValue{static_cast(CborSerializer::BitArray), QByteArray("\x00UUU", 4)} 73 | << QJsonValue{QStringLiteral("AFVVVQ")}; 74 | QTest::newRow("unaligned") << QVariantHash{} 75 | << TestQ{} 76 | << static_cast(nullptr) 77 | << static_cast(QMetaType::QBitArray) 78 | << QVariant{generateAlternating(28, 4)} 79 | << QCborValue{static_cast(CborSerializer::BitArray), QByteArray("\x04\x11\x11\x11\x01", 5)} 80 | << QJsonValue{QStringLiteral("BBEREQE")}; 81 | QTest::newRow("empty") << QVariantHash{} 82 | << TestQ{} 83 | << static_cast(nullptr) 84 | << static_cast(QMetaType::QBitArray) 85 | << QVariant{QBitArray{}} 86 | << QCborValue{static_cast(CborSerializer::BitArray), QByteArray{}} 87 | << QJsonValue{QStringLiteral("")}; 88 | } 89 | 90 | QBitArray BitarrayConverterTest::generateAlternating(int len, int width) const 91 | { 92 | QBitArray array(len, false); 93 | for (auto i = 0; i < len; i += width) 94 | array.setBit(i, true); 95 | return array; 96 | } 97 | 98 | QTEST_MAIN(BitarrayConverterTest) 99 | 100 | #include "tst_bitarrayconverter.moc" 101 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/BytearrayConverterTest/BytearrayConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_bytearrayconverter 8 | 9 | include(../convlib.pri) 10 | 11 | SOURCES += \ 12 | tst_bytearrayconverter.cpp 13 | 14 | include(../../testrun.pri) 15 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/CborConverterTest/CborConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_cborconverter 8 | 9 | include(../convlib.pri) 10 | 11 | SOURCES += \ 12 | tst_cborconverter.cpp 13 | 14 | include(../../testrun.pri) 15 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/ChronoDurationConverterTest/ChronoDurationConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_chronodurationconverter 8 | 9 | include(../convlib.pri) 10 | 11 | SOURCES += \ 12 | tst_chronodurationconverter.cpp 13 | 14 | include(../../testrun.pri) 15 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/DateTimeConverterTest/DateTimeConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_datetimeconverter 8 | 9 | include(../convlib.pri) 10 | 11 | SOURCES += \ 12 | tst_datetimeconverter.cpp 13 | 14 | include(../../testrun.pri) 15 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/EnumConverterTest/EnumConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_enumconverter 8 | 9 | include(../convlib.pri) 10 | 11 | SOURCES += \ 12 | testclass.cpp \ 13 | tst_enumconverter.cpp 14 | 15 | include(../../testrun.pri) 16 | 17 | HEADERS += \ 18 | testclass.h 19 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/EnumConverterTest/testclass.cpp: -------------------------------------------------------------------------------- 1 | #include "testclass.h" 2 | 3 | TestClass::TestClass(QObject *parent) : QObject(parent) 4 | { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/EnumConverterTest/testclass.h: -------------------------------------------------------------------------------- 1 | #ifndef TESTCLASS_H 2 | #define TESTCLASS_H 3 | 4 | #include 5 | 6 | class TestClass : public QObject 7 | { 8 | Q_OBJECT 9 | 10 | public: 11 | enum class TestEnum { 12 | Key0, 13 | Key1, 14 | Key4 = 4 15 | }; 16 | Q_ENUM(TestEnum) 17 | 18 | enum class TestFlag { 19 | Flag1 = 0x01, 20 | Flag2 = 0x02, 21 | Flag4 = 0x04 22 | }; 23 | Q_DECLARE_FLAGS(TestFlags, TestFlag) 24 | Q_FLAG(TestFlags) 25 | 26 | explicit TestClass(QObject *parent = nullptr); 27 | }; 28 | 29 | Q_DECLARE_OPERATORS_FOR_FLAGS(TestClass::TestFlags) 30 | 31 | #endif // TESTCLASS_H 32 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/GadgetConverterTest/GadgetConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_gadgetconverter 8 | 9 | include(../convlib.pri) 10 | 11 | HEADERS += \ 12 | testgadget.h 13 | 14 | SOURCES += \ 15 | tst_gadgetconverter.cpp \ 16 | testgadget.cpp 17 | 18 | include(../../testrun.pri) 19 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/GadgetConverterTest/testgadget.cpp: -------------------------------------------------------------------------------- 1 | #include "testgadget.h" 2 | 3 | TestGadget::TestGadget(int key, double value, int zhidden) : 4 | key(key), 5 | value(value), 6 | zhidden(zhidden) 7 | {} 8 | 9 | bool TestGadget::operator==(const TestGadget &other) const 10 | { 11 | // exclude unstored properties 12 | return key == other.key && 13 | qFuzzyCompare(value, other.value) && 14 | zhidden == other.zhidden; 15 | } 16 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/GadgetConverterTest/testgadget.h: -------------------------------------------------------------------------------- 1 | #ifndef TESTGADGET_H 2 | #define TESTGADGET_H 3 | 4 | #include 5 | 6 | class TestGadget 7 | { 8 | Q_GADGET 9 | 10 | Q_PROPERTY(int key MEMBER key) 11 | Q_PROPERTY(double value MEMBER value) 12 | Q_PROPERTY(int zhidden MEMBER zhidden STORED false) 13 | 14 | public: 15 | TestGadget(int key = 0, double value = 0.0, int zhidden = 11); 16 | 17 | int key; 18 | double value; 19 | int zhidden; 20 | 21 | bool operator==(const TestGadget &other) const; 22 | }; 23 | 24 | Q_DECLARE_METATYPE(TestGadget) 25 | Q_DECLARE_METATYPE(TestGadget*) 26 | 27 | #endif // TESTGADGET_H 28 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/GeomConverterTest/GeomConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_geomconverter 8 | 9 | include(../convlib.pri) 10 | 11 | SOURCES += \ 12 | tst_geomconverter.cpp 13 | 14 | include(../../testrun.pri) 15 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/LegacyGeomConverterTest/LegacyGeomConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_legacygeomconverter 8 | 9 | include(../convlib.pri) 10 | 11 | SOURCES += \ 12 | tst_legacygeomconverter.cpp 13 | 14 | include(../../testrun.pri) 15 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/ListConverterTest/ListConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_listconverter 8 | 9 | include(../convlib.pri) 10 | 11 | SOURCES += \ 12 | tst_listconverter.cpp 13 | 14 | include(../../testrun.pri) 15 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/LocaleConverterTest/LocaleConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_localeconverter 8 | 9 | include(../convlib.pri) 10 | 11 | SOURCES += \ 12 | tst_localeconverter.cpp 13 | 14 | include(../../testrun.pri) 15 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/LocaleConverterTest/tst_localeconverter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "typeconvertertestbase.h" 5 | 6 | #include 7 | using namespace QtJsonSerializer; 8 | using namespace QtJsonSerializer::TypeConverters; 9 | 10 | class LocaleConverterTest : public TypeConverterTestBase 11 | { 12 | Q_OBJECT 13 | 14 | protected: 15 | TypeConverter *converter() override; 16 | void addConverterData() override; 17 | void addMetaData() override; 18 | void addCommonSerData() override; 19 | void addDeserData() override; 20 | 21 | private: 22 | LocaleConverter _converter; 23 | }; 24 | 25 | TypeConverter *LocaleConverterTest::converter() 26 | { 27 | return &_converter; 28 | } 29 | 30 | void LocaleConverterTest::addConverterData() 31 | { 32 | QTest::newRow("locale") << static_cast(TypeConverter::Standard); 33 | } 34 | 35 | void LocaleConverterTest::addMetaData() 36 | { 37 | QTest::newRow("locale.iso") << static_cast(QMetaType::QLocale) 38 | << static_cast(CborSerializer::LocaleISO) 39 | << QCborValue::String 40 | << true 41 | << TypeConverter::DeserializationCapabilityResult::Positive; 42 | QTest::newRow("locale.bcp47") << static_cast(QMetaType::QLocale) 43 | << static_cast(CborSerializer::LocaleBCP47) 44 | << QCborValue::String 45 | << true 46 | << TypeConverter::DeserializationCapabilityResult::Positive; 47 | QTest::newRow("guessed.iso") << static_cast(QMetaType::UnknownType) 48 | << static_cast(CborSerializer::LocaleISO) 49 | << QCborValue::String 50 | << false 51 | << TypeConverter::DeserializationCapabilityResult::Guessed; 52 | QTest::newRow("guessed.bcp47") << static_cast(QMetaType::UnknownType) 53 | << static_cast(CborSerializer::LocaleBCP47) 54 | << QCborValue::String 55 | << false 56 | << TypeConverter::DeserializationCapabilityResult::Guessed; 57 | QTest::newRow("invalid.type") << static_cast(QMetaType::QString) 58 | << static_cast(CborSerializer::LocaleISO) 59 | << QCborValue::String 60 | << false 61 | << TypeConverter::DeserializationCapabilityResult::Negative; 62 | QTest::newRow("invalid.data") << static_cast(QMetaType::QLocale) 63 | << static_cast(CborSerializer::LocaleISO) 64 | << QCborValue::ByteArray 65 | << true 66 | << TypeConverter::DeserializationCapabilityResult::Negative; 67 | QTest::newRow("invalid.tag") << static_cast(QMetaType::QLocale) 68 | << static_cast(CborSerializer::Font) 69 | << QCborValue::String 70 | << true 71 | << TypeConverter::DeserializationCapabilityResult::WrongTag; 72 | } 73 | 74 | void LocaleConverterTest::addCommonSerData() 75 | { 76 | QTest::newRow("normal") << QVariantHash{} 77 | << TestQ{} 78 | << static_cast(nullptr) 79 | << static_cast(QMetaType::QLocale) 80 | << QVariant{QLocale{QLocale::German, QLocale::Germany}} 81 | << QCborValue{static_cast(CborSerializer::LocaleISO), QStringLiteral("de_DE")} 82 | << QJsonValue{QStringLiteral("de_DE")}; 83 | QTest::newRow("c") << QVariantHash{} 84 | << TestQ{} 85 | << static_cast(nullptr) 86 | << static_cast(QMetaType::QLocale) 87 | << QVariant{QLocale::c()} 88 | << QCborValue{static_cast(CborSerializer::LocaleISO), QStringLiteral("C")} 89 | << QJsonValue{QStringLiteral("C")}; 90 | QTest::newRow("bcp47.default") << QVariantHash{{QStringLiteral("useBcp47Locale"), true}} 91 | << TestQ{} 92 | << static_cast(nullptr) 93 | << static_cast(QMetaType::QLocale) 94 | << QVariant{QLocale{QLocale::German, QLocale::Germany}} 95 | << QCborValue{static_cast(CborSerializer::LocaleBCP47), QStringLiteral("de")} 96 | << QJsonValue{QStringLiteral("de")}; 97 | QTest::newRow("bcp47.special") << QVariantHash{{QStringLiteral("useBcp47Locale"), true}} 98 | << TestQ{} 99 | << static_cast(nullptr) 100 | << static_cast(QMetaType::QLocale) 101 | << QVariant{QLocale{QLocale::German, QLocale::Austria}} 102 | << QCborValue{static_cast(CborSerializer::LocaleBCP47), QStringLiteral("de-AT")} 103 | << QJsonValue{QStringLiteral("de-AT")}; 104 | } 105 | 106 | void LocaleConverterTest::addDeserData() 107 | { 108 | QTest::newRow("empty") << QVariantHash{} 109 | << TestQ{} 110 | << static_cast(nullptr) 111 | << static_cast(QMetaType::QLocale) 112 | << QVariant{QLocale::c()} 113 | << QCborValue{static_cast(CborSerializer::LocaleISO), QString{}} 114 | << QJsonValue{QString{}}; 115 | QTest::newRow("invalid") << QVariantHash{} 116 | << TestQ{} 117 | << static_cast(nullptr) 118 | << static_cast(QMetaType::QLocale) 119 | << QVariant{} 120 | << QCborValue{static_cast(CborSerializer::LocaleISO), QStringLiteral("some random text")} 121 | << QJsonValue{QStringLiteral("some random text")}; 122 | } 123 | 124 | QTEST_MAIN(LocaleConverterTest) 125 | 126 | #include "tst_localeconverter.moc" 127 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/MapConverterTest/MapConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_mapconverter 8 | 9 | include(../convlib.pri) 10 | 11 | SOURCES += \ 12 | tst_mapconverter.cpp 13 | 14 | include(../../testrun.pri) 15 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/MultiMapConverterTest/MultiMapConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_multimapconverter 8 | 9 | include(../convlib.pri) 10 | 11 | SOURCES += \ 12 | tst_multimapconverter.cpp 13 | 14 | include(../../testrun.pri) 15 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/ObjectConverterTest/ObjectConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_objectconverter 8 | 9 | include(../convlib.pri) 10 | 11 | HEADERS += \ 12 | testobject.h 13 | 14 | SOURCES += \ 15 | tst_objectconverter.cpp \ 16 | testobject.cpp 17 | 18 | include(../../testrun.pri) 19 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/ObjectConverterTest/testobject.cpp: -------------------------------------------------------------------------------- 1 | #include "testobject.h" 2 | 3 | TestObject::TestObject(QObject *parent) : 4 | QObject{parent} 5 | {} 6 | 7 | TestObject::TestObject(int key, double value, int zhidden, QObject *parent) : 8 | QObject{parent}, 9 | key{key}, 10 | value{value}, 11 | zhidden{zhidden} 12 | { 13 | setObjectName(QStringLiteral("TestObject")); 14 | } 15 | 16 | bool TestObject::compare(const TestObject *other) const 17 | { 18 | return key == other->key && 19 | qFuzzyCompare(value, other->value) && 20 | zhidden == other->zhidden; 21 | } 22 | 23 | StaticPolyObject::StaticPolyObject(QObject *parent) : 24 | TestObject{parent} 25 | {} 26 | 27 | StaticPolyObject::StaticPolyObject(int key, double value, int hidden, bool extra1, QObject *parent) : 28 | TestObject{key, value, hidden, parent}, 29 | extra1{extra1} 30 | {} 31 | 32 | bool StaticPolyObject::compare(const TestObject *other) const 33 | { 34 | auto o = qobject_cast(other); 35 | if(o) { 36 | return TestObject::compare(o) && 37 | extra1 == o->extra1; 38 | } else 39 | return false; 40 | } 41 | 42 | StaticNonPolyObject::StaticNonPolyObject(QObject *parent) : 43 | TestObject{parent} 44 | {} 45 | 46 | StaticNonPolyObject::StaticNonPolyObject(int key, double value, int hidden, bool extra2, QObject *parent) : 47 | TestObject{key, value, hidden, parent}, 48 | extra2{extra2} 49 | {} 50 | 51 | bool StaticNonPolyObject::compare(const TestObject *other) const 52 | { 53 | auto o = qobject_cast(other); 54 | if(o) { 55 | return TestObject::compare(o) && 56 | extra2 == o->extra2; 57 | } else 58 | return false; 59 | } 60 | 61 | DynamicPolyObject::DynamicPolyObject(QObject *parent) : 62 | TestObject{parent} 63 | { 64 | setProperty("__qt_json_serializer_polymorphic", false); 65 | } 66 | 67 | DynamicPolyObject::DynamicPolyObject(int key, double value, int hidden, bool extra3, bool poly, QObject *parent) : 68 | TestObject{key, value, hidden, parent}, 69 | extra3{extra3} 70 | { 71 | setProperty("__qt_json_serializer_polymorphic", poly); 72 | } 73 | 74 | bool DynamicPolyObject::compare(const TestObject *other) const 75 | { 76 | auto o = qobject_cast(other); 77 | if(o) { 78 | return TestObject::compare(o) && 79 | extra3 == o->extra3; 80 | } else 81 | return false; 82 | } 83 | 84 | BrokenObject::BrokenObject(QObject *parent) : 85 | TestObject{parent} 86 | {} 87 | 88 | DerivedTestObject::DerivedTestObject(QObject *parent) : 89 | TestObject{parent} 90 | {} 91 | 92 | DerivedTestObject::DerivedTestObject(int key, double value, int hidden, bool extra4, QObject *parent) : 93 | TestObject{key, value, hidden, parent}, 94 | extra4{extra4} 95 | {} 96 | 97 | bool DerivedTestObject::compare(const TestObject *other) const 98 | { 99 | auto o = qobject_cast(other); 100 | if(o) { 101 | return TestObject::compare(o) && 102 | extra4 == o->extra4; 103 | } else 104 | return false; 105 | } 106 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/ObjectConverterTest/testobject.h: -------------------------------------------------------------------------------- 1 | #ifndef TESTOBJECT_H 2 | #define TESTOBJECT_H 3 | 4 | #include 5 | #include 6 | 7 | class TestObject : public QObject 8 | { 9 | Q_OBJECT 10 | 11 | Q_PROPERTY(int key MEMBER key) 12 | Q_PROPERTY(double value MEMBER value) 13 | Q_PROPERTY(int zhidden MEMBER zhidden STORED false) 14 | 15 | public: 16 | Q_INVOKABLE explicit TestObject(QObject *parent = nullptr); 17 | Q_INVOKABLE explicit TestObject(int key, double value, int zhidden = 11, QObject *parent = nullptr); 18 | 19 | int key = 0; 20 | double value = 0; 21 | int zhidden = 11; 22 | 23 | virtual bool compare(const TestObject *other) const; 24 | }; 25 | 26 | class StaticPolyObject : public TestObject 27 | { 28 | Q_OBJECT 29 | Q_JSON_POLYMORPHIC(true) 30 | 31 | Q_PROPERTY(bool extra1 MEMBER extra1) 32 | 33 | public: 34 | Q_INVOKABLE explicit StaticPolyObject(QObject *parent = nullptr); 35 | explicit StaticPolyObject(int key, double value, int hidden, bool extra1, QObject *parent = nullptr); 36 | 37 | bool extra1 = false; 38 | 39 | bool compare(const TestObject *other) const override; 40 | }; 41 | 42 | class StaticNonPolyObject : public TestObject 43 | { 44 | Q_OBJECT 45 | Q_JSON_POLYMORPHIC(false) 46 | 47 | Q_PROPERTY(bool extra2 MEMBER extra2) 48 | 49 | public: 50 | Q_INVOKABLE explicit StaticNonPolyObject(QObject *parent = nullptr); 51 | explicit StaticNonPolyObject(int key, double value, int hidden, bool extra2, QObject *parent = nullptr); 52 | 53 | bool extra2 = false; 54 | 55 | bool compare(const TestObject *other) const override; 56 | }; 57 | 58 | class DynamicPolyObject : public TestObject 59 | { 60 | Q_OBJECT 61 | 62 | Q_PROPERTY(bool extra3 MEMBER extra3) 63 | 64 | public: 65 | Q_INVOKABLE explicit DynamicPolyObject(QObject *parent = nullptr); 66 | explicit DynamicPolyObject(int key, double value, int hidden, bool extra3, bool poly, QObject *parent = nullptr); 67 | 68 | bool extra3 = false; 69 | 70 | bool compare(const TestObject *other) const override; 71 | }; 72 | 73 | class DerivedTestObject : public TestObject 74 | { 75 | Q_OBJECT 76 | 77 | Q_PROPERTY(bool extra4 MEMBER extra4) 78 | 79 | public: 80 | Q_INVOKABLE explicit DerivedTestObject(QObject *parent = nullptr); 81 | explicit DerivedTestObject(int key, double value, int hidden, bool extra4, QObject *parent = nullptr); 82 | 83 | bool extra4 = false; 84 | 85 | bool compare(const TestObject *other) const override; 86 | }; 87 | 88 | class BrokenObject : public TestObject 89 | { 90 | Q_OBJECT 91 | 92 | public: 93 | explicit BrokenObject(QObject *parent = nullptr); 94 | }; 95 | 96 | Q_DECLARE_METATYPE(TestObject*) 97 | Q_DECLARE_METATYPE(StaticPolyObject*) 98 | Q_DECLARE_METATYPE(StaticNonPolyObject*) 99 | Q_DECLARE_METATYPE(DynamicPolyObject*) 100 | Q_DECLARE_METATYPE(DerivedTestObject*) 101 | Q_DECLARE_METATYPE(BrokenObject*) 102 | 103 | #endif // TESTOBJECT_H 104 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/OptionalConverterTest/OptionalConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_optionalconverter 8 | 9 | include(../convlib.pri) 10 | 11 | SOURCES += \ 12 | tst_optionalconverter.cpp 13 | 14 | include(../../testrun.pri) 15 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/OptionalConverterTest/tst_optionalconverter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "typeconvertertestbase.h" 5 | 6 | #include 7 | 8 | #include 9 | using namespace QtJsonSerializer; 10 | using namespace QtJsonSerializer::TypeConverters; 11 | 12 | using ExtendedOptional = std::optional>; 13 | 14 | Q_DECLARE_METATYPE(std::optional) 15 | Q_DECLARE_METATYPE(ExtendedOptional) 16 | Q_DECLARE_METATYPE(std::optional) 17 | 18 | class OptionalConverterTest : public TypeConverterTestBase 19 | { 20 | Q_OBJECT 21 | 22 | protected: 23 | void initTest() override; 24 | TypeConverter *converter() override; 25 | void addConverterData() override; 26 | void addMetaData() override; 27 | void addCommonSerData() override; 28 | void addSerData() override; 29 | 30 | private: 31 | StdOptionalConverter _converter; 32 | }; 33 | 34 | void OptionalConverterTest::initTest() 35 | { 36 | JsonSerializer::registerOptionalConverters(); 37 | JsonSerializer::registerOptionalConverters>(); 38 | JsonSerializer::registerOptionalConverters(); 39 | 40 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 41 | QMetaType::registerEqualsComparator>(); 42 | #endif 43 | } 44 | 45 | TypeConverter *OptionalConverterTest::converter() 46 | { 47 | return &_converter; 48 | } 49 | 50 | void OptionalConverterTest::addConverterData() 51 | { 52 | QTest::newRow("optional") << static_cast(TypeConverter::Standard); 53 | } 54 | 55 | void OptionalConverterTest::addMetaData() 56 | { 57 | QTest::newRow("basic") << qMetaTypeId>() 58 | << static_cast(CborSerializer::NoTag) 59 | << QCborValue::Double 60 | << true 61 | << TypeConverter::DeserializationCapabilityResult::Positive; 62 | QTest::newRow("extended") << qMetaTypeId>>() 63 | << static_cast(CborSerializer::NoTag) 64 | << QCborValue::Null 65 | << true 66 | << TypeConverter::DeserializationCapabilityResult::Positive; 67 | QTest::newRow("invalid") << qMetaTypeId>() 68 | << static_cast(CborSerializer::NoTag) 69 | << QCborValue::Integer 70 | << false 71 | << TypeConverter::DeserializationCapabilityResult::Negative; 72 | } 73 | 74 | void OptionalConverterTest::addCommonSerData() 75 | { 76 | QTest::newRow("basic") << QVariantHash{} 77 | << TestQ{{QMetaType::Int, 5, 1}} 78 | << static_cast(nullptr) 79 | << qMetaTypeId>() 80 | << QVariant::fromValue(std::optional{5}) 81 | << QCborValue{1} 82 | << QJsonValue{1}; 83 | QTest::newRow("nullopt") << QVariantHash{} 84 | << TestQ{{QMetaType::Nullptr, QVariant::fromValue(nullptr), QJsonValue::Null}} 85 | << static_cast(nullptr) 86 | << qMetaTypeId>() 87 | << QVariant::fromValue>(std::nullopt) 88 | << QCborValue{QCborValue::Null} 89 | << QJsonValue{QJsonValue::Null}; 90 | } 91 | 92 | void OptionalConverterTest::addSerData() 93 | { 94 | QTest::newRow("invalid.unconvertible") << QVariantHash{} 95 | << TestQ{} 96 | << static_cast(nullptr) 97 | << qMetaTypeId>() 98 | << QVariant::fromValue(std::optional{OpaqueDummy{}}) 99 | << QCborValue{} 100 | << QJsonValue{QJsonValue::Undefined}; 101 | } 102 | 103 | QTEST_MAIN(OptionalConverterTest) 104 | 105 | #include "tst_optionalconverter.moc" 106 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/PairConverterTest/PairConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_pairconverter 8 | 9 | include(../convlib.pri) 10 | 11 | SOURCES += \ 12 | tst_pairconverter.cpp 13 | 14 | include(../../testrun.pri) 15 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/SerializerTest/SerializerTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core gui testlib jsonserializer jsonserializer-private 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_serializer 8 | 9 | HEADERS += \ 10 | testconverter.h 11 | 12 | SOURCES += \ 13 | testconverter.cpp \ 14 | tst_serializer.cpp 15 | 16 | include(../../testrun.pri) 17 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/SerializerTest/testconverter.cpp: -------------------------------------------------------------------------------- 1 | #include "testconverter.h" 2 | #include 3 | using namespace QtJsonSerializer; 4 | 5 | bool EnumContainer::operator==(EnumContainer other) const 6 | { 7 | return normalEnum == other.normalEnum && 8 | enumFlags == other.enumFlags; 9 | } 10 | 11 | bool EnumContainer::operator!=(EnumContainer other) const 12 | { 13 | return normalEnum != other.normalEnum || 14 | enumFlags != other.enumFlags; 15 | } 16 | 17 | EnumContainer::EnumFlags EnumContainer::getEnumFlags() const 18 | { 19 | return enumFlags; 20 | } 21 | 22 | void EnumContainer::setEnumFlags(EnumFlags value) 23 | { 24 | enumFlags = value; 25 | } 26 | 27 | 28 | 29 | TestEnumConverter::TestEnumConverter() 30 | { 31 | setPriority(Priority::VeryHigh); 32 | } 33 | 34 | bool TestEnumConverter::canConvert(int metaTypeId) const 35 | { 36 | return metaTypeId == qMetaTypeId() || 37 | metaTypeId == qMetaTypeId(); 38 | } 39 | 40 | QList TestEnumConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const 41 | { 42 | Q_UNUSED(metaTypeId) 43 | Q_UNUSED(tag) 44 | return {QCborValue::String}; 45 | } 46 | 47 | QCborValue TestEnumConverter::serialize(int propertyType, const QVariant &value) const 48 | { 49 | if (propertyType == qMetaTypeId()) { 50 | const auto me = QMetaEnum::fromType(); 51 | return QString::fromUtf8(me.valueToKey(value.toInt())); 52 | } else { 53 | const auto me = QMetaEnum::fromType(); 54 | return QString::fromUtf8(me.valueToKeys(value.toInt())); 55 | } 56 | } 57 | 58 | QVariant TestEnumConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const 59 | { 60 | Q_UNUSED(parent) 61 | if (propertyType == qMetaTypeId()) { 62 | const auto me = QMetaEnum::fromType(); 63 | return me.keyToValue(qUtf8Printable(value.toString())); 64 | } else { 65 | const auto me = QMetaEnum::fromType(); 66 | return me.keysToValue(qUtf8Printable(value.toString())); 67 | } 68 | } 69 | 70 | 71 | 72 | TestWrapperConverter::TestWrapperConverter() 73 | { 74 | setPriority(Priority::VeryHigh); 75 | } 76 | 77 | bool TestWrapperConverter::canConvert(int metaTypeId) const 78 | { 79 | return metaTypeId == qMetaTypeId(); 80 | } 81 | 82 | QList TestWrapperConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const 83 | { 84 | Q_UNUSED(metaTypeId) 85 | Q_UNUSED(tag) 86 | return {QCborValue::Map}; 87 | } 88 | 89 | QCborValue TestWrapperConverter::serialize(int propertyType, const QVariant &value) const 90 | { 91 | Q_UNUSED(propertyType) 92 | auto mo = &EnumContainer::staticMetaObject; 93 | auto container = value.value(); 94 | return QCborMap { 95 | {QStringLiteral("0"), helper()->serializeSubtype(mo->property(mo->propertyOffset()), static_cast(container.normalEnum))}, 96 | {QStringLiteral("1"), helper()->serializeSubtype(mo->property(mo->propertyOffset() + 1), static_cast(container.enumFlags))} 97 | }; 98 | } 99 | 100 | QVariant TestWrapperConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const 101 | { 102 | auto mo = &EnumContainer::staticMetaObject; 103 | auto map = value.toMap(); 104 | if (map.contains(QStringLiteral("error"))) 105 | helper()->deserializeSubtype(propertyType, QCborValue{42}, parent, "test"); 106 | return QVariant::fromValue(EnumContainer { 107 | static_cast(helper()->deserializeSubtype(mo->property(mo->propertyOffset()), map.value(QStringLiteral("0")), parent).toInt()), 108 | static_cast(helper()->deserializeSubtype(mo->property(mo->propertyOffset() + 1), map.value(QStringLiteral("1")), parent).toInt()) 109 | }); 110 | } 111 | 112 | 113 | 114 | TestObject::TestObject(QObject *parent) 115 | : QObject{parent} 116 | {} 117 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/SerializerTest/testconverter.h: -------------------------------------------------------------------------------- 1 | #ifndef TESTCONVERTER_H 2 | #define TESTCONVERTER_H 3 | 4 | #include 5 | #include 6 | 7 | class EnumContainer 8 | { 9 | Q_GADGET 10 | 11 | Q_PROPERTY(NormalEnum normalEnum MEMBER normalEnum) 12 | Q_PROPERTY(EnumFlags enumFlags READ getEnumFlags WRITE setEnumFlags) 13 | 14 | public: 15 | enum NormalEnum { 16 | Normal0 = 0, 17 | Normal1 = 1, 18 | Normal2 = 2 19 | }; 20 | Q_ENUM(NormalEnum) 21 | 22 | enum EnumFlag { 23 | Flag1 = 0x02, 24 | Flag2 = 0x04, 25 | Flag3 = 0x08, 26 | 27 | FlagX = Flag1 | Flag2 28 | }; 29 | Q_DECLARE_FLAGS(EnumFlags, EnumFlag) 30 | Q_FLAG(EnumFlags) 31 | 32 | NormalEnum normalEnum; 33 | EnumFlags enumFlags; 34 | 35 | bool operator==(EnumContainer other) const; 36 | bool operator!=(EnumContainer other) const; 37 | 38 | private: 39 | EnumFlags getEnumFlags() const; 40 | void setEnumFlags(EnumFlags value); 41 | }; 42 | 43 | class TestEnumConverter : public QtJsonSerializer::TypeConverter 44 | { 45 | public: 46 | using NormalEnum = EnumContainer::NormalEnum; 47 | using EnumFlags = EnumContainer::EnumFlags; 48 | 49 | TestEnumConverter(); 50 | 51 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(TestEnumConverter) 52 | bool canConvert(int metaTypeId) const override; 53 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 54 | QCborValue serialize(int propertyType, const QVariant &value) const override; 55 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 56 | }; 57 | 58 | class TestWrapperConverter : public QtJsonSerializer::TypeConverter 59 | { 60 | public: 61 | TestWrapperConverter(); 62 | 63 | QT_JSONSERIALIZER_TYPECONVERTER_NAME(TestWrapperConverter) 64 | bool canConvert(int metaTypeId) const override; 65 | QList allowedCborTypes(int metaTypeId, QCborTag tag) const override; 66 | QCborValue serialize(int propertyType, const QVariant &value) const override; 67 | QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override; 68 | }; 69 | 70 | class TestObject : public QObject 71 | { 72 | Q_OBJECT 73 | 74 | public: 75 | TestObject(QObject *parent = nullptr); 76 | }; 77 | 78 | Q_DECLARE_OPERATORS_FOR_FLAGS(EnumContainer::EnumFlags) 79 | 80 | Q_DECLARE_METATYPE(EnumContainer) 81 | 82 | #endif // TESTCONVERTER_H 83 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/SmartPointerConverterTest/SmartPointerConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_smartpointerconverter 8 | 9 | include(../convlib.pri) 10 | 11 | SOURCES += \ 12 | testobject.cpp \ 13 | tst_smartpointerconverter.cpp 14 | 15 | include(../../testrun.pri) 16 | 17 | HEADERS += \ 18 | testobject.h 19 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/SmartPointerConverterTest/testobject.cpp: -------------------------------------------------------------------------------- 1 | #include "testobject.h" 2 | 3 | TestClass::TestClass(int value) 4 | : value{value} 5 | {} 6 | 7 | TestObject::TestObject(int value, QObject *parent) 8 | : QObject{parent} 9 | , value{value} 10 | {} 11 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/SmartPointerConverterTest/testobject.h: -------------------------------------------------------------------------------- 1 | #ifndef TESTOBJECT_H 2 | #define TESTOBJECT_H 3 | 4 | #include 5 | #include 6 | 7 | class TestClass 8 | { 9 | public: 10 | int value; 11 | 12 | TestClass(int value = 0); 13 | }; 14 | 15 | class TestObject : public QObject 16 | { 17 | Q_OBJECT 18 | 19 | public: 20 | int value; 21 | 22 | explicit TestObject(int value = 0, QObject *parent = nullptr); 23 | }; 24 | 25 | Q_DECLARE_METATYPE(TestClass*) 26 | Q_DECLARE_METATYPE(QSharedPointer) 27 | Q_DECLARE_METATYPE(TestObject*) 28 | 29 | #endif // TESTOBJECT_H 30 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/TupleConverterTest/TupleConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_tupleconverter 8 | 9 | include(../convlib.pri) 10 | 11 | SOURCES += \ 12 | tst_tupleconverter.cpp 13 | 14 | include(../../testrun.pri) 15 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/TupleConverterTest/tst_tupleconverter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "typeconvertertestbase.h" 5 | 6 | #include 7 | using namespace QtJsonSerializer; 8 | using namespace QtJsonSerializer::TypeConverters; 9 | 10 | using TestTpl1 = std::tuple; 11 | using TestTpl2 = std::tuple, QPair, QMap>; 12 | using TestTpl3 = std::tuple; 13 | 14 | Q_DECLARE_METATYPE(TestTpl1) 15 | Q_DECLARE_METATYPE(TestTpl2) 16 | Q_DECLARE_METATYPE(TestTpl3) 17 | 18 | class TupleConverterTest : public TypeConverterTestBase 19 | { 20 | Q_OBJECT 21 | 22 | protected: 23 | void initTest() override; 24 | TypeConverter *converter() override; 25 | void addConverterData() override; 26 | void addMetaData() override; 27 | void addCommonSerData() override; 28 | void addSerData() override; 29 | void addDeserData() override; 30 | 31 | private: 32 | StdTupleConverter _converter; 33 | }; 34 | 35 | void TupleConverterTest::initTest() 36 | { 37 | JsonSerializer::registerTupleConverters(); 38 | JsonSerializer::registerTupleConverters, QPair, QMap>(); 39 | JsonSerializer::registerTupleConverters(); 40 | 41 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 42 | QMetaType::registerEqualsComparator(); 43 | #endif 44 | } 45 | 46 | TypeConverter *TupleConverterTest::converter() 47 | { 48 | return &_converter; 49 | } 50 | 51 | void TupleConverterTest::addConverterData() 52 | { 53 | QTest::newRow("tuple") << static_cast(TypeConverter::Standard); 54 | } 55 | 56 | void TupleConverterTest::addMetaData() 57 | { 58 | QTest::newRow("basic") << qMetaTypeId>() 59 | << static_cast(CborSerializer::Tuple) 60 | << QCborValue::Array 61 | << true 62 | << TypeConverter::DeserializationCapabilityResult::Positive; 63 | QTest::newRow("extended") << qMetaTypeId, QPair, QMap>>() 64 | << static_cast(CborSerializer::NoTag) 65 | << QCborValue::Array 66 | << true 67 | << TypeConverter::DeserializationCapabilityResult::Positive; 68 | QTest::newRow("invalid") << static_cast(QMetaType::QVariant) 69 | << static_cast(CborSerializer::NoTag) 70 | << QCborValue::Null 71 | << false 72 | << TypeConverter::DeserializationCapabilityResult::Negative; 73 | QTest::newRow("wrongtag") << qMetaTypeId>() 74 | << static_cast(CborSerializer::Homogeneous) 75 | << QCborValue::Array 76 | << true 77 | << TypeConverter::DeserializationCapabilityResult::WrongTag; 78 | } 79 | 80 | void TupleConverterTest::addCommonSerData() 81 | { 82 | QTest::newRow("basic") << QVariantHash{} 83 | << TestQ{{QMetaType::Int, 5, 1}, {QMetaType::Bool, true, 2}, {QMetaType::Double, 5.5, 3}} 84 | << static_cast(this) 85 | << qMetaTypeId>() 86 | << QVariant::fromValue(std::make_tuple(5, true, 5.5)) 87 | << QCborValue{static_cast(CborSerializer::Tuple), QCborArray{1, 2, 3}} 88 | << QJsonValue{QJsonArray{1, 2, 3}}; 89 | } 90 | 91 | void TupleConverterTest::addSerData() 92 | { 93 | QTest::newRow("unconvertible") << QVariantHash{} 94 | << TestQ{} 95 | << static_cast(nullptr) 96 | << qMetaTypeId>() 97 | << QVariant::fromValue(std::tuple{}) 98 | << QCborValue{} 99 | << QJsonValue{QJsonValue::Undefined}; 100 | } 101 | 102 | void TupleConverterTest::addDeserData() 103 | { 104 | QTest::newRow("invalid") << QVariantHash{} 105 | << TestQ{} 106 | << static_cast(nullptr) 107 | << qMetaTypeId() 108 | << QVariant{} 109 | << QCborValue{static_cast(CborSerializer::Tuple), QCborArray{1, true, 3.4, 4}} 110 | << QJsonValue{QJsonArray{1, true, 3.4, 4}}; 111 | } 112 | 113 | QTEST_MAIN(TupleConverterTest) 114 | 115 | #include "tst_tupleconverter.moc" 116 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/TypeConverterTestLib/TypeConverterTestLib.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = lib 2 | 3 | QT = core testlib jsonserializer jsonserializer-private 4 | CONFIG += staticlib 5 | 6 | TARGET = TypeConverterTestLib 7 | 8 | HEADERS += \ 9 | typeconvertertestbase.h \ 10 | dummyserializationhelper.h \ 11 | opaquedummy.h \ 12 | multitypeconvertertestbase.h 13 | 14 | SOURCES += \ 15 | typeconvertertestbase.cpp \ 16 | dummyserializationhelper.cpp \ 17 | opaquedummy.cpp \ 18 | multitypeconvertertestbase.cpp 19 | 20 | runtarget.target = run-tests 21 | !compat_test { 22 | win32: runtarget.depends += $(DESTDIR_TARGET) 23 | else: runtarget.depends += $(TARGET) 24 | } 25 | QMAKE_EXTRA_TARGETS += runtarget 26 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/TypeConverterTestLib/dummyserializationhelper.cpp: -------------------------------------------------------------------------------- 1 | #include "dummyserializationhelper.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | using namespace QtJsonSerializer; 9 | 10 | DummySerializationHelper::DummySerializationHelper(QObject *parent) : 11 | QObject{parent} 12 | {} 13 | 14 | bool DummySerializationHelper::jsonMode() const 15 | { 16 | return json; 17 | } 18 | 19 | QVariant DummySerializationHelper::getProperty(const char *name) const 20 | { 21 | return properties.value(QString::fromUtf8(name)); 22 | } 23 | 24 | QCborTag DummySerializationHelper::typeTag(int metaTypeId) const 25 | { 26 | Q_UNUSED(metaTypeId) 27 | return properties.value(QStringLiteral("typeTag"), 28 | QVariant::fromValue(static_cast(CborSerializer::NoTag))) 29 | .value(); 30 | } 31 | 32 | QSharedPointer DummySerializationHelper::extractor(int metaTypeId) const 33 | { 34 | return SerializerBasePrivate::extractors.get(metaTypeId); 35 | } 36 | 37 | QCborValue DummySerializationHelper::serializeSubtype(const QMetaProperty &property, const QVariant &value) const 38 | { 39 | return serializeSubtype(property.userType(), value, property.name()); 40 | } 41 | 42 | QCborValue DummySerializationHelper::serializeSubtype(int propertyType, const QVariant &value, const QByteArray &traceHint) const 43 | { 44 | ExceptionContext ctx{propertyType, traceHint}; 45 | if (serData.isEmpty()) 46 | throw SerializationException{"No more data to serialize was expected"}; 47 | 48 | for (auto i = 0; i < serData.size(); ++i) { 49 | if (serData[i].typeId != propertyType) 50 | continue; 51 | 52 | auto data = serData.takeAt(i); 53 | auto ok = false; 54 | [&](){ 55 | QCOMPARE(value, data.variant); 56 | ok = true; 57 | }(); 58 | if (ok) 59 | return data.cbor; 60 | else 61 | throw SerializationException{"Data comparison failed"}; 62 | } 63 | 64 | throw SerializationException{QByteArrayLiteral("Unable to find data of type ") + QMetaTypeName(propertyType) + QByteArrayLiteral(" in serData")}; 65 | } 66 | 67 | QVariant DummySerializationHelper::deserializeSubtype(const QMetaProperty &property, const QCborValue &value, QObject *parent) const 68 | { 69 | return deserializeSubtype(property.userType(), value, parent, property.name()); 70 | } 71 | 72 | QVariant DummySerializationHelper::deserializeSubtype(int propertyType, const QCborValue &value, QObject *parent, const QByteArray &traceHint) const 73 | { 74 | ExceptionContext ctx{propertyType, traceHint}; 75 | if (deserData.isEmpty()) 76 | throw DeserializationException{"No more data to deserialize was expected"}; 77 | 78 | for(auto i = 0; i < deserData.size(); i++) { 79 | if (deserData[i].typeId != propertyType) 80 | continue; 81 | 82 | auto data = deserData.takeAt(i); 83 | auto ok = false; 84 | [&](){ 85 | QCOMPARE(value, data.cbor); 86 | if(expectedParent) 87 | QCOMPARE(parent, expectedParent); 88 | ok = true; 89 | }(); 90 | if (ok) 91 | return data.variant; 92 | else 93 | throw DeserializationException{"Data comparison failed"}; 94 | } 95 | 96 | throw DeserializationException{QByteArrayLiteral("Unable to find data of type ") + QMetaTypeName(propertyType) + QByteArrayLiteral(" in deserData")}; 97 | } 98 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/TypeConverterTestLib/dummyserializationhelper.h: -------------------------------------------------------------------------------- 1 | #ifndef DUMMYSERIALIZATIONHELPER_H 2 | #define DUMMYSERIALIZATIONHELPER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class DummySerializationHelper : public QObject, public QtJsonSerializer::TypeConverter::SerializationHelper 9 | { 10 | Q_OBJECT 11 | 12 | public: 13 | DummySerializationHelper(QObject *parent = nullptr); 14 | 15 | bool jsonMode() const override; 16 | QVariant getProperty(const char *name) const override; 17 | QCborTag typeTag(int metaTypeId) const override; 18 | QSharedPointer extractor(int metaTypeId) const override; 19 | QCborValue serializeSubtype(const QMetaProperty &property, const QVariant &value) const override; 20 | QCborValue serializeSubtype(int propertyType, const QVariant &value, const QByteArray &traceHint) const override; 21 | QVariant deserializeSubtype(const QMetaProperty &property, const QCborValue &value, QObject *parent) const override; 22 | QVariant deserializeSubtype(int propertyType, const QCborValue &value, QObject *parent, const QByteArray &traceHint) const override; 23 | 24 | bool json = false; 25 | QVariantHash properties; 26 | struct SerInfo { 27 | int typeId; 28 | QVariant variant; 29 | QCborValue cbor; 30 | }; 31 | mutable QList serData; 32 | mutable QList deserData; 33 | QObject *expectedParent = nullptr; 34 | }; 35 | 36 | Q_DECLARE_METATYPE(QList) 37 | 38 | #endif // DUMMYSERIALIZATIONHELPER_H 39 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/TypeConverterTestLib/multitypeconvertertestbase.cpp: -------------------------------------------------------------------------------- 1 | #include "multitypeconvertertestbase.h" 2 | #include 3 | using namespace QtJsonSerializer; 4 | 5 | MultiTypeConverterTestBase::MultiTypeConverterTestBase(QObject *parent) : 6 | TypeConverterTestBase{parent} 7 | {} 8 | 9 | TypeConverter *MultiTypeConverterTestBase::converter() 10 | { 11 | QFETCH(TypeConverter*, converter); 12 | return converter; 13 | } 14 | 15 | void MultiTypeConverterTestBase::testConverterIsRegistered_data() 16 | { 17 | QTest::addColumn("converter"); 18 | addConverterInstances(); 19 | } 20 | 21 | void MultiTypeConverterTestBase::testConverterMeta_data() 22 | { 23 | QTest::addColumn("converter"); 24 | TypeConverterTestBase::testConverterMeta_data(); 25 | } 26 | 27 | void MultiTypeConverterTestBase::testMetaTypeDetection_data() 28 | { 29 | QTest::addColumn("converter"); 30 | TypeConverterTestBase::testMetaTypeDetection_data(); 31 | } 32 | 33 | void MultiTypeConverterTestBase::testSerialization_data() 34 | { 35 | QTest::addColumn("converter"); 36 | TypeConverterTestBase::testSerialization_data(); 37 | } 38 | 39 | void MultiTypeConverterTestBase::testDeserialization_data() 40 | { 41 | QTest::addColumn("converter"); 42 | TypeConverterTestBase::testDeserialization_data(); 43 | } 44 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/TypeConverterTestLib/multitypeconvertertestbase.h: -------------------------------------------------------------------------------- 1 | #ifndef MULTITYPECONVERTERTESTBASE_H 2 | #define MULTITYPECONVERTERTESTBASE_H 3 | 4 | #include "typeconvertertestbase.h" 5 | 6 | class MultiTypeConverterTestBase : public TypeConverterTestBase 7 | { 8 | Q_OBJECT 9 | 10 | public: 11 | explicit MultiTypeConverterTestBase(QObject *parent = nullptr); 12 | 13 | protected: 14 | QtJsonSerializer::TypeConverter *converter() final; 15 | void testConverterIsRegistered_data() override; 16 | void testConverterMeta_data() override; 17 | void testMetaTypeDetection_data() override; 18 | void testSerialization_data() override; 19 | void testDeserialization_data() override; 20 | 21 | virtual void addConverterInstances() = 0; 22 | }; 23 | 24 | Q_DECLARE_METATYPE(QtJsonSerializer::TypeConverter*) 25 | 26 | #endif // MULTITYPECONVERTERTESTBASE_H 27 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/TypeConverterTestLib/opaquedummy.cpp: -------------------------------------------------------------------------------- 1 | #include "opaquedummy.h" 2 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/TypeConverterTestLib/opaquedummy.h: -------------------------------------------------------------------------------- 1 | #ifndef OPAQUEDUMMY_H 2 | #define OPAQUEDUMMY_H 3 | 4 | #include 5 | 6 | class OpaqueDummy {}; 7 | 8 | class OpaqueDummyGadget 9 | { 10 | Q_GADGET 11 | }; 12 | 13 | Q_DECLARE_METATYPE(OpaqueDummy) 14 | Q_DECLARE_METATYPE(OpaqueDummy*) 15 | Q_DECLARE_METATYPE(OpaqueDummyGadget) 16 | Q_DECLARE_METATYPE(OpaqueDummyGadget*) 17 | 18 | #endif // OPAQUEDUMMY_H 19 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/TypeConverterTestLib/typeconvertertestbase.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPECONVERTERTESTLIB_H 2 | #define TYPECONVERTERTESTLIB_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "dummyserializationhelper.h" 9 | #include "opaquedummy.h" 10 | 11 | class TypeConverterTestBase : public QObject 12 | { 13 | Q_OBJECT 14 | friend class MultiTypeConverterTestBase; 15 | 16 | public: 17 | using TestQ = QList; 18 | 19 | TypeConverterTestBase(QObject *parent = nullptr); 20 | 21 | protected: 22 | DummySerializationHelper * const helper; 23 | 24 | virtual QtJsonSerializer::TypeConverter *converter() = 0; 25 | 26 | virtual void initTest(); 27 | virtual void cleanupTest(); 28 | 29 | virtual void addConverterData() = 0; 30 | virtual void addMetaData() = 0; 31 | virtual void addCommonSerData(); 32 | virtual void addSerData(); 33 | virtual void addDeserData(); 34 | 35 | virtual bool compare(int type, 36 | QVariant &actual, 37 | QVariant &expected, 38 | const char *aName, 39 | const char *eName, 40 | const char *file, 41 | int line); 42 | 43 | private Q_SLOTS: 44 | void initTestCase(); 45 | void cleanupTestCase(); 46 | 47 | virtual void testConverterIsRegistered_data(); 48 | void testConverterIsRegistered(); 49 | virtual void testConverterMeta_data(); 50 | void testConverterMeta(); 51 | virtual void testMetaTypeDetection_data(); 52 | void testMetaTypeDetection(); 53 | virtual void testSerialization_data(); 54 | void testSerialization(); 55 | virtual void testDeserialization_data(); 56 | void testDeserialization(); 57 | }; 58 | 59 | Q_DECLARE_METATYPE(QCborValue::Type) 60 | Q_DECLARE_METATYPE(QJsonValue::Type) 61 | Q_DECLARE_METATYPE(QtJsonSerializer::TypeConverter::DeserializationCapabilityResult) 62 | 63 | #endif // TYPECONVERTERTESTLIB_H 64 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/VariantConverterTest/VariantConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_variantconverter 8 | 9 | include(../convlib.pri) 10 | 11 | SOURCES += \ 12 | tst_variantconverter.cpp 13 | 14 | include(../../testrun.pri) 15 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/VariantConverterTest/tst_variantconverter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "typeconvertertestbase.h" 5 | 6 | #include 7 | 8 | #include 9 | using namespace QtJsonSerializer; 10 | using namespace QtJsonSerializer::TypeConverters; 11 | 12 | using TestVar1 = std::variant; 13 | using TestVar2 = std::variant, QPair, QMap>; 14 | using TestVar3 = std::variant; 15 | 16 | Q_DECLARE_METATYPE(TestVar1) 17 | Q_DECLARE_METATYPE(TestVar2) 18 | Q_DECLARE_METATYPE(TestVar3) 19 | 20 | class VariantConverterTest : public TypeConverterTestBase 21 | { 22 | Q_OBJECT 23 | 24 | protected: 25 | void initTest() override; 26 | TypeConverter *converter() override; 27 | void addConverterData() override; 28 | void addMetaData() override; 29 | void addCommonSerData() override; 30 | void addSerData() override; 31 | void addDeserData() override; 32 | 33 | private: 34 | StdVariantConverter _converter; 35 | }; 36 | 37 | 38 | 39 | void VariantConverterTest::initTest() 40 | { 41 | JsonSerializer::registerVariantConverters(); 42 | JsonSerializer::registerVariantConverters, QPair, QMap>(); 43 | JsonSerializer::registerVariantConverters(); 44 | 45 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 46 | QMetaType::registerEqualsComparator(); 47 | #endif 48 | } 49 | 50 | TypeConverter *VariantConverterTest::converter() 51 | { 52 | return &_converter; 53 | } 54 | 55 | void VariantConverterTest::addConverterData() 56 | { 57 | QTest::newRow("variant") << static_cast(TypeConverter::Standard); 58 | } 59 | 60 | void VariantConverterTest::addMetaData() 61 | { 62 | QTest::newRow("basic") << qMetaTypeId>() 63 | << static_cast(CborSerializer::NoTag) 64 | << QCborValue::Double 65 | << true 66 | << TypeConverter::DeserializationCapabilityResult::Positive; 67 | QTest::newRow("extended") << qMetaTypeId, QPair, QMap>>() 68 | << static_cast(CborSerializer::NoTag) 69 | << QCborValue::Array 70 | << true 71 | << TypeConverter::DeserializationCapabilityResult::Positive; 72 | QTest::newRow("invalid") << static_cast(QMetaType::QVariant) 73 | << static_cast(CborSerializer::NoTag) 74 | << QCborValue::Null 75 | << false 76 | << TypeConverter::DeserializationCapabilityResult::Negative; 77 | } 78 | 79 | void VariantConverterTest::addCommonSerData() 80 | { 81 | QTest::newRow("basic.int") << QVariantHash{} 82 | << TestQ{{QMetaType::Int, 5, 1}} 83 | << static_cast(nullptr) 84 | << qMetaTypeId>() 85 | << QVariant::fromValue>(5) 86 | << QCborValue{1} 87 | << QJsonValue{1}; 88 | QTest::newRow("basic.bool") << QVariantHash{} 89 | << TestQ{{QMetaType::Bool, true, 2}} 90 | << static_cast(nullptr) 91 | << qMetaTypeId>() 92 | << QVariant::fromValue>(true) 93 | << QCborValue{2} 94 | << QJsonValue{2}; 95 | QTest::newRow("basic.double") << QVariantHash{} 96 | << TestQ{{QMetaType::Double, 7.3, 3}} 97 | << static_cast(nullptr) 98 | << qMetaTypeId>() 99 | << QVariant::fromValue>(7.3) 100 | << QCborValue{3} 101 | << QJsonValue{3}; 102 | } 103 | 104 | void VariantConverterTest::addSerData() 105 | { 106 | QTest::newRow("invalid.unconvertible") << QVariantHash{} 107 | << TestQ{} 108 | << static_cast(nullptr) 109 | << qMetaTypeId>() 110 | << QVariant::fromValue>(OpaqueDummy{}) 111 | << QCborValue{} 112 | << QJsonValue{QJsonValue::Undefined}; 113 | QTest::newRow("invalid.input") << QVariantHash{} 114 | << TestQ{} 115 | << static_cast(nullptr) 116 | << qMetaTypeId>() 117 | << QVariant::fromValue(QStringLiteral("Hello World")) 118 | << QCborValue{} 119 | << QJsonValue{QJsonValue::Undefined}; 120 | } 121 | 122 | void VariantConverterTest::addDeserData() 123 | { 124 | QTest::newRow("invalid") << QVariantHash{} 125 | << TestQ{} 126 | << static_cast(nullptr) 127 | << qMetaTypeId>() 128 | << QVariant{} 129 | << QCborValue{QStringLiteral("Hello World")} 130 | << QJsonValue{QStringLiteral("Hello World")}; 131 | } 132 | 133 | QTEST_MAIN(VariantConverterTest) 134 | 135 | #include "tst_variantconverter.moc" 136 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/VersionConverterTest/VersionConverterTest.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib jsonserializer 4 | CONFIG += console 5 | CONFIG -= app_bundle 6 | 7 | TARGET = tst_versionconverter 8 | 9 | include(../convlib.pri) 10 | 11 | SOURCES += \ 12 | tst_versionconverter.cpp 13 | 14 | include(../../testrun.pri) 15 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/VersionConverterTest/tst_versionconverter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "typeconvertertestbase.h" 5 | 6 | #include 7 | using namespace QtJsonSerializer; 8 | using namespace QtJsonSerializer::TypeConverters; 9 | 10 | class VersionConverterTest : public TypeConverterTestBase 11 | { 12 | Q_OBJECT 13 | 14 | protected: 15 | void initTest() override; 16 | TypeConverter *converter() override; 17 | void addConverterData() override; 18 | void addMetaData() override; 19 | void addCommonSerData() override; 20 | void addDeserData() override; 21 | 22 | private: 23 | VersionNumberConverter _converter; 24 | }; 25 | 26 | void VersionConverterTest::initTest() 27 | { 28 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 29 | QMetaType::registerEqualsComparator(); 30 | #endif 31 | } 32 | 33 | TypeConverter *VersionConverterTest::converter() 34 | { 35 | return &_converter; 36 | } 37 | 38 | void VersionConverterTest::addConverterData() 39 | { 40 | QTest::newRow("version") << static_cast(TypeConverter::Standard); 41 | } 42 | 43 | void VersionConverterTest::addMetaData() 44 | { 45 | QTest::newRow("array.tagged") << qMetaTypeId() 46 | << static_cast(CborSerializer::VersionNumber) 47 | << QCborValue::Array 48 | << true 49 | << TypeConverter::DeserializationCapabilityResult::Positive; 50 | QTest::newRow("array.untagged") << qMetaTypeId() 51 | << static_cast(CborSerializer::NoTag) 52 | << QCborValue::Array 53 | << true 54 | << TypeConverter::DeserializationCapabilityResult::Positive; 55 | QTest::newRow("array.guessed") << static_cast(QMetaType::UnknownType) 56 | << static_cast(CborSerializer::VersionNumber) 57 | << QCborValue::Array 58 | << false 59 | << TypeConverter::DeserializationCapabilityResult::Guessed; 60 | QTest::newRow("string.tagged") << qMetaTypeId() 61 | << static_cast(CborSerializer::VersionNumber) 62 | << QCborValue::String 63 | << true 64 | << TypeConverter::DeserializationCapabilityResult::Positive; 65 | QTest::newRow("string.untagged") << qMetaTypeId() 66 | << static_cast(CborSerializer::NoTag) 67 | << QCborValue::String 68 | << true 69 | << TypeConverter::DeserializationCapabilityResult::Positive; 70 | QTest::newRow("string.guessed") << static_cast(QMetaType::UnknownType) 71 | << static_cast(CborSerializer::VersionNumber) 72 | << QCborValue::String 73 | << false 74 | << TypeConverter::DeserializationCapabilityResult::Guessed; 75 | QTest::newRow("invalid.type") << static_cast(QMetaType::QString) 76 | << static_cast(CborSerializer::VersionNumber) 77 | << QCborValue::String 78 | << false 79 | << TypeConverter::DeserializationCapabilityResult::Negative; 80 | QTest::newRow("invalid.data") << qMetaTypeId() 81 | << static_cast(CborSerializer::VersionNumber) 82 | << QCborValue::ByteArray 83 | << true 84 | << TypeConverter::DeserializationCapabilityResult::Negative; 85 | QTest::newRow("invalid.tag") << qMetaTypeId() 86 | << static_cast(CborSerializer::Homogeneous) 87 | << QCborValue::Array 88 | << true 89 | << TypeConverter::DeserializationCapabilityResult::WrongTag; 90 | } 91 | 92 | void VersionConverterTest::addCommonSerData() 93 | { 94 | QTest::newRow("array") << QVariantHash{} 95 | << TestQ{} 96 | << static_cast(nullptr) 97 | << qMetaTypeId() 98 | << QVariant::fromValue(QVersionNumber{1, 2, 3, 4, 5}) 99 | << QCborValue{static_cast(CborSerializer::VersionNumber), QCborArray{1, 2, 3, 4, 5}} 100 | << QJsonValue{QJsonArray{1, 2, 3, 4, 5}}; 101 | QTest::newRow("array.empty") << QVariantHash{} 102 | << TestQ{} 103 | << static_cast(nullptr) 104 | << qMetaTypeId() 105 | << QVariant::fromValue(QVersionNumber{}) 106 | << QCborValue{static_cast(CborSerializer::VersionNumber), QCborArray{}} 107 | << QJsonValue{QJsonArray{}}; 108 | QTest::newRow("string") << QVariantHash{{QStringLiteral("versionAsString"), true}} 109 | << TestQ{} 110 | << static_cast(nullptr) 111 | << qMetaTypeId() 112 | << QVariant::fromValue(QVersionNumber{1, 2, 3, 4, 5}) 113 | << QCborValue{static_cast(CborSerializer::VersionNumber), QStringLiteral("1.2.3.4.5")} 114 | << QJsonValue{QStringLiteral("1.2.3.4.5")}; 115 | QTest::newRow("string.empty") << QVariantHash{{QStringLiteral("versionAsString"), true}} 116 | << TestQ{} 117 | << static_cast(nullptr) 118 | << qMetaTypeId() 119 | << QVariant::fromValue(QVersionNumber{}) 120 | << QCborValue{static_cast(CborSerializer::VersionNumber), QString{}} 121 | << QJsonValue{QString{}}; 122 | } 123 | 124 | void VersionConverterTest::addDeserData() 125 | { 126 | QTest::newRow("array.invalid") << QVariantHash{} 127 | << TestQ{} 128 | << static_cast(nullptr) 129 | << qMetaTypeId() 130 | << QVariant{} 131 | << QCborValue{static_cast(CborSerializer::VersionNumber), QCborArray{1, 2, 3, 4.5}} 132 | << QJsonValue{QJsonArray{1, 2, 3, 4.5}}; 133 | QTest::newRow("string.suffixed") << QVariantHash{{QStringLiteral("versionAsString"), true}} 134 | << TestQ{} 135 | << static_cast(nullptr) 136 | << qMetaTypeId() 137 | << QVariant::fromValue(QVersionNumber{1, 2, 3}) 138 | << QCborValue{static_cast(CborSerializer::VersionNumber), QStringLiteral("1.2.3-r1")} 139 | << QJsonValue{QStringLiteral("1.2.3-r1")}; 140 | QTest::newRow("string.invalid") << QVariantHash{{QStringLiteral("versionAsString"), true}} 141 | << TestQ{} 142 | << static_cast(nullptr) 143 | << qMetaTypeId() 144 | << QVariant{} 145 | << QCborValue{static_cast(CborSerializer::VersionNumber), QStringLiteral("A1.4.5")} 146 | << QJsonValue{QStringLiteral("A1.4.5")}; 147 | } 148 | 149 | QTEST_MAIN(VersionConverterTest) 150 | 151 | #include "tst_versionconverter.moc" 152 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/convlib.pri: -------------------------------------------------------------------------------- 1 | QT *= core testlib jsonserializer-private 2 | 3 | INCLUDEPATH += $$PWD/TypeConverterTestLib 4 | DEPENDPATH += $$PWD/TypeConverterTestLib 5 | 6 | win32:!win32-g++:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../TypeConverterTestLib/release/ -lTypeConverterTestLib 7 | else:win32:!win32-g++:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../TypeConverterTestLib/debug/ -lTypeConverterTestLib 8 | else: LIBS += -L$$OUT_PWD/../TypeConverterTestLib/ -lTypeConverterTestLib 9 | 10 | win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../TypeConverterTestLib/release/TypeConverterTestLib.lib 11 | else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../TypeConverterTestLib/debug/TypeConverterTestLib.lib 12 | else: PRE_TARGETDEPS += $$OUT_PWD/../TypeConverterTestLib/libTypeConverterTestLib.a 13 | -------------------------------------------------------------------------------- /tests/auto/jsonserializer/jsonserializer.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | TypeConverterTestLib \ 5 | SerializerTest 6 | 7 | CONVERTER_TESTS = \ 8 | BitArrayConverterTest \ 9 | BytearrayConverterTest \ 10 | CborConverterTest \ 11 | ChronoDurationConverterTest \ 12 | DateTimeConverterTest \ 13 | EnumConverterTest \ 14 | GadgetConverterTest \ 15 | GeomConverterTest \ 16 | LegacyGeomConverterTest \ 17 | ListConverterTest \ 18 | LocaleConverterTest \ 19 | MapConverterTest \ 20 | MultiMapConverterTest \ 21 | ObjectConverterTest \ 22 | OptionalConverterTest \ 23 | PairConverterTest \ 24 | SmartPointerConverterTest \ 25 | TupleConverterTest \ 26 | VariantConverterTest \ 27 | VersionConverterTest 28 | 29 | for(test, CONVERTER_TESTS) { 30 | SUBDIRS += $$test 31 | $${test}.depends += TypeConverterTestLib 32 | } 33 | 34 | prepareRecursiveTarget(run-tests) 35 | QMAKE_EXTRA_TARGETS += run-tests 36 | -------------------------------------------------------------------------------- /tests/auto/testrun.pri: -------------------------------------------------------------------------------- 1 | contains(debug_and_release, CONFIG): message(debug_and_release) 2 | 3 | debug_and_release:!ReleaseBuild:!DebugBuild { 4 | runtarget.target = run-tests 5 | runtarget.CONFIG = recursive 6 | runtarget.recurse_target = run-tests 7 | QMAKE_EXTRA_TARGETS += runtarget 8 | } else { 9 | oneshell.target = .ONESHELL 10 | QMAKE_EXTRA_TARGETS += oneshell 11 | 12 | win32:!win32-g++ { 13 | CONFIG(debug, debug|release): outdir_helper = debug 14 | CONFIG(release, debug|release): outdir_helper = release 15 | runtarget.target = run-tests 16 | !compat_test: runtarget.depends += $(DESTDIR_TARGET) 17 | runtarget.commands += set PATH=$$shell_path($$shadowed($$dirname(_QMAKE_CONF_))/bin);$$shell_path($$[QT_INSTALL_BINS]);$(PATH) 18 | runtarget.commands += $$escape_expand(\\n\\t)set QT_PLUGIN_PATH=$$shadowed($$dirname(_QMAKE_CONF_))/plugins;$$[QT_INSTALL_PLUGINS];$(QT_PLUGIN_PATH) 19 | runtarget.commands += $$escape_expand(\\n\\t)set QML2_IMPORT_PATH=$$shadowed($$dirname(_QMAKE_CONF_))/qml;$$[QT_INSTALL_QML];$(QML2_IMPORT_PATH) 20 | !isEmpty(LOGGING_RULES): runtarget.commands += $$escape_expand(\\n\\t)set \"QT_LOGGING_RULES=$$LOGGING_RULES\" 21 | runtarget.commands += $$escape_expand(\\n\\t)if exist $${outdir_helper}\\fail del $${outdir_helper}\\fail 22 | runtarget.commands += $$escape_expand(\\n\\t)start /w call $(DESTDIR_TARGET) ^> $${outdir_helper}\\test.log ^|^| echo FAIL ^> $${outdir_helper}\\fail ^& exit 0 23 | runtarget.commands += $$escape_expand(\\n\\t)type $${outdir_helper}\\test.log 24 | runtarget.commands += $$escape_expand(\\n\\t)if exist $${outdir_helper}\\fail exit 42 25 | QMAKE_EXTRA_TARGETS += runtarget 26 | } else { 27 | win32-g++: QMAKE_DIRLIST_SEP = ";" 28 | runtarget.commands += export PATH=\"$$shell_path($$shadowed($$dirname(_QMAKE_CONF_))/bin):$$shell_path($$[QT_INSTALL_BINS]):$${LITERAL_DOLLAR}$${LITERAL_DOLLAR}PATH\" 29 | runtarget.commands += $$escape_expand(\\n\\t)export QT_PLUGIN_PATH=\"$$shadowed($$dirname(_QMAKE_CONF_))/plugins$${QMAKE_DIRLIST_SEP}$$[QT_INSTALL_PLUGINS]$${QMAKE_DIRLIST_SEP}$(QT_PLUGIN_PATH)\" 30 | runtarget.commands += $$escape_expand(\\n\\t)export QML2_IMPORT_PATH=\"$$shadowed($$dirname(_QMAKE_CONF_))/qml$${QMAKE_DIRLIST_SEP}$$[QT_INSTALL_QML]$${QMAKE_DIRLIST_SEP}$(QML2_IMPORT_PATH)\" 31 | !isEmpty(LOGGING_RULES): runtarget.commands += $$escape_expand(\\n\\t)export QT_LOGGING_RULES=\"$$LOGGING_RULES\" 32 | win32-g++: QMAKE_DIRLIST_SEP = ":" 33 | 34 | linux|win32-g++ { 35 | runtarget.commands += $$escape_expand(\\n\\t)export LD_LIBRARY_PATH=\"$$shadowed($$dirname(_QMAKE_CONF_))/lib$${QMAKE_DIRLIST_SEP}$$[QT_INSTALL_LIBS]$${QMAKE_DIRLIST_SEP}$(LD_LIBRARY_PATH)\" 36 | runtarget.commands += $$escape_expand(\\n\\t)export QT_QPA_PLATFORM=minimal 37 | } else:mac { 38 | runtarget.commands += $$escape_expand(\\n\\t)export DYLD_LIBRARY_PATH=\"$$shadowed($$dirname(_QMAKE_CONF_))/lib:$$[QT_INSTALL_LIBS]:$(DYLD_LIBRARY_PATH)\" 39 | runtarget.commands += $$escape_expand(\\n\\t)export DYLD_FRAMEWORK_PATH=\"$$shadowed($$dirname(_QMAKE_CONF_))/lib:$$[QT_INSTALL_LIBS]:$(DYLD_FRAMEWORK_PATH)\" 40 | } 41 | 42 | runtarget.target = run-tests 43 | win32-g++ { 44 | !compat_test: runtarget.depends += $(DESTDIR_TARGET) 45 | runtarget.commands += $$escape_expand(\\n\\t)./$(DESTDIR_TARGET) 46 | } else { 47 | !compat_test: runtarget.depends += $(TARGET) 48 | runtarget.commands += $$escape_expand(\\n\\t)./$(TARGET) 49 | } 50 | QMAKE_EXTRA_TARGETS += runtarget 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/global/global.cfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/tests.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | CONFIG += no_docs_target 4 | 5 | SUBDIRS += auto 6 | 7 | OTHER_FILES += ../.github/workflows/build.yml 8 | 9 | prepareRecursiveTarget(run-tests) 10 | QMAKE_EXTRA_TARGETS += run-tests 11 | --------------------------------------------------------------------------------