├── .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 |
33 | $projectname
34 | $projectnumber
35 |
36 | $projectbrief
37 | |
38 |
39 |
40 |
41 |
42 | $projectbrief
43 | |
44 |
45 |
46 |
47 |
48 | $searchbox |
49 |
50 |
51 |
52 |
53 |
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 |