Coverage Report

Created: 2024-02-11 06:09

/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.60k
{
35
36
1.60k
  m_methods.resize(static_cast<size_t>(data::mapping::type::ClassId::getClassCount()), nullptr);
37
38
1.60k
  setSerializerMethod(data::mapping::type::__class::String::CLASS_ID, &Serializer::serializeString);
39
1.60k
  setSerializerMethod(data::mapping::type::__class::Any::CLASS_ID, &Serializer::serializeAny);
40
41
1.60k
  setSerializerMethod(data::mapping::type::__class::Int8::CLASS_ID, &Serializer::serializePrimitive<oatpp::Int8>);
42
1.60k
  setSerializerMethod(data::mapping::type::__class::UInt8::CLASS_ID, &Serializer::serializePrimitive<oatpp::UInt8>);
43
44
1.60k
  setSerializerMethod(data::mapping::type::__class::Int16::CLASS_ID, &Serializer::serializePrimitive<oatpp::Int16>);
45
1.60k
  setSerializerMethod(data::mapping::type::__class::UInt16::CLASS_ID, &Serializer::serializePrimitive<oatpp::UInt16>);
46
47
1.60k
  setSerializerMethod(data::mapping::type::__class::Int32::CLASS_ID, &Serializer::serializePrimitive<oatpp::Int32>);
48
1.60k
  setSerializerMethod(data::mapping::type::__class::UInt32::CLASS_ID, &Serializer::serializePrimitive<oatpp::UInt32>);
49
50
1.60k
  setSerializerMethod(data::mapping::type::__class::Int64::CLASS_ID, &Serializer::serializePrimitive<oatpp::Int64>);
51
1.60k
  setSerializerMethod(data::mapping::type::__class::UInt64::CLASS_ID, &Serializer::serializePrimitive<oatpp::UInt64>);
52
53
1.60k
  setSerializerMethod(data::mapping::type::__class::Float32::CLASS_ID, &Serializer::serializePrimitive<oatpp::Float32>);
54
1.60k
  setSerializerMethod(data::mapping::type::__class::Float64::CLASS_ID, &Serializer::serializePrimitive<oatpp::Float64>);
55
1.60k
  setSerializerMethod(data::mapping::type::__class::Boolean::CLASS_ID, &Serializer::serializePrimitive<oatpp::Boolean>);
56
57
1.60k
  setSerializerMethod(data::mapping::type::__class::AbstractObject::CLASS_ID, &Serializer::serializeObject);
58
1.60k
  setSerializerMethod(data::mapping::type::__class::AbstractEnum::CLASS_ID, &Serializer::serializeEnum);
59
60
1.60k
  setSerializerMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &Serializer::serializeCollection);
61
1.60k
  setSerializerMethod(data::mapping::type::__class::AbstractList::CLASS_ID, &Serializer::serializeCollection);
62
1.60k
  setSerializerMethod(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID, &Serializer::serializeCollection);
63
64
1.60k
  setSerializerMethod(data::mapping::type::__class::AbstractPairList::CLASS_ID, &Serializer::serializeMap);
65
1.60k
  setSerializerMethod(data::mapping::type::__class::AbstractUnorderedMap::CLASS_ID, &Serializer::serializeMap);
66
67
1.60k
}
68
69
32.0k
void Serializer::setSerializerMethod(const data::mapping::type::ClassId& classId, SerializerMethod method) {
70
32.0k
  const v_uint32 id = static_cast<v_uint32>(classId.id);
71
32.0k
  if(id >= m_methods.size()) {
72
0
    m_methods.resize(id + 1, nullptr);
73
0
  }
74
32.0k
  m_methods[id] = method;
75
32.0k
}
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
}}}}