/src/oatpp/src/oatpp/parser/json/mapping/Serializer.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /*************************************************************************** |
2 | | * |
3 | | * Project _____ __ ____ _ _ |
4 | | * ( _ ) /__\ (_ _)_| |_ _| |_ |
5 | | * )(_)( /(__)\ )( (_ _)(_ _) |
6 | | * (_____)(__)(__)(__) |_| |_| |
7 | | * |
8 | | * |
9 | | * Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com> |
10 | | * |
11 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
12 | | * you may not use this file except in compliance with the License. |
13 | | * You may obtain a copy of the License at |
14 | | * |
15 | | * http://www.apache.org/licenses/LICENSE-2.0 |
16 | | * |
17 | | * Unless required by applicable law or agreed to in writing, software |
18 | | * distributed under the License is distributed on an "AS IS" BASIS, |
19 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
20 | | * See the License for the specific language governing permissions and |
21 | | * limitations under the License. |
22 | | * |
23 | | ***************************************************************************/ |
24 | | |
25 | | #include "Serializer.hpp" |
26 | | |
27 | | #include "oatpp/parser/json/Utils.hpp" |
28 | | #include "oatpp/core/data/mapping/type/Any.hpp" |
29 | | |
30 | | namespace oatpp { namespace parser { namespace json { namespace mapping { |
31 | | |
32 | | Serializer::Serializer(const std::shared_ptr<Config>& config) |
33 | | : m_config(config) |
34 | 1.63k | { |
35 | | |
36 | 1.63k | m_methods.resize(static_cast<size_t>(data::mapping::type::ClassId::getClassCount()), nullptr); |
37 | | |
38 | 1.63k | setSerializerMethod(data::mapping::type::__class::String::CLASS_ID, &Serializer::serializeString); |
39 | 1.63k | setSerializerMethod(data::mapping::type::__class::Any::CLASS_ID, &Serializer::serializeAny); |
40 | | |
41 | 1.63k | setSerializerMethod(data::mapping::type::__class::Int8::CLASS_ID, &Serializer::serializePrimitive<oatpp::Int8>); |
42 | 1.63k | setSerializerMethod(data::mapping::type::__class::UInt8::CLASS_ID, &Serializer::serializePrimitive<oatpp::UInt8>); |
43 | | |
44 | 1.63k | setSerializerMethod(data::mapping::type::__class::Int16::CLASS_ID, &Serializer::serializePrimitive<oatpp::Int16>); |
45 | 1.63k | setSerializerMethod(data::mapping::type::__class::UInt16::CLASS_ID, &Serializer::serializePrimitive<oatpp::UInt16>); |
46 | | |
47 | 1.63k | setSerializerMethod(data::mapping::type::__class::Int32::CLASS_ID, &Serializer::serializePrimitive<oatpp::Int32>); |
48 | 1.63k | setSerializerMethod(data::mapping::type::__class::UInt32::CLASS_ID, &Serializer::serializePrimitive<oatpp::UInt32>); |
49 | | |
50 | 1.63k | setSerializerMethod(data::mapping::type::__class::Int64::CLASS_ID, &Serializer::serializePrimitive<oatpp::Int64>); |
51 | 1.63k | setSerializerMethod(data::mapping::type::__class::UInt64::CLASS_ID, &Serializer::serializePrimitive<oatpp::UInt64>); |
52 | | |
53 | 1.63k | setSerializerMethod(data::mapping::type::__class::Float32::CLASS_ID, &Serializer::serializePrimitive<oatpp::Float32>); |
54 | 1.63k | setSerializerMethod(data::mapping::type::__class::Float64::CLASS_ID, &Serializer::serializePrimitive<oatpp::Float64>); |
55 | 1.63k | setSerializerMethod(data::mapping::type::__class::Boolean::CLASS_ID, &Serializer::serializePrimitive<oatpp::Boolean>); |
56 | | |
57 | 1.63k | setSerializerMethod(data::mapping::type::__class::AbstractObject::CLASS_ID, &Serializer::serializeObject); |
58 | 1.63k | setSerializerMethod(data::mapping::type::__class::AbstractEnum::CLASS_ID, &Serializer::serializeEnum); |
59 | | |
60 | 1.63k | setSerializerMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &Serializer::serializeCollection); |
61 | 1.63k | setSerializerMethod(data::mapping::type::__class::AbstractList::CLASS_ID, &Serializer::serializeCollection); |
62 | 1.63k | setSerializerMethod(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID, &Serializer::serializeCollection); |
63 | | |
64 | 1.63k | setSerializerMethod(data::mapping::type::__class::AbstractPairList::CLASS_ID, &Serializer::serializeMap); |
65 | 1.63k | setSerializerMethod(data::mapping::type::__class::AbstractUnorderedMap::CLASS_ID, &Serializer::serializeMap); |
66 | | |
67 | 1.63k | } |
68 | | |
69 | 32.6k | void Serializer::setSerializerMethod(const data::mapping::type::ClassId& classId, SerializerMethod method) { |
70 | 32.6k | const v_uint32 id = static_cast<v_uint32>(classId.id); |
71 | 32.6k | if(id >= m_methods.size()) { |
72 | 0 | m_methods.resize(id + 1, nullptr); |
73 | 0 | } |
74 | 32.6k | m_methods[id] = method; |
75 | 32.6k | } |
76 | | |
77 | 0 | void Serializer::serializeString(data::stream::ConsistentOutputStream* stream, const char* data, v_buff_size size, v_uint32 escapeFlags) { |
78 | 0 | auto encodedValue = Utils::escapeString(data, size, escapeFlags); |
79 | 0 | stream->writeCharSimple('\"'); |
80 | 0 | stream->writeSimple(encodedValue); |
81 | 0 | stream->writeCharSimple('\"'); |
82 | 0 | } |
83 | | |
84 | | void Serializer::serializeString(Serializer* serializer, |
85 | | data::stream::ConsistentOutputStream* stream, |
86 | | const oatpp::Void& polymorph) |
87 | 0 | { |
88 | |
|
89 | 0 | if(!polymorph) { |
90 | 0 | stream->writeSimple("null", 4); |
91 | 0 | return; |
92 | 0 | } |
93 | | |
94 | 0 | auto str = static_cast<std::string*>(polymorph.get()); |
95 | |
|
96 | 0 | serializeString(stream, str->data(), static_cast<v_buff_size>(str->size()), serializer->m_config->escapeFlags); |
97 | |
|
98 | 0 | } |
99 | | |
100 | | void Serializer::serializeAny(Serializer* serializer, |
101 | | data::stream::ConsistentOutputStream* stream, |
102 | | const oatpp::Void& polymorph) |
103 | 0 | { |
104 | |
|
105 | 0 | if(!polymorph) { |
106 | 0 | stream->writeSimple("null", 4); |
107 | 0 | return; |
108 | 0 | } |
109 | | |
110 | 0 | auto anyHandle = static_cast<data::mapping::type::AnyHandle*>(polymorph.get()); |
111 | 0 | serializer->serialize(stream, oatpp::Void(anyHandle->ptr, anyHandle->type)); |
112 | |
|
113 | 0 | } |
114 | | |
115 | | void Serializer::serializeEnum(Serializer* serializer, |
116 | | data::stream::ConsistentOutputStream* stream, |
117 | | const oatpp::Void& polymorph) |
118 | 0 | { |
119 | 0 | auto polymorphicDispatcher = static_cast<const data::mapping::type::__class::AbstractEnum::PolymorphicDispatcher*>( |
120 | 0 | polymorph.getValueType()->polymorphicDispatcher |
121 | 0 | ); |
122 | |
|
123 | 0 | data::mapping::type::EnumInterpreterError e = data::mapping::type::EnumInterpreterError::OK; |
124 | 0 | serializer->serialize(stream, polymorphicDispatcher->toInterpretation(polymorph, e)); |
125 | |
|
126 | 0 | if(e == data::mapping::type::EnumInterpreterError::OK) { |
127 | 0 | return; |
128 | 0 | } |
129 | | |
130 | 0 | switch(e) { |
131 | 0 | case data::mapping::type::EnumInterpreterError::CONSTRAINT_NOT_NULL: |
132 | 0 | throw std::runtime_error("[oatpp::parser::json::mapping::Serializer::serializeEnum()]: Error. Enum constraint violated - 'NotNull'."); |
133 | 0 | case data::mapping::type::EnumInterpreterError::OK: |
134 | 0 | case data::mapping::type::EnumInterpreterError::TYPE_MISMATCH_ENUM: |
135 | 0 | case data::mapping::type::EnumInterpreterError::TYPE_MISMATCH_ENUM_VALUE: |
136 | 0 | case data::mapping::type::EnumInterpreterError::ENTRY_NOT_FOUND: |
137 | 0 | default: |
138 | 0 | throw std::runtime_error("[oatpp::parser::json::mapping::Serializer::serializeEnum()]: Error. Can't serialize Enum."); |
139 | 0 | } |
140 | |
|
141 | 0 | } |
142 | | |
143 | | void Serializer::serializeCollection(Serializer* serializer, |
144 | | data::stream::ConsistentOutputStream* stream, |
145 | | const oatpp::Void& polymorph) |
146 | 0 | { |
147 | |
|
148 | 0 | if(!polymorph) { |
149 | 0 | stream->writeSimple("null", 4); |
150 | 0 | return; |
151 | 0 | } |
152 | | |
153 | 0 | auto dispatcher = static_cast<const data::mapping::type::__class::Collection::PolymorphicDispatcher*>( |
154 | 0 | polymorph.getValueType()->polymorphicDispatcher |
155 | 0 | ); |
156 | |
|
157 | 0 | stream->writeCharSimple('['); |
158 | 0 | bool first = true; |
159 | |
|
160 | 0 | auto iterator = dispatcher->beginIteration(polymorph); |
161 | |
|
162 | 0 | while (!iterator->finished()) { |
163 | 0 | const auto& value = iterator->get(); |
164 | 0 | if(value || serializer->getConfig()->includeNullFields || serializer->getConfig()->alwaysIncludeNullCollectionElements) { |
165 | 0 | (first) ? first = false : stream->writeSimple(",", 1); |
166 | 0 | serializer->serialize(stream, value); |
167 | 0 | } |
168 | 0 | iterator->next(); |
169 | 0 | } |
170 | |
|
171 | 0 | stream->writeCharSimple(']'); |
172 | |
|
173 | 0 | } |
174 | | |
175 | | void Serializer::serializeMap(Serializer* serializer, |
176 | | data::stream::ConsistentOutputStream* stream, |
177 | | const oatpp::Void& polymorph) |
178 | 0 | { |
179 | |
|
180 | 0 | if(!polymorph) { |
181 | 0 | stream->writeSimple("null", 4); |
182 | 0 | return; |
183 | 0 | } |
184 | | |
185 | 0 | auto dispatcher = static_cast<const data::mapping::type::__class::Map::PolymorphicDispatcher*>( |
186 | 0 | polymorph.getValueType()->polymorphicDispatcher |
187 | 0 | ); |
188 | |
|
189 | 0 | auto keyType = dispatcher->getKeyType(); |
190 | 0 | if(keyType->classId != oatpp::String::Class::CLASS_ID){ |
191 | 0 | throw std::runtime_error("[oatpp::parser::json::mapping::Serializer::serializeMap()]: Invalid json map key. Key should be String"); |
192 | 0 | } |
193 | | |
194 | 0 | stream->writeCharSimple('{'); |
195 | 0 | bool first = true; |
196 | |
|
197 | 0 | auto iterator = dispatcher->beginIteration(polymorph); |
198 | |
|
199 | 0 | while (!iterator->finished()) { |
200 | 0 | const auto& value = iterator->getValue(); |
201 | 0 | if(value || serializer->m_config->includeNullFields || serializer->m_config->alwaysIncludeNullCollectionElements) { |
202 | 0 | (first) ? first = false : stream->writeSimple(",", 1); |
203 | 0 | const auto& untypedKey = iterator->getKey(); |
204 | 0 | const auto& key = oatpp::String(std::static_pointer_cast<std::string>(untypedKey.getPtr())); |
205 | 0 | serializeString(stream, key->data(), static_cast<v_buff_size>(key->size()), serializer->m_config->escapeFlags); |
206 | 0 | stream->writeSimple(":", 1); |
207 | 0 | serializer->serialize(stream, value); |
208 | 0 | } |
209 | 0 | iterator->next(); |
210 | 0 | } |
211 | |
|
212 | 0 | stream->writeCharSimple('}'); |
213 | |
|
214 | 0 | } |
215 | | |
216 | | void Serializer::serializeObject(Serializer* serializer, |
217 | | data::stream::ConsistentOutputStream* stream, |
218 | | const oatpp::Void& polymorph) |
219 | 0 | { |
220 | |
|
221 | 0 | if(!polymorph) { |
222 | 0 | stream->writeSimple("null", 4); |
223 | 0 | return; |
224 | 0 | } |
225 | | |
226 | 0 | stream->writeCharSimple('{'); |
227 | |
|
228 | 0 | bool first = true; |
229 | 0 | auto type = polymorph.getValueType(); |
230 | 0 | auto dispatcher = static_cast<const oatpp::data::mapping::type::__class::AbstractObject::PolymorphicDispatcher*>( |
231 | 0 | type->polymorphicDispatcher |
232 | 0 | ); |
233 | 0 | auto fields = dispatcher->getProperties()->getList(); |
234 | 0 | auto object = static_cast<oatpp::BaseObject*>(polymorph.get()); |
235 | 0 | auto config = serializer->m_config; |
236 | |
|
237 | 0 | for (auto const& field : fields) { |
238 | |
|
239 | 0 | oatpp::Void value; |
240 | 0 | if(field->info.typeSelector && field->type == oatpp::Any::Class::getType()) { |
241 | 0 | const auto& any = field->get(object).cast<oatpp::Any>(); |
242 | 0 | value = any.retrieve(field->info.typeSelector->selectType(object)); |
243 | 0 | } else { |
244 | 0 | value = field->get(object); |
245 | 0 | } |
246 | |
|
247 | 0 | if(field->info.required && value == nullptr) { |
248 | 0 | throw std::runtime_error("[oatpp::parser::json::mapping::Serializer::serialize()]: " |
249 | 0 | "Error. " + std::string(type->nameQualifier) + "::" |
250 | 0 | + std::string(field->name) + " is required!"); |
251 | 0 | } |
252 | | |
253 | 0 | if (value || config->includeNullFields || (field->info.required && config->alwaysIncludeRequired)) { |
254 | 0 | (first) ? first = false : stream->writeSimple(",", 1); |
255 | 0 | serializeString(stream, field->name, static_cast<v_buff_size>(std::strlen(field->name)), serializer->m_config->escapeFlags); |
256 | 0 | stream->writeSimple(":", 1); |
257 | 0 | serializer->serialize(stream, value); |
258 | 0 | } |
259 | |
|
260 | 0 | } |
261 | | |
262 | 0 | stream->writeCharSimple('}'); |
263 | |
|
264 | 0 | } |
265 | | |
266 | | void Serializer::serialize(data::stream::ConsistentOutputStream* stream, |
267 | | const oatpp::Void& polymorph) |
268 | 0 | { |
269 | 0 | auto id = static_cast<v_uint32>(polymorph.getValueType()->classId.id); |
270 | 0 | auto& method = m_methods[id]; |
271 | 0 | if(method) { |
272 | 0 | (*method)(this, stream, polymorph); |
273 | 0 | } else { |
274 | |
|
275 | 0 | auto* interpretation = polymorph.getValueType()->findInterpretation(m_config->enabledInterpretations); |
276 | 0 | if(interpretation) { |
277 | 0 | serialize(stream, interpretation->toInterpretation(polymorph)); |
278 | 0 | } else { |
279 | 0 | throw std::runtime_error("[oatpp::parser::json::mapping::Serializer::serialize()]: " |
280 | 0 | "Error. No serialize method for type '" + |
281 | 0 | std::string(polymorph.getValueType()->classId.name) + "'"); |
282 | 0 | } |
283 | |
|
284 | 0 | } |
285 | 0 | } |
286 | | |
287 | | void Serializer::serializeToStream(data::stream::ConsistentOutputStream* stream, |
288 | | const oatpp::Void& polymorph) |
289 | 0 | { |
290 | 0 | if(m_config->useBeautifier) { |
291 | 0 | json::Beautifier beautifier(stream, " ", "\n"); |
292 | 0 | serialize(&beautifier, polymorph); |
293 | 0 | } else { |
294 | 0 | serialize(stream, polymorph); |
295 | 0 | } |
296 | 0 | } |
297 | | |
298 | 0 | const std::shared_ptr<Serializer::Config>& Serializer::getConfig() { |
299 | 0 | return m_config; |
300 | 0 | } |
301 | | |
302 | | }}}} |