mirror of
https://github.com/oatpp/oatpp.git
synced 2024-11-21 03:14:51 +08:00
json::ObjectMapper: use mapping::Tree
This commit is contained in:
parent
77ca525d2c
commit
b890a15840
@ -120,11 +120,6 @@ void ObjectToTreeMapper::mapAny(const ObjectToTreeMapper* mapper, MappingState&
|
||||
|
||||
void ObjectToTreeMapper::mapEnum(const ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph) {
|
||||
|
||||
if(!polymorph) {
|
||||
state.tree->setNull();
|
||||
return;
|
||||
}
|
||||
|
||||
auto polymorphicDispatcher = static_cast<const data::mapping::type::__class::AbstractEnum::PolymorphicDispatcher*>(
|
||||
polymorph.getValueType()->polymorphicDispatcher
|
||||
);
|
||||
|
@ -26,34 +26,39 @@
|
||||
|
||||
namespace oatpp { namespace json {
|
||||
|
||||
ObjectMapper::ObjectMapper(const std::shared_ptr<Serializer::Config>& serializerConfig,
|
||||
ObjectMapper::ObjectMapper(const std::shared_ptr<SerializerConfig>& serializerConfig,
|
||||
const std::shared_ptr<DeserializerConfig>& deserializerConfig)
|
||||
: data::mapping::ObjectMapper(getMapperInfo())
|
||||
, m_serializer(std::make_shared<Serializer>(serializerConfig))
|
||||
, m_serializerConfig(serializerConfig)
|
||||
, m_deserializerConfig(deserializerConfig)
|
||||
{}
|
||||
|
||||
ObjectMapper::ObjectMapper(const std::shared_ptr<Serializer>& serializer)
|
||||
: data::mapping::ObjectMapper(getMapperInfo())
|
||||
, m_serializer(serializer)
|
||||
, m_deserializerConfig(std::make_shared<DeserializerConfig>())
|
||||
{}
|
||||
|
||||
std::shared_ptr<ObjectMapper> ObjectMapper::createShared(const std::shared_ptr<Serializer::Config>& serializerConfig,
|
||||
std::shared_ptr<ObjectMapper> ObjectMapper::createShared(const std::shared_ptr<SerializerConfig>& serializerConfig,
|
||||
const std::shared_ptr<DeserializerConfig>& deserializerConfig)
|
||||
{
|
||||
return std::make_shared<ObjectMapper>(serializerConfig, deserializerConfig);
|
||||
}
|
||||
|
||||
std::shared_ptr<ObjectMapper> ObjectMapper::createShared(const std::shared_ptr<Serializer>& serializer,
|
||||
const std::shared_ptr<Deserializer>& deserializer)
|
||||
{
|
||||
return std::make_shared<ObjectMapper>(serializer);
|
||||
}
|
||||
void ObjectMapper::write(data::stream::ConsistentOutputStream* stream, const oatpp::Void& variant) const {
|
||||
|
||||
data::mapping::Tree tree;
|
||||
{
|
||||
data::mapping::ObjectToTreeMapper::MappingState state;
|
||||
state.config = m_serializerConfig.get();
|
||||
state.tree = &tree;
|
||||
m_objectToTreeMapper.map(state, variant);
|
||||
if(!state.errorStack.empty()) {
|
||||
throw std::runtime_error(state.errorStacktrace());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Serializer::MappingState state;
|
||||
state.config = m_serializerConfig.get();
|
||||
state.tree = &tree;
|
||||
Serializer::serializeToStream(stream, state);
|
||||
}
|
||||
|
||||
void ObjectMapper::write(data::stream::ConsistentOutputStream* stream,
|
||||
const oatpp::Void& variant) const {
|
||||
m_serializer->serializeToStream(stream, variant);
|
||||
}
|
||||
|
||||
oatpp::Void ObjectMapper::read(oatpp::utils::parser::Caret& caret, const oatpp::data::mapping::type::Type* const type) const {
|
||||
@ -90,8 +95,8 @@ oatpp::Void ObjectMapper::read(oatpp::utils::parser::Caret& caret, const oatpp::
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<Serializer> ObjectMapper::getSerializer() {
|
||||
return m_serializer;
|
||||
std::shared_ptr<ObjectMapper::SerializerConfig> ObjectMapper::getSerializerConfig() {
|
||||
return m_serializerConfig;
|
||||
}
|
||||
|
||||
std::shared_ptr<ObjectMapper::DeserializerConfig> ObjectMapper::getDeserializerConfig() {
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "./Serializer.hpp"
|
||||
#include "./Deserializer.hpp"
|
||||
|
||||
#include "oatpp/data/mapping/ObjectToTreeMapper.hpp"
|
||||
#include "oatpp/data/mapping/TreeToObjectMapper.hpp"
|
||||
#include "oatpp/data/mapping/ObjectMapper.hpp"
|
||||
|
||||
@ -50,51 +51,31 @@ public:
|
||||
class DeserializerConfig : public data::mapping::TreeToObjectMapper::Config, public Deserializer::Config {
|
||||
public:
|
||||
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
class SerializerConfig : public data::mapping::ObjectToTreeMapper::Config, public Serializer::Config {
|
||||
public:
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
std::shared_ptr<Serializer> m_serializer;
|
||||
std::shared_ptr<SerializerConfig> m_serializerConfig;
|
||||
std::shared_ptr<DeserializerConfig> m_deserializerConfig;
|
||||
private:
|
||||
data::mapping::ObjectToTreeMapper m_objectToTreeMapper;
|
||||
data::mapping::TreeToObjectMapper m_treeToObjectMapper;
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param serializerConfig - &id:oatpp::json::Serializer::Config;.
|
||||
* @param deserializerConfig - &id:oatpp::json::Deserializer::Config;.
|
||||
*/
|
||||
ObjectMapper(const std::shared_ptr<Serializer::Config>& serializerConfig,
|
||||
const std::shared_ptr<DeserializerConfig>& deserializerConfig);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param serializer
|
||||
* @param deserializer
|
||||
*/
|
||||
ObjectMapper(const std::shared_ptr<Serializer>& serializer = std::make_shared<Serializer>());
|
||||
ObjectMapper(const std::shared_ptr<SerializerConfig>& serializerConfig = std::make_shared<SerializerConfig>(),
|
||||
const std::shared_ptr<DeserializerConfig>& deserializerConfig = std::make_shared<DeserializerConfig>());
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create shared ObjectMapper.
|
||||
* @param serializerConfig - &id:oatpp::json::Serializer::Config;.
|
||||
* @param deserializerConfig - &id:oatpp::json::Deserializer::Config;.
|
||||
* @return - `std::shared_ptr` to ObjectMapper.
|
||||
*/
|
||||
static std::shared_ptr<ObjectMapper>
|
||||
createShared(const std::shared_ptr<Serializer::Config>& serializerConfig,
|
||||
const std::shared_ptr<DeserializerConfig>& deserializerConfig);
|
||||
|
||||
/**
|
||||
* Create shared ObjectMapper.
|
||||
* @param serializer
|
||||
* @param deserializer
|
||||
* @return
|
||||
*/
|
||||
static std::shared_ptr<ObjectMapper>
|
||||
createShared(const std::shared_ptr<Serializer>& serializer = std::make_shared<Serializer>(),
|
||||
const std::shared_ptr<Deserializer>& deserializer = std::make_shared<Deserializer>());
|
||||
createShared(const std::shared_ptr<SerializerConfig>& serializerConfig = std::make_shared<SerializerConfig>(),
|
||||
const std::shared_ptr<DeserializerConfig>& deserializerConfig = std::make_shared<DeserializerConfig>());
|
||||
|
||||
/**
|
||||
* Implementation of &id:oatpp::data::mapping::ObjectMapper::write;.
|
||||
@ -112,16 +93,8 @@ public:
|
||||
oatpp::Void read(oatpp::utils::parser::Caret& caret, const oatpp::data::mapping::type::Type* const type) const override;
|
||||
|
||||
|
||||
/**
|
||||
* Get serializer.
|
||||
* @return
|
||||
*/
|
||||
std::shared_ptr<Serializer> getSerializer();
|
||||
std::shared_ptr<ObjectMapper::SerializerConfig> getSerializerConfig();
|
||||
|
||||
/**
|
||||
* Get deserializer.
|
||||
* @return
|
||||
*/
|
||||
std::shared_ptr<DeserializerConfig> getDeserializerConfig();
|
||||
|
||||
};
|
||||
|
@ -25,53 +25,17 @@
|
||||
#include "Serializer.hpp"
|
||||
|
||||
#include "./Utils.hpp"
|
||||
#include "oatpp/data/mapping/type/Any.hpp"
|
||||
#include "oatpp/data/stream/BufferStream.hpp"
|
||||
#include "oatpp/utils/Conversion.hpp"
|
||||
|
||||
namespace oatpp { namespace json {
|
||||
|
||||
Serializer::Serializer(const std::shared_ptr<Config>& config)
|
||||
: m_config(config)
|
||||
{
|
||||
|
||||
m_methods.resize(static_cast<size_t>(data::mapping::type::ClassId::getClassCount()), nullptr);
|
||||
|
||||
setSerializerMethod(data::mapping::type::__class::String::CLASS_ID, &Serializer::serializeString);
|
||||
setSerializerMethod(data::mapping::type::__class::Any::CLASS_ID, &Serializer::serializeAny);
|
||||
|
||||
setSerializerMethod(data::mapping::type::__class::Int8::CLASS_ID, &Serializer::serializePrimitive<oatpp::Int8>);
|
||||
setSerializerMethod(data::mapping::type::__class::UInt8::CLASS_ID, &Serializer::serializePrimitive<oatpp::UInt8>);
|
||||
|
||||
setSerializerMethod(data::mapping::type::__class::Int16::CLASS_ID, &Serializer::serializePrimitive<oatpp::Int16>);
|
||||
setSerializerMethod(data::mapping::type::__class::UInt16::CLASS_ID, &Serializer::serializePrimitive<oatpp::UInt16>);
|
||||
|
||||
setSerializerMethod(data::mapping::type::__class::Int32::CLASS_ID, &Serializer::serializePrimitive<oatpp::Int32>);
|
||||
setSerializerMethod(data::mapping::type::__class::UInt32::CLASS_ID, &Serializer::serializePrimitive<oatpp::UInt32>);
|
||||
|
||||
setSerializerMethod(data::mapping::type::__class::Int64::CLASS_ID, &Serializer::serializePrimitive<oatpp::Int64>);
|
||||
setSerializerMethod(data::mapping::type::__class::UInt64::CLASS_ID, &Serializer::serializePrimitive<oatpp::UInt64>);
|
||||
|
||||
setSerializerMethod(data::mapping::type::__class::Float32::CLASS_ID, &Serializer::serializePrimitive<oatpp::Float32>);
|
||||
setSerializerMethod(data::mapping::type::__class::Float64::CLASS_ID, &Serializer::serializePrimitive<oatpp::Float64>);
|
||||
setSerializerMethod(data::mapping::type::__class::Boolean::CLASS_ID, &Serializer::serializePrimitive<oatpp::Boolean>);
|
||||
|
||||
setSerializerMethod(data::mapping::type::__class::AbstractObject::CLASS_ID, &Serializer::serializeObject);
|
||||
setSerializerMethod(data::mapping::type::__class::AbstractEnum::CLASS_ID, &Serializer::serializeEnum);
|
||||
|
||||
setSerializerMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &Serializer::serializeCollection);
|
||||
setSerializerMethod(data::mapping::type::__class::AbstractList::CLASS_ID, &Serializer::serializeCollection);
|
||||
setSerializerMethod(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID, &Serializer::serializeCollection);
|
||||
|
||||
setSerializerMethod(data::mapping::type::__class::AbstractPairList::CLASS_ID, &Serializer::serializeMap);
|
||||
setSerializerMethod(data::mapping::type::__class::AbstractUnorderedMap::CLASS_ID, &Serializer::serializeMap);
|
||||
|
||||
}
|
||||
|
||||
void Serializer::setSerializerMethod(const data::mapping::type::ClassId& classId, SerializerMethod method) {
|
||||
const v_uint32 id = static_cast<v_uint32>(classId.id);
|
||||
if(id >= m_methods.size()) {
|
||||
m_methods.resize(id + 1, nullptr);
|
||||
oatpp::String Serializer::MappingState::errorStacktrace() const {
|
||||
data::stream::BufferOutputStream ss;
|
||||
for(auto& s : errorStack) {
|
||||
ss << s << "\n";
|
||||
}
|
||||
m_methods[id] = method;
|
||||
return ss.toString();
|
||||
}
|
||||
|
||||
void Serializer::serializeString(data::stream::ConsistentOutputStream* stream, const char* data, v_buff_size size, v_uint32 escapeFlags) {
|
||||
@ -81,222 +45,188 @@ void Serializer::serializeString(data::stream::ConsistentOutputStream* stream, c
|
||||
stream->writeCharSimple('\"');
|
||||
}
|
||||
|
||||
void Serializer::serializeString(Serializer* serializer,
|
||||
data::stream::ConsistentOutputStream* stream,
|
||||
const oatpp::Void& polymorph)
|
||||
{
|
||||
void Serializer::serializeNull(MappingState& state) {
|
||||
state.stream->writeSimple("null");
|
||||
}
|
||||
|
||||
void Serializer::serializeString(MappingState& state) {
|
||||
const auto& str = state.tree->getString();
|
||||
serializeString(state.stream, str->data(), static_cast<v_buff_size>(str->size()), state.config->escapeFlags);
|
||||
}
|
||||
|
||||
void Serializer::serializeArray(MappingState& state) {
|
||||
|
||||
state.stream->writeCharSimple('[');
|
||||
|
||||
MappingState nestedState;
|
||||
nestedState.stream = state.stream;
|
||||
nestedState.config = state.config;
|
||||
|
||||
auto& vector = state.tree->getVector();
|
||||
|
||||
v_int64 index = 0;
|
||||
for(auto& tree : vector) {
|
||||
|
||||
nestedState.tree = &tree;
|
||||
|
||||
if(!tree.isNull() || state.config->includeNullElements) {
|
||||
|
||||
if(index > 0) state.stream->writeSimple(",", 1);
|
||||
|
||||
serialize(nestedState);
|
||||
|
||||
if(!nestedState.errorStack.empty()) {
|
||||
state.errorStack.splice(state.errorStack.end(), nestedState.errorStack);
|
||||
state.errorStack.emplace_back("[oatpp::json::Serializer::serializeArray()]: index=" + utils::Conversion::int64ToStr(index));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
index ++;
|
||||
|
||||
if(!polymorph) {
|
||||
stream->writeSimple("null", 4);
|
||||
return;
|
||||
}
|
||||
|
||||
auto str = static_cast<std::string*>(polymorph.get());
|
||||
|
||||
serializeString(stream, str->data(), static_cast<v_buff_size>(str->size()), serializer->m_config->escapeFlags);
|
||||
state.stream->writeCharSimple(']');
|
||||
|
||||
}
|
||||
|
||||
void Serializer::serializeAny(Serializer* serializer,
|
||||
data::stream::ConsistentOutputStream* stream,
|
||||
const oatpp::Void& polymorph)
|
||||
{
|
||||
void Serializer::serializeMap(MappingState& state) {
|
||||
|
||||
state.stream->writeCharSimple('{');
|
||||
|
||||
MappingState nestedState;
|
||||
nestedState.stream = state.stream;
|
||||
nestedState.config = state.config;
|
||||
|
||||
auto& map = state.tree->getMap();
|
||||
auto mapSize = map.size();
|
||||
|
||||
for(v_uint64 index = 0; index < mapSize; index ++) {
|
||||
|
||||
const auto& pair = map[index];
|
||||
|
||||
nestedState.tree = &pair.second.get();
|
||||
|
||||
if(!nestedState.tree->isNull() || state.config->includeNullElements) {
|
||||
|
||||
if(index > 0) state.stream->writeSimple(",", 1);
|
||||
|
||||
const auto& str = pair.first;
|
||||
serializeString(state.stream, str->data(), static_cast<v_buff_size>(str->size()), state.config->escapeFlags);
|
||||
state.stream->writeCharSimple(':');
|
||||
|
||||
serialize(nestedState);
|
||||
|
||||
if(!nestedState.errorStack.empty()) {
|
||||
state.errorStack.splice(state.errorStack.end(), nestedState.errorStack);
|
||||
state.errorStack.emplace_back("[oatpp::json::Serializer::serializeMap()]: key='" + pair.first + "'");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(!polymorph) {
|
||||
stream->writeSimple("null", 4);
|
||||
return;
|
||||
}
|
||||
|
||||
auto anyHandle = static_cast<data::mapping::type::AnyHandle*>(polymorph.get());
|
||||
serializer->serialize(stream, oatpp::Void(anyHandle->ptr, anyHandle->type));
|
||||
state.stream->writeCharSimple('}');
|
||||
|
||||
}
|
||||
|
||||
void Serializer::serializeEnum(Serializer* serializer,
|
||||
data::stream::ConsistentOutputStream* stream,
|
||||
const oatpp::Void& polymorph)
|
||||
{
|
||||
auto polymorphicDispatcher = static_cast<const data::mapping::type::__class::AbstractEnum::PolymorphicDispatcher*>(
|
||||
polymorph.getValueType()->polymorphicDispatcher
|
||||
);
|
||||
void Serializer::serializePairs(MappingState& state) {
|
||||
|
||||
data::mapping::type::EnumInterpreterError e = data::mapping::type::EnumInterpreterError::OK;
|
||||
serializer->serialize(stream, polymorphicDispatcher->toInterpretation(polymorph, e));
|
||||
state.stream->writeCharSimple('{');
|
||||
|
||||
MappingState nestedState;
|
||||
nestedState.stream = state.stream;
|
||||
nestedState.config = state.config;
|
||||
|
||||
auto& map = state.tree->getPairs();
|
||||
auto mapSize = map.size();
|
||||
|
||||
for(v_uint64 index = 0; index < mapSize; index ++) {
|
||||
|
||||
const auto& pair = map[index];
|
||||
|
||||
nestedState.tree = &pair.second;
|
||||
|
||||
if(!nestedState.tree->isNull() || state.config->includeNullElements) {
|
||||
|
||||
if(index > 0) state.stream->writeSimple(",", 1);
|
||||
|
||||
const auto& str = pair.first;
|
||||
serializeString(state.stream, str->data(), static_cast<v_buff_size>(str->size()), state.config->escapeFlags);
|
||||
state.stream->writeCharSimple(':');
|
||||
|
||||
serialize(nestedState);
|
||||
|
||||
if(!nestedState.errorStack.empty()) {
|
||||
state.errorStack.splice(state.errorStack.end(), nestedState.errorStack);
|
||||
state.errorStack.emplace_back("[oatpp::json::Serializer::serializeMap()]: key='" + pair.first + "'");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(e == data::mapping::type::EnumInterpreterError::OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch(e) {
|
||||
case data::mapping::type::EnumInterpreterError::CONSTRAINT_NOT_NULL:
|
||||
throw std::runtime_error("[oatpp::json::Serializer::serializeEnum()]: Error. Enum constraint violated - 'NotNull'.");
|
||||
case data::mapping::type::EnumInterpreterError::OK:
|
||||
case data::mapping::type::EnumInterpreterError::TYPE_MISMATCH_ENUM:
|
||||
case data::mapping::type::EnumInterpreterError::TYPE_MISMATCH_ENUM_VALUE:
|
||||
case data::mapping::type::EnumInterpreterError::ENTRY_NOT_FOUND:
|
||||
state.stream->writeCharSimple('}');
|
||||
|
||||
}
|
||||
|
||||
void Serializer::serialize(MappingState& state) {
|
||||
|
||||
switch (state.tree->getType()) {
|
||||
|
||||
case data::mapping::Tree::Type::UNDEFINED: break;
|
||||
case data::mapping::Tree::Type::NULL_VALUE: serializeNull(state); return;
|
||||
|
||||
case data::mapping::Tree::Type::INTEGER: state.stream->writeAsString(state.tree->getInteger()); return;
|
||||
case data::mapping::Tree::Type::FLOAT: state.stream->writeAsString(state.tree->getFloat()); return;
|
||||
|
||||
case data::mapping::Tree::Type::BOOL: state.stream->writeAsString(state.tree->getValue<bool>()); return;
|
||||
|
||||
case data::mapping::Tree::Type::INT_8: state.stream->writeAsString(state.tree->getValue<v_int8>()); return;
|
||||
case data::mapping::Tree::Type::UINT_8: state.stream->writeAsString(state.tree->getValue<v_uint8>()); return;
|
||||
case data::mapping::Tree::Type::INT_16: state.stream->writeAsString(state.tree->getValue<v_int16>()); return;
|
||||
case data::mapping::Tree::Type::UINT_16: state.stream->writeAsString(state.tree->getValue<v_uint16>()); return;
|
||||
case data::mapping::Tree::Type::INT_32: state.stream->writeAsString(state.tree->getValue<v_int32>()); return;
|
||||
case data::mapping::Tree::Type::UINT_32: state.stream->writeAsString(state.tree->getValue<v_uint32>()); return;
|
||||
case data::mapping::Tree::Type::INT_64: state.stream->writeAsString(state.tree->getValue<v_int64>()); return;
|
||||
case data::mapping::Tree::Type::UINT_64: state.stream->writeAsString(state.tree->getValue<v_uint64>()); return;
|
||||
|
||||
case data::mapping::Tree::Type::FLOAT_32: state.stream->writeAsString(state.tree->getValue<v_float32>()); return;
|
||||
case data::mapping::Tree::Type::FLOAT_64: state.stream->writeAsString(state.tree->getValue<v_float64>()); return;
|
||||
|
||||
case data::mapping::Tree::Type::STRING: serializeString(state); return;
|
||||
case data::mapping::Tree::Type::VECTOR: serializeArray(state); return;
|
||||
case data::mapping::Tree::Type::MAP: serializeMap(state); return;
|
||||
case data::mapping::Tree::Type::PAIRS: serializePairs(state); return;
|
||||
|
||||
default:
|
||||
throw std::runtime_error("[oatpp::json::Serializer::serializeEnum()]: Error. Can't serialize Enum.");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
state.errorStack.emplace_back("[oatpp::json::Serializer::serialize()]: Unknown node type");
|
||||
|
||||
}
|
||||
|
||||
void Serializer::serializeCollection(Serializer* serializer,
|
||||
data::stream::ConsistentOutputStream* stream,
|
||||
const oatpp::Void& polymorph)
|
||||
{
|
||||
void Serializer::serializeToStream(data::stream::ConsistentOutputStream* stream, MappingState& state) {
|
||||
|
||||
if(!polymorph) {
|
||||
stream->writeSimple("null", 4);
|
||||
return;
|
||||
}
|
||||
if(state.config->useBeautifier) {
|
||||
|
||||
auto dispatcher = static_cast<const data::mapping::type::__class::Collection::PolymorphicDispatcher*>(
|
||||
polymorph.getValueType()->polymorphicDispatcher
|
||||
);
|
||||
|
||||
stream->writeCharSimple('[');
|
||||
bool first = true;
|
||||
|
||||
auto iterator = dispatcher->beginIteration(polymorph);
|
||||
|
||||
while (!iterator->finished()) {
|
||||
const auto& value = iterator->get();
|
||||
if(value || serializer->getConfig()->includeNullFields || serializer->getConfig()->alwaysIncludeNullCollectionElements) {
|
||||
(first) ? first = false : stream->writeSimple(",", 1);
|
||||
serializer->serialize(stream, value);
|
||||
}
|
||||
iterator->next();
|
||||
}
|
||||
|
||||
stream->writeCharSimple(']');
|
||||
|
||||
}
|
||||
|
||||
void Serializer::serializeMap(Serializer* serializer,
|
||||
data::stream::ConsistentOutputStream* stream,
|
||||
const oatpp::Void& polymorph)
|
||||
{
|
||||
|
||||
if(!polymorph) {
|
||||
stream->writeSimple("null", 4);
|
||||
return;
|
||||
}
|
||||
|
||||
auto dispatcher = static_cast<const data::mapping::type::__class::Map::PolymorphicDispatcher*>(
|
||||
polymorph.getValueType()->polymorphicDispatcher
|
||||
);
|
||||
|
||||
auto keyType = dispatcher->getKeyType();
|
||||
if(keyType->classId != oatpp::String::Class::CLASS_ID){
|
||||
throw std::runtime_error("[oatpp::json::Serializer::serializeMap()]: Invalid json map key. Key should be String");
|
||||
}
|
||||
|
||||
stream->writeCharSimple('{');
|
||||
bool first = true;
|
||||
|
||||
auto iterator = dispatcher->beginIteration(polymorph);
|
||||
|
||||
while (!iterator->finished()) {
|
||||
const auto& value = iterator->getValue();
|
||||
if(value || serializer->m_config->includeNullFields || serializer->m_config->alwaysIncludeNullCollectionElements) {
|
||||
(first) ? first = false : stream->writeSimple(",", 1);
|
||||
const auto& untypedKey = iterator->getKey();
|
||||
const auto& key = oatpp::String(std::static_pointer_cast<std::string>(untypedKey.getPtr()));
|
||||
serializeString(stream, key->data(), static_cast<v_buff_size>(key->size()), serializer->m_config->escapeFlags);
|
||||
stream->writeSimple(":", 1);
|
||||
serializer->serialize(stream, value);
|
||||
}
|
||||
iterator->next();
|
||||
}
|
||||
|
||||
stream->writeCharSimple('}');
|
||||
|
||||
}
|
||||
|
||||
void Serializer::serializeObject(Serializer* serializer,
|
||||
data::stream::ConsistentOutputStream* stream,
|
||||
const oatpp::Void& polymorph)
|
||||
{
|
||||
|
||||
if(!polymorph) {
|
||||
stream->writeSimple("null", 4);
|
||||
return;
|
||||
}
|
||||
|
||||
stream->writeCharSimple('{');
|
||||
|
||||
bool first = true;
|
||||
auto type = polymorph.getValueType();
|
||||
auto dispatcher = static_cast<const oatpp::data::mapping::type::__class::AbstractObject::PolymorphicDispatcher*>(
|
||||
type->polymorphicDispatcher
|
||||
);
|
||||
auto fields = dispatcher->getProperties()->getList();
|
||||
auto object = static_cast<oatpp::BaseObject*>(polymorph.get());
|
||||
auto config = serializer->m_config;
|
||||
|
||||
for (auto const& field : fields) {
|
||||
|
||||
oatpp::Void value;
|
||||
if(field->info.typeSelector && field->type == oatpp::Any::Class::getType()) {
|
||||
const auto& any = field->get(object).cast<oatpp::Any>();
|
||||
value = any.retrieve(field->info.typeSelector->selectType(object));
|
||||
} else {
|
||||
value = field->get(object);
|
||||
}
|
||||
|
||||
if(field->info.required && value == nullptr) {
|
||||
throw std::runtime_error("[oatpp::json::Serializer::serialize()]: "
|
||||
"Error. " + std::string(type->nameQualifier) + "::"
|
||||
+ std::string(field->name) + " is required!");
|
||||
}
|
||||
|
||||
if (value || config->includeNullFields || (field->info.required && config->alwaysIncludeRequired)) {
|
||||
(first) ? first = false : stream->writeSimple(",", 1);
|
||||
serializeString(stream, field->name, static_cast<v_buff_size>(std::strlen(field->name)), serializer->m_config->escapeFlags);
|
||||
stream->writeSimple(":", 1);
|
||||
serializer->serialize(stream, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
stream->writeCharSimple('}');
|
||||
|
||||
}
|
||||
|
||||
void Serializer::serialize(data::stream::ConsistentOutputStream* stream,
|
||||
const oatpp::Void& polymorph)
|
||||
{
|
||||
auto id = static_cast<v_uint32>(polymorph.getValueType()->classId.id);
|
||||
auto& method = m_methods[id];
|
||||
if(method) {
|
||||
(*method)(this, stream, polymorph);
|
||||
} else {
|
||||
|
||||
auto* interpretation = polymorph.getValueType()->findInterpretation(m_config->enabledInterpretations);
|
||||
if(interpretation) {
|
||||
serialize(stream, interpretation->toInterpretation(polymorph));
|
||||
} else {
|
||||
throw std::runtime_error("[oatpp::json::Serializer::serialize()]: "
|
||||
"Error. No serialize method for type '" +
|
||||
std::string(polymorph.getValueType()->classId.name) + "'");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Serializer::serializeToStream(data::stream::ConsistentOutputStream* stream,
|
||||
const oatpp::Void& polymorph)
|
||||
{
|
||||
if(m_config->useBeautifier) {
|
||||
json::Beautifier beautifier(stream, " ", "\n");
|
||||
serialize(&beautifier, polymorph);
|
||||
} else {
|
||||
serialize(stream, polymorph);
|
||||
}
|
||||
}
|
||||
|
||||
const std::shared_ptr<Serializer::Config>& Serializer::getConfig() {
|
||||
return m_config;
|
||||
MappingState beautifulState;
|
||||
beautifulState.stream = &beautifier;
|
||||
beautifulState.tree = state.tree;
|
||||
beautifulState.config = state.config;
|
||||
serialize(beautifulState);
|
||||
|
||||
state.errorStack = std::move(beautifulState.errorStack);
|
||||
|
||||
} else {
|
||||
state.stream = stream;
|
||||
serialize(state);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}}
|
||||
|
@ -27,8 +27,8 @@
|
||||
|
||||
#include "./Utils.hpp"
|
||||
#include "./Beautifier.hpp"
|
||||
#include "oatpp/data/mapping/Tree.hpp"
|
||||
#include "oatpp/Types.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace oatpp { namespace json {
|
||||
|
||||
@ -38,55 +38,18 @@ namespace oatpp { namespace json {
|
||||
*/
|
||||
class Serializer {
|
||||
public:
|
||||
typedef oatpp::data::mapping::type::Type Type;
|
||||
typedef oatpp::data::mapping::type::BaseObject::Property Property;
|
||||
typedef oatpp::data::mapping::type::BaseObject::Properties Properties;
|
||||
|
||||
typedef oatpp::String String;
|
||||
public:
|
||||
/**
|
||||
* Serializer config.
|
||||
*/
|
||||
class Config : public oatpp::base::Countable {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
Config()
|
||||
{}
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create shared config.
|
||||
* @return - `std::shared_ptr` to Config.
|
||||
*/
|
||||
static std::shared_ptr<Config> createShared(){
|
||||
return std::make_shared<Config>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Include fields with value == nullptr into serialized json.
|
||||
* Field will still be included when field-info `required` is set to true and &id:alwaysIncludeRequired is set to true.
|
||||
*/
|
||||
bool includeNullFields = true;
|
||||
|
||||
/**
|
||||
* Always include required fields (set in in DTO_FIELD_INFO) even if they are `value == nullptr`
|
||||
*/
|
||||
bool alwaysIncludeRequired = false;
|
||||
|
||||
/**
|
||||
* Always include array or map elements, even if their value is `nullptr`.
|
||||
*/
|
||||
bool alwaysIncludeNullCollectionElements = false;
|
||||
|
||||
/**
|
||||
* If `true` - insert string `"<unknown-type>"` in json field value in case unknown field found.
|
||||
* Fail if `false`.
|
||||
* Known types for this serializer are:<br>
|
||||
* (String, Int8, Int16, Int32, Int64, Float32, Float64, Boolean, DTOs, List, Fields).
|
||||
*/
|
||||
bool throwOnUnknownTypes = true;
|
||||
bool includeNullElements = true;
|
||||
|
||||
/**
|
||||
* Use JSON Beautifier.
|
||||
@ -103,97 +66,45 @@ public:
|
||||
*/
|
||||
oatpp::String beautifierNewLine = "\n";
|
||||
|
||||
/**
|
||||
* Enable type interpretations.
|
||||
*/
|
||||
std::vector<std::string> enabledInterpretations = {};
|
||||
|
||||
/**
|
||||
* Escape flags.
|
||||
*/
|
||||
v_uint32 escapeFlags = json::Utils::FLAG_ESCAPE_ALL;
|
||||
|
||||
};
|
||||
|
||||
public:
|
||||
typedef void (*SerializerMethod)(Serializer*,
|
||||
data::stream::ConsistentOutputStream*,
|
||||
const oatpp::Void&);
|
||||
|
||||
struct MappingState {
|
||||
|
||||
Config* config;
|
||||
const data::mapping::Tree* tree;
|
||||
data::stream::ConsistentOutputStream* stream;
|
||||
|
||||
std::list<oatpp::String> errorStack;
|
||||
oatpp::String errorStacktrace() const;
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
template<class T>
|
||||
static void serializePrimitive(Serializer* serializer,
|
||||
data::stream::ConsistentOutputStream* stream,
|
||||
const oatpp::Void& polymorph){
|
||||
(void) serializer;
|
||||
|
||||
if(polymorph){
|
||||
stream->writeAsString(* static_cast<typename T::ObjectType*>(polymorph.get()));
|
||||
} else {
|
||||
stream->writeSimple("null", 4);
|
||||
}
|
||||
}
|
||||
|
||||
static void serializeString(oatpp::data::stream::ConsistentOutputStream* stream,
|
||||
const char* data,
|
||||
v_buff_size size,
|
||||
v_uint32 escapeFlags);
|
||||
|
||||
static void serializeString(Serializer* serializer,
|
||||
data::stream::ConsistentOutputStream* stream,
|
||||
const oatpp::Void& polymorph);
|
||||
static void serializeNull(MappingState& state);
|
||||
static void serializeString(MappingState& state);
|
||||
static void serializeArray(MappingState& state);
|
||||
static void serializeMap(MappingState& state);
|
||||
static void serializePairs(MappingState& state);
|
||||
|
||||
static void serializeAny(Serializer* serializer,
|
||||
data::stream::ConsistentOutputStream* stream,
|
||||
const oatpp::Void& polymorph);
|
||||
static void serialize(MappingState& state);
|
||||
|
||||
static void serializeEnum(Serializer* serializer,
|
||||
data::stream::ConsistentOutputStream* stream,
|
||||
const oatpp::Void& polymorph);
|
||||
|
||||
static void serializeCollection(Serializer* serializer,
|
||||
data::stream::ConsistentOutputStream* stream,
|
||||
const oatpp::Void& polymorph);
|
||||
|
||||
static void serializeMap(Serializer* serializer,
|
||||
data::stream::ConsistentOutputStream* stream,
|
||||
const oatpp::Void& polymorph);
|
||||
|
||||
static void serializeObject(Serializer* serializer,
|
||||
data::stream::ConsistentOutputStream* stream,
|
||||
const oatpp::Void& polymorph);
|
||||
|
||||
void serialize(data::stream::ConsistentOutputStream* stream, const oatpp::Void& polymorph);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Config> m_config;
|
||||
std::vector<SerializerMethod> m_methods;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param config - serializer config.
|
||||
*/
|
||||
Serializer(const std::shared_ptr<Config>& config = std::make_shared<Config>());
|
||||
|
||||
/**
|
||||
* Set serializer method for type.
|
||||
* @param classId - &id:oatpp::data::mapping::type::ClassId;.
|
||||
* @param method - `typedef void (*SerializerMethod)(Serializer*, data::stream::ConsistentOutputStream*, const oatpp::Void&)`.
|
||||
*/
|
||||
void setSerializerMethod(const data::mapping::type::ClassId& classId, SerializerMethod method);
|
||||
|
||||
/**
|
||||
* Serialize object to stream.
|
||||
* @param stream - &id:oatpp::data::stream::ConsistentOutputStream;.
|
||||
* @param polymorph - DTO as &id:oatpp::Void;.
|
||||
*/
|
||||
void serializeToStream(data::stream::ConsistentOutputStream* stream, const oatpp::Void& polymorph);
|
||||
|
||||
/**
|
||||
* Get serializer config.
|
||||
* @return
|
||||
*/
|
||||
const std::shared_ptr<Config>& getConfig();
|
||||
static void serializeToStream(data::stream::ConsistentOutputStream* stream, MappingState& state);
|
||||
|
||||
};
|
||||
|
||||
|
@ -69,8 +69,8 @@ class TestDto1 : public oatpp::DTO {
|
||||
void TreeToObjectMapperTest::onRun() {
|
||||
|
||||
json::ObjectMapper jsonMapper;
|
||||
jsonMapper.getSerializer()->getConfig()->useBeautifier = true;
|
||||
jsonMapper.getSerializer()->getConfig()->includeNullFields = false;
|
||||
jsonMapper.getSerializerConfig()->useBeautifier = true;
|
||||
jsonMapper.getSerializerConfig()->includeNullFields = false;
|
||||
|
||||
TreeToObjectMapper mapper;
|
||||
TreeToObjectMapper::Config config;
|
||||
|
@ -176,7 +176,7 @@ void InterpretationTest::onRun() {
|
||||
oatpp::json::ObjectMapper mapper;
|
||||
|
||||
{
|
||||
auto config = mapper.getSerializer()->getConfig();
|
||||
auto config = mapper.getSerializerConfig();
|
||||
config->enabledInterpretations = {"test"};
|
||||
config->useBeautifier = false;
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ class TestAnyNested : public oatpp::DTO {
|
||||
void DTOMapperTest::onRun(){
|
||||
|
||||
auto mapper = oatpp::json::ObjectMapper::createShared();
|
||||
mapper->getSerializer()->getConfig()->useBeautifier = true;
|
||||
mapper->getSerializerConfig()->useBeautifier = true;
|
||||
|
||||
{
|
||||
auto test1 = Test::createShared();
|
||||
|
Loading…
Reference in New Issue
Block a user