mirror of
https://gitee.com/zyjblog/oatpp.git
synced 2024-12-22 22:16:37 +08:00
json::ObjectMapper: use mapping::Tree for Deserialization
This commit is contained in:
parent
87af860824
commit
8137eba15e
@ -80,7 +80,7 @@ void ObjectToTreeMapper::setMapperMethod(const data::mapping::type::ClassId& cla
|
||||
m_methods[id] = method;
|
||||
}
|
||||
|
||||
void ObjectToTreeMapper::map(MappingState& state, const oatpp::Void& polymorph)
|
||||
void ObjectToTreeMapper::map(MappingState& state, const oatpp::Void& polymorph) const
|
||||
{
|
||||
auto id = static_cast<v_uint32>(polymorph.getValueType()->classId.id);
|
||||
auto& method = m_methods[id];
|
||||
@ -101,7 +101,7 @@ void ObjectToTreeMapper::map(MappingState& state, const oatpp::Void& polymorph)
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectToTreeMapper::mapString(ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph) {
|
||||
void ObjectToTreeMapper::mapString(const ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph) {
|
||||
if(!polymorph) {
|
||||
state.tree->setNull();
|
||||
return;
|
||||
@ -109,7 +109,7 @@ void ObjectToTreeMapper::mapString(ObjectToTreeMapper* mapper, MappingState& sta
|
||||
state.tree->setString(oatpp::String(std::static_pointer_cast<std::string>(polymorph.getPtr()), oatpp::String::Class::getType()));
|
||||
}
|
||||
|
||||
void ObjectToTreeMapper::mapAny(ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph) {
|
||||
void ObjectToTreeMapper::mapAny(const ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph) {
|
||||
if(!polymorph) {
|
||||
state.tree->setNull();
|
||||
return;
|
||||
@ -118,7 +118,7 @@ void ObjectToTreeMapper::mapAny(ObjectToTreeMapper* mapper, MappingState& state,
|
||||
mapper->map(state, oatpp::Void(anyHandle->ptr, anyHandle->type));
|
||||
}
|
||||
|
||||
void ObjectToTreeMapper::mapEnum(ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph) {
|
||||
void ObjectToTreeMapper::mapEnum(const ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph) {
|
||||
|
||||
if(!polymorph) {
|
||||
state.tree->setNull();
|
||||
@ -150,7 +150,7 @@ void ObjectToTreeMapper::mapEnum(ObjectToTreeMapper* mapper, MappingState& state
|
||||
|
||||
}
|
||||
|
||||
void ObjectToTreeMapper::mapCollection(ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph) {
|
||||
void ObjectToTreeMapper::mapCollection(const ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph) {
|
||||
|
||||
if(!polymorph) {
|
||||
state.tree->setNull();
|
||||
@ -196,7 +196,7 @@ void ObjectToTreeMapper::mapCollection(ObjectToTreeMapper* mapper, MappingState&
|
||||
|
||||
}
|
||||
|
||||
void ObjectToTreeMapper::mapMap(ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph) {
|
||||
void ObjectToTreeMapper::mapMap(const ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph) {
|
||||
|
||||
if(!polymorph) {
|
||||
state.tree->setNull();
|
||||
@ -243,7 +243,7 @@ void ObjectToTreeMapper::mapMap(ObjectToTreeMapper* mapper, MappingState& state,
|
||||
|
||||
}
|
||||
|
||||
void ObjectToTreeMapper::mapObject(ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph) {
|
||||
void ObjectToTreeMapper::mapObject(const ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph) {
|
||||
|
||||
if(!polymorph) {
|
||||
state.tree->setNull();
|
||||
|
@ -52,11 +52,11 @@ public:
|
||||
};
|
||||
|
||||
public:
|
||||
typedef void (*MapperMethod)(ObjectToTreeMapper*, MappingState&, const oatpp::Void&);
|
||||
typedef void (*MapperMethod)(const ObjectToTreeMapper*, MappingState&, const oatpp::Void&);
|
||||
public:
|
||||
|
||||
template<class T>
|
||||
static void mapPrimitive(ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph){
|
||||
static void mapPrimitive(const ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph){
|
||||
(void) mapper;
|
||||
if(polymorph){
|
||||
state.tree->setValue<typename T::ObjectType>(* static_cast<typename T::ObjectType*>(polymorph.get()));
|
||||
@ -65,14 +65,14 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
static void mapString(ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph);
|
||||
static void mapAny(ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph);
|
||||
static void mapEnum(ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph);
|
||||
static void mapString(const ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph);
|
||||
static void mapAny(const ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph);
|
||||
static void mapEnum(const ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph);
|
||||
|
||||
static void mapCollection(ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph);
|
||||
static void mapMap(ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph);
|
||||
static void mapCollection(const ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph);
|
||||
static void mapMap(const ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph);
|
||||
|
||||
static void mapObject(ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph);
|
||||
static void mapObject(const ObjectToTreeMapper* mapper, MappingState& state, const oatpp::Void& polymorph);
|
||||
|
||||
private:
|
||||
std::vector<MapperMethod> m_methods;
|
||||
@ -82,7 +82,7 @@ public:
|
||||
|
||||
void setMapperMethod(const data::mapping::type::ClassId& classId, MapperMethod method);
|
||||
|
||||
void map(MappingState& state, const oatpp::Void& polymorph);
|
||||
void map(MappingState& state, const oatpp::Void& polymorph) const;
|
||||
|
||||
};
|
||||
|
||||
|
@ -80,7 +80,7 @@ void TreeToObjectMapper::setMapperMethod(const data::mapping::type::ClassId& cla
|
||||
m_methods[id] = method;
|
||||
}
|
||||
|
||||
oatpp::Void TreeToObjectMapper::map(MappingState& state, const Type* const type) {
|
||||
oatpp::Void TreeToObjectMapper::map(MappingState& state, const Type* const type) const {
|
||||
auto id = static_cast<v_uint32>(type->classId.id);
|
||||
auto& method = m_methods[id];
|
||||
if(method) {
|
||||
@ -131,7 +131,7 @@ const Type* TreeToObjectMapper::guessType(const Tree& node) {
|
||||
|
||||
}
|
||||
|
||||
oatpp::Void TreeToObjectMapper::mapString(TreeToObjectMapper* mapper, MappingState& state, const Type* const type) {
|
||||
oatpp::Void TreeToObjectMapper::mapString(const TreeToObjectMapper* mapper, MappingState& state, const Type* const type) {
|
||||
|
||||
(void) mapper;
|
||||
(void) type;
|
||||
@ -149,7 +149,7 @@ oatpp::Void TreeToObjectMapper::mapString(TreeToObjectMapper* mapper, MappingSta
|
||||
|
||||
}
|
||||
|
||||
oatpp::Void TreeToObjectMapper::mapAny(TreeToObjectMapper* mapper, MappingState& state, const Type* const type) {
|
||||
oatpp::Void TreeToObjectMapper::mapAny(const TreeToObjectMapper* mapper, MappingState& state, const Type* const type) {
|
||||
(void) type;
|
||||
if(state.tree->isNull()){
|
||||
return oatpp::Void(Any::Class::getType());
|
||||
@ -164,7 +164,7 @@ oatpp::Void TreeToObjectMapper::mapAny(TreeToObjectMapper* mapper, MappingState&
|
||||
return oatpp::Void(Any::Class::getType());
|
||||
}
|
||||
|
||||
oatpp::Void TreeToObjectMapper::mapEnum(TreeToObjectMapper* mapper, MappingState& state, const Type* const type) {
|
||||
oatpp::Void TreeToObjectMapper::mapEnum(const TreeToObjectMapper* mapper, MappingState& state, const Type* const type) {
|
||||
|
||||
auto polymorphicDispatcher = static_cast<const data::mapping::type::__class::AbstractEnum::PolymorphicDispatcher*>(
|
||||
type->polymorphicDispatcher
|
||||
@ -198,7 +198,7 @@ oatpp::Void TreeToObjectMapper::mapEnum(TreeToObjectMapper* mapper, MappingState
|
||||
|
||||
}
|
||||
|
||||
oatpp::Void TreeToObjectMapper::mapCollection(TreeToObjectMapper* mapper, MappingState& state, const Type* const type) {
|
||||
oatpp::Void TreeToObjectMapper::mapCollection(const TreeToObjectMapper* mapper, MappingState& state, const Type* const type) {
|
||||
|
||||
if(state.tree->isNull()){
|
||||
return oatpp::Void(type);
|
||||
@ -242,7 +242,7 @@ oatpp::Void TreeToObjectMapper::mapCollection(TreeToObjectMapper* mapper, Mappin
|
||||
|
||||
}
|
||||
|
||||
oatpp::Void TreeToObjectMapper::mapMap(TreeToObjectMapper* mapper, MappingState& state, const Type* const type) {
|
||||
oatpp::Void TreeToObjectMapper::mapMap(const TreeToObjectMapper* mapper, MappingState& state, const Type* const type) {
|
||||
|
||||
if(state.tree->isNull()){
|
||||
return oatpp::Void(type);
|
||||
@ -290,7 +290,7 @@ oatpp::Void TreeToObjectMapper::mapMap(TreeToObjectMapper* mapper, MappingState&
|
||||
|
||||
}
|
||||
|
||||
oatpp::Void TreeToObjectMapper::mapObject(TreeToObjectMapper* mapper, MappingState& state, const Type* const type) {
|
||||
oatpp::Void TreeToObjectMapper::mapObject(const TreeToObjectMapper* mapper, MappingState& state, const Type* const type) {
|
||||
|
||||
if(state.tree->isNull()){
|
||||
return oatpp::Void(type);
|
||||
|
@ -50,11 +50,11 @@ public:
|
||||
};
|
||||
|
||||
public:
|
||||
typedef oatpp::Void (*MapperMethod)(TreeToObjectMapper*, MappingState&, const Type* const);
|
||||
typedef oatpp::Void (*MapperMethod)(const TreeToObjectMapper*, MappingState&, const Type* const);
|
||||
public:
|
||||
|
||||
template<class T>
|
||||
static oatpp::Void mapPrimitive(TreeToObjectMapper* mapper, MappingState& state, const Type* const type){
|
||||
static oatpp::Void mapPrimitive(const TreeToObjectMapper* mapper, MappingState& state, const Type* const type){
|
||||
(void) mapper;
|
||||
(void) type;
|
||||
if(state.tree->isNull()) {
|
||||
@ -69,14 +69,14 @@ public:
|
||||
|
||||
static const Type* guessType(const Tree& node);
|
||||
|
||||
static oatpp::Void mapString(TreeToObjectMapper* mapper, MappingState& state, const Type* const type);
|
||||
static oatpp::Void mapAny(TreeToObjectMapper* mapper, MappingState& state, const Type* const type);
|
||||
static oatpp::Void mapEnum(TreeToObjectMapper* mapper, MappingState& state, const Type* const type);
|
||||
static oatpp::Void mapString(const TreeToObjectMapper* mapper, MappingState& state, const Type* const type);
|
||||
static oatpp::Void mapAny(const TreeToObjectMapper* mapper, MappingState& state, const Type* const type);
|
||||
static oatpp::Void mapEnum(const TreeToObjectMapper* mapper, MappingState& state, const Type* const type);
|
||||
|
||||
static oatpp::Void mapCollection(TreeToObjectMapper* mapper, MappingState& state, const Type* type);
|
||||
static oatpp::Void mapMap(TreeToObjectMapper* mapper, MappingState& state, const Type* const type);
|
||||
static oatpp::Void mapCollection(const TreeToObjectMapper* mapper, MappingState& state, const Type* type);
|
||||
static oatpp::Void mapMap(const TreeToObjectMapper* mapper, MappingState& state, const Type* const type);
|
||||
|
||||
static oatpp::Void mapObject(TreeToObjectMapper* mapper, MappingState& state, const Type* const type);
|
||||
static oatpp::Void mapObject(const TreeToObjectMapper* mapper, MappingState& state, const Type* const type);
|
||||
|
||||
private:
|
||||
std::vector<MapperMethod> m_methods;
|
||||
@ -86,7 +86,7 @@ public:
|
||||
|
||||
void setMapperMethod(const data::mapping::type::ClassId& classId, MapperMethod method);
|
||||
|
||||
oatpp::Void map(MappingState& state, const Type* const type);
|
||||
oatpp::Void map(MappingState& state, const Type* const type) const;
|
||||
|
||||
};
|
||||
|
||||
|
@ -24,505 +24,194 @@
|
||||
|
||||
#include "Deserializer.hpp"
|
||||
|
||||
#include "oatpp/data/stream/BufferStream.hpp"
|
||||
#include "oatpp/utils/Conversion.hpp"
|
||||
|
||||
namespace oatpp { namespace json {
|
||||
|
||||
Deserializer::Deserializer(const std::shared_ptr<Config>& config)
|
||||
: m_config(config)
|
||||
{
|
||||
|
||||
m_methods.resize(static_cast<size_t>(data::mapping::type::ClassId::getClassCount()), nullptr);
|
||||
|
||||
setDeserializerMethod(data::mapping::type::__class::String::CLASS_ID, &Deserializer::deserializeString);
|
||||
setDeserializerMethod(data::mapping::type::__class::Any::CLASS_ID, &Deserializer::deserializeAny);
|
||||
|
||||
setDeserializerMethod(data::mapping::type::__class::Int8::CLASS_ID, &Deserializer::deserializeInt<oatpp::Int8>);
|
||||
setDeserializerMethod(data::mapping::type::__class::UInt8::CLASS_ID, &Deserializer::deserializeUInt<oatpp::UInt8>);
|
||||
|
||||
setDeserializerMethod(data::mapping::type::__class::Int16::CLASS_ID, &Deserializer::deserializeInt<oatpp::Int16>);
|
||||
setDeserializerMethod(data::mapping::type::__class::UInt16::CLASS_ID, &Deserializer::deserializeUInt<oatpp::UInt16>);
|
||||
|
||||
setDeserializerMethod(data::mapping::type::__class::Int32::CLASS_ID, &Deserializer::deserializeInt<oatpp::Int32>);
|
||||
setDeserializerMethod(data::mapping::type::__class::UInt32::CLASS_ID, &Deserializer::deserializeUInt<oatpp::UInt32>);
|
||||
|
||||
setDeserializerMethod(data::mapping::type::__class::Int64::CLASS_ID, &Deserializer::deserializeInt<oatpp::Int64>);
|
||||
setDeserializerMethod(data::mapping::type::__class::UInt64::CLASS_ID, &Deserializer::deserializeUInt<oatpp::UInt64>);
|
||||
|
||||
setDeserializerMethod(data::mapping::type::__class::Float32::CLASS_ID, &Deserializer::deserializeFloat32);
|
||||
setDeserializerMethod(data::mapping::type::__class::Float64::CLASS_ID, &Deserializer::deserializeFloat64);
|
||||
setDeserializerMethod(data::mapping::type::__class::Boolean::CLASS_ID, &Deserializer::deserializeBoolean);
|
||||
|
||||
setDeserializerMethod(data::mapping::type::__class::AbstractObject::CLASS_ID, &Deserializer::deserializeObject);
|
||||
setDeserializerMethod(data::mapping::type::__class::AbstractEnum::CLASS_ID, &Deserializer::deserializeEnum);
|
||||
|
||||
setDeserializerMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &Deserializer::deserializeCollection);
|
||||
setDeserializerMethod(data::mapping::type::__class::AbstractList::CLASS_ID, &Deserializer::deserializeCollection);
|
||||
setDeserializerMethod(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID, &Deserializer::deserializeCollection);
|
||||
|
||||
setDeserializerMethod(data::mapping::type::__class::AbstractPairList::CLASS_ID, &Deserializer::deserializeMap);
|
||||
setDeserializerMethod(data::mapping::type::__class::AbstractUnorderedMap::CLASS_ID, &Deserializer::deserializeMap);
|
||||
|
||||
}
|
||||
|
||||
void Deserializer::setDeserializerMethod(const data::mapping::type::ClassId& classId, DeserializerMethod method) {
|
||||
const v_uint32 id = static_cast<v_uint32>(classId.id);
|
||||
if(id >= m_methods.size()) {
|
||||
m_methods.resize(id + 1, nullptr);
|
||||
oatpp::String Deserializer::MappingState::errorStacktrace() const {
|
||||
data::stream::BufferOutputStream ss;
|
||||
for(auto& s : errorStack) {
|
||||
ss << s << "\n";
|
||||
}
|
||||
m_methods[id] = method;
|
||||
return ss.toString();
|
||||
}
|
||||
|
||||
void Deserializer::skipScope(oatpp::utils::parser::Caret& caret, v_char8 charOpen, v_char8 charClose){
|
||||
|
||||
const char* data = caret.getData();
|
||||
v_buff_size size = caret.getDataSize();
|
||||
v_buff_size pos = caret.getPosition();
|
||||
v_int32 scopeCounter = 0;
|
||||
|
||||
bool isInString = false;
|
||||
|
||||
while(pos < size){
|
||||
v_char8 a = static_cast<v_char8>(data[pos]);
|
||||
if(a == charOpen){
|
||||
if(!isInString){
|
||||
scopeCounter ++;
|
||||
}
|
||||
} else if(a == charClose){
|
||||
if(!isInString){
|
||||
scopeCounter --;
|
||||
if(scopeCounter == 0){
|
||||
caret.setPosition(pos + 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if(a == '"') {
|
||||
isInString = !isInString;
|
||||
} else if(a == '\\'){
|
||||
pos ++;
|
||||
}
|
||||
|
||||
pos ++;
|
||||
|
||||
void Deserializer::deserializeNull(MappingState& state) {
|
||||
if(state.caret->isAtText("null", true)){
|
||||
state.tree->setNull();
|
||||
} else {
|
||||
state.errorStack.emplace_back("[oatpp::json::Deserializer::deserializeNull()]: 'null' expected");
|
||||
}
|
||||
}
|
||||
|
||||
void Deserializer::skipString(oatpp::utils::parser::Caret& caret){
|
||||
const char* data = caret.getData();
|
||||
v_buff_size size = caret.getDataSize();
|
||||
v_buff_size pos = caret.getPosition();
|
||||
v_int32 scopeCounter = 0;
|
||||
while(pos < size){
|
||||
v_char8 a = static_cast<v_char8>(data[pos]);
|
||||
if(a == '"'){
|
||||
scopeCounter ++;
|
||||
if(scopeCounter == 2) {
|
||||
caret.setPosition(pos + 1);
|
||||
void Deserializer::deserializeNumber(MappingState& state) {
|
||||
if (!Utils::findDecimalSeparatorInCurrentNumber(*state.caret)) {
|
||||
state.tree->setInteger(state.caret->parseInt());
|
||||
} else {
|
||||
state.tree->setFloat(state.caret->parseFloat64());
|
||||
}
|
||||
}
|
||||
|
||||
void Deserializer::deserializeBoolean(MappingState& state) {
|
||||
if(state.caret->isAtText("true", true)) {
|
||||
state.tree->setValue<bool>(true);
|
||||
} else if(state.caret->isAtText("false", true)) {
|
||||
state.tree->setValue<bool>(false);
|
||||
} else {
|
||||
state.errorStack.emplace_back("[oatpp::json::Deserializer::deserializeBoolean()]: 'true' or 'false' expected");
|
||||
}
|
||||
}
|
||||
|
||||
void Deserializer::deserializeString(MappingState& state) {
|
||||
state.tree->setString(Utils::parseString(*state.caret));
|
||||
}
|
||||
|
||||
void Deserializer::deserializeArray(MappingState& state) {
|
||||
|
||||
if(state.caret->canContinueAtChar('[', 1)) {
|
||||
|
||||
state.tree->setVector(0);
|
||||
auto& vector = state.tree->getVector();
|
||||
|
||||
state.caret->skipBlankChars();
|
||||
|
||||
v_int64 index = 0;
|
||||
|
||||
while(!state.caret->isAtChar(']') && state.caret->canContinue()){
|
||||
|
||||
state.caret->skipBlankChars();
|
||||
|
||||
vector.emplace_back();
|
||||
|
||||
MappingState nestedState;
|
||||
nestedState.caret = state.caret;
|
||||
nestedState.config = state.config;
|
||||
nestedState.tree = &vector[vector.size() - 1];
|
||||
|
||||
deserialize(nestedState);
|
||||
|
||||
if(!nestedState.errorStack.empty()) {
|
||||
state.errorStack.splice(state.errorStack.end(), nestedState.errorStack);
|
||||
state.errorStack.emplace_back("[oatpp::json::Deserializer::deserializeArray()]: index=" + utils::Conversion::int64ToStr(index));
|
||||
return;
|
||||
}
|
||||
} else if(a == '\\'){
|
||||
pos ++;
|
||||
}
|
||||
pos ++;
|
||||
}
|
||||
}
|
||||
|
||||
void Deserializer::skipToken(oatpp::utils::parser::Caret& caret){
|
||||
const char* data = caret.getData();
|
||||
v_buff_size size = caret.getDataSize();
|
||||
v_buff_size pos = caret.getPosition();
|
||||
while(pos < size){
|
||||
v_char8 a = static_cast<v_char8>(data[pos]);
|
||||
if(a == ' ' || a == '\t' || a == '\n' || a == '\r' || a == '\b' || a == '\f' ||
|
||||
a == '}' || a == ',' || a == ']') {
|
||||
caret.setPosition(pos);
|
||||
state.caret->skipBlankChars();
|
||||
|
||||
state.caret->canContinueAtChar(',', 1);
|
||||
|
||||
index ++;
|
||||
|
||||
}
|
||||
|
||||
if(!state.caret->canContinueAtChar(']', 1)){
|
||||
state.errorStack.emplace_back("[oatpp::json::Deserializer::deserializeArray()]: ']' expected");
|
||||
return;
|
||||
}
|
||||
pos ++;
|
||||
}
|
||||
}
|
||||
|
||||
void Deserializer::skipValue(oatpp::utils::parser::Caret& caret){
|
||||
if(caret.isAtChar('{')){
|
||||
skipScope(caret, '{', '}');
|
||||
} else if(caret.isAtChar('[')){
|
||||
skipScope(caret, '[', ']');
|
||||
} else if(caret.isAtChar('"')){
|
||||
skipString(caret);
|
||||
} else {
|
||||
skipToken(caret);
|
||||
}
|
||||
}
|
||||
|
||||
oatpp::Void Deserializer::deserializeFloat32(Deserializer* deserializer, utils::parser::Caret& caret, const Type* const type) {
|
||||
|
||||
(void) deserializer;
|
||||
(void) type;
|
||||
|
||||
if(caret.isAtText("null", true)){
|
||||
return oatpp::Void(Float32::Class::getType());
|
||||
} else {
|
||||
return Float32(caret.parseFloat32());
|
||||
}
|
||||
}
|
||||
|
||||
oatpp::Void Deserializer::deserializeFloat64(Deserializer* deserializer, utils::parser::Caret& caret, const Type* const type) {
|
||||
|
||||
(void) deserializer;
|
||||
(void) type;
|
||||
|
||||
if(caret.isAtText("null", true)){
|
||||
return oatpp::Void(Float64::Class::getType());
|
||||
} else {
|
||||
return Float64(caret.parseFloat64());
|
||||
state.errorStack.emplace_back("[oatpp::json::Deserializer::deserializeArray()]: '[' expected");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
oatpp::Void Deserializer::deserializeBoolean(Deserializer* deserializer, utils::parser::Caret& caret, const Type* const type) {
|
||||
void Deserializer::deserializeMap(MappingState& state) {
|
||||
|
||||
(void) deserializer;
|
||||
(void) type;
|
||||
if(state.caret->canContinueAtChar('{', 1)) {
|
||||
|
||||
state.caret->skipBlankChars();
|
||||
|
||||
state.tree->setMap({});
|
||||
auto& map = state.tree->getMap();
|
||||
|
||||
while (!state.caret->isAtChar('}') && state.caret->canContinue()) {
|
||||
|
||||
state.caret->skipBlankChars();
|
||||
|
||||
auto key = Utils::parseString(*state.caret);
|
||||
if(state.caret->hasError()){
|
||||
state.errorStack.emplace_back("[oatpp::json::Deserializer::deserializeMap()]: Item key name expected");
|
||||
return;
|
||||
}
|
||||
|
||||
state.caret->skipBlankChars();
|
||||
if(!state.caret->canContinueAtChar(':', 1)){
|
||||
state.errorStack.emplace_back("[oatpp::json::Deserializer::deserializeMap()]: ':' expected");
|
||||
return;
|
||||
}
|
||||
|
||||
state.caret->skipBlankChars();
|
||||
|
||||
MappingState nestedState;
|
||||
nestedState.caret = state.caret;
|
||||
nestedState.config = state.config;
|
||||
nestedState.tree = &map[key];
|
||||
|
||||
deserialize(nestedState);
|
||||
|
||||
if(!nestedState.errorStack.empty()) {
|
||||
state.errorStack.splice(state.errorStack.end(), nestedState.errorStack);
|
||||
state.errorStack.emplace_back("[oatpp::json::Deserializer::deserializeMap()]: key='" + key + "'");
|
||||
return;
|
||||
}
|
||||
|
||||
state.caret->skipBlankChars();
|
||||
state.caret->canContinueAtChar(',', 1);
|
||||
|
||||
if(caret.isAtText("null", true)){
|
||||
return oatpp::Void(Boolean::Class::getType());
|
||||
} else {
|
||||
if(caret.isAtText("true", true)) {
|
||||
return Boolean(true);
|
||||
} else if(caret.isAtText("false", true)) {
|
||||
return Boolean(false);
|
||||
} else {
|
||||
caret.setError("[oatpp::json::Deserializer::readBooleanValue()]: Error. 'true' or 'false' - expected.", ERROR_CODE_VALUE_BOOLEAN);
|
||||
return oatpp::Void(Boolean::Class::getType());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if(!state.caret->canContinueAtChar('}', 1)){
|
||||
state.errorStack.emplace_back("[oatpp::json::Deserializer::deserializeMap()]: '}' expected");
|
||||
return;
|
||||
}
|
||||
|
||||
oatpp::Void Deserializer::deserializeString(Deserializer* deserializer, utils::parser::Caret& caret, const Type* const type) {
|
||||
|
||||
(void) deserializer;
|
||||
(void) type;
|
||||
|
||||
if(caret.isAtText("null", true)){
|
||||
return oatpp::Void(String::Class::getType());
|
||||
} else {
|
||||
return oatpp::Void(Utils::parseString(caret).getPtr(), String::Class::getType());
|
||||
state.errorStack.emplace_back("[oatpp::json::Deserializer::deserializeMap()]: '{' expected");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const data::mapping::type::Type* Deserializer::guessNumberType(oatpp::utils::parser::Caret& caret) {
|
||||
if (!Utils::findDecimalSeparatorInCurrentNumber(caret)) {
|
||||
if (*caret.getCurrData() == '-') {
|
||||
return Int64::Class::getType();
|
||||
} else {
|
||||
return UInt64::Class::getType();
|
||||
}
|
||||
}
|
||||
return Float64::Class::getType();
|
||||
}
|
||||
void Deserializer::deserialize(MappingState& state) {
|
||||
|
||||
const data::mapping::type::Type* Deserializer::guessType(oatpp::utils::parser::Caret& caret) {
|
||||
{
|
||||
utils::parser::Caret::StateSaveGuard stateGuard(caret);
|
||||
v_char8 c = static_cast<v_char8>(*caret.getCurrData());
|
||||
switch (c) {
|
||||
case '"':
|
||||
return String::Class::getType();
|
||||
case '{':
|
||||
return oatpp::Fields<Any>::Class::getType();
|
||||
case '[':
|
||||
return oatpp::List<Any>::Class::getType();
|
||||
case 't':
|
||||
if(caret.isAtText("true")) return Boolean::Class::getType();
|
||||
break;
|
||||
case 'f':
|
||||
if(caret.isAtText("false")) return Boolean::Class::getType();
|
||||
break;
|
||||
default:
|
||||
if (c == '-' || caret.isAtDigitChar()) {
|
||||
return guessNumberType(caret);
|
||||
}
|
||||
}
|
||||
}
|
||||
caret.setError("[oatpp::json::Deserializer::guessType()]: Error. Can't guess type for oatpp::Any.");
|
||||
return nullptr;
|
||||
}
|
||||
state.caret->skipBlankChars();
|
||||
|
||||
oatpp::Void Deserializer::deserializeAny(Deserializer* deserializer, utils::parser::Caret& caret, const Type* const type) {
|
||||
(void) type;
|
||||
if(caret.isAtText("null", true)){
|
||||
return oatpp::Void(Any::Class::getType());
|
||||
} else {
|
||||
const Type* const fieldType = guessType(caret);
|
||||
if(fieldType != nullptr) {
|
||||
auto fieldValue = deserializer->deserialize(caret, fieldType);
|
||||
auto anyHandle = std::make_shared<data::mapping::type::AnyHandle>(fieldValue.getPtr(), fieldValue.getValueType());
|
||||
return oatpp::Void(anyHandle, Any::Class::getType());
|
||||
}
|
||||
}
|
||||
return oatpp::Void(Any::Class::getType());
|
||||
}
|
||||
|
||||
oatpp::Void Deserializer::deserializeEnum(Deserializer* deserializer, utils::parser::Caret& caret, const Type* const type) {
|
||||
|
||||
auto polymorphicDispatcher = static_cast<const data::mapping::type::__class::AbstractEnum::PolymorphicDispatcher*>(
|
||||
type->polymorphicDispatcher
|
||||
);
|
||||
|
||||
data::mapping::type::EnumInterpreterError e = data::mapping::type::EnumInterpreterError::OK;
|
||||
const auto& value = deserializer->deserialize(caret, polymorphicDispatcher->getInterpretationType());
|
||||
if(caret.hasError()) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto& result = polymorphicDispatcher->fromInterpretation(value, e);
|
||||
|
||||
if(e == data::mapping::type::EnumInterpreterError::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
switch(e) {
|
||||
case data::mapping::type::EnumInterpreterError::CONSTRAINT_NOT_NULL:
|
||||
caret.setError("[oatpp::json::Deserializer::deserializeEnum()]: Error. Enum constraint violated - 'NotNull'.");
|
||||
auto c = *state.caret->getCurrData();
|
||||
switch (c) {
|
||||
case 'n':
|
||||
deserializeNull(state);
|
||||
break;
|
||||
case '{':
|
||||
deserializeMap(state);
|
||||
break;
|
||||
case '[':
|
||||
deserializeArray(state);
|
||||
break;
|
||||
case '"':
|
||||
deserializeString(state);
|
||||
break;
|
||||
case 't':
|
||||
case 'f':
|
||||
deserializeBoolean(state);
|
||||
break;
|
||||
case '-':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
deserializeNumber(state);
|
||||
break;
|
||||
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:
|
||||
default:
|
||||
caret.setError("[oatpp::json::Deserializer::deserializeEnum()]: Error. Can't deserialize Enum.");
|
||||
state.errorStack.emplace_back("[json]: Unknown character.");
|
||||
break;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
oatpp::Void Deserializer::deserializeCollection(Deserializer* deserializer, utils::parser::Caret& caret, const Type* type) {
|
||||
|
||||
if(caret.isAtText("null", true)){
|
||||
return oatpp::Void(type);
|
||||
}
|
||||
|
||||
if(caret.canContinueAtChar('[', 1)) {
|
||||
|
||||
auto dispatcher = static_cast<const data::mapping::type::__class::Collection::PolymorphicDispatcher*>(type->polymorphicDispatcher);
|
||||
auto collection = dispatcher->createObject();
|
||||
|
||||
auto itemType = dispatcher->getItemType();
|
||||
|
||||
caret.skipBlankChars();
|
||||
|
||||
while(!caret.isAtChar(']') && caret.canContinue()){
|
||||
|
||||
caret.skipBlankChars();
|
||||
auto item = deserializer->deserialize(caret, itemType);
|
||||
if(caret.hasError()){
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
dispatcher->addItem(collection, item);
|
||||
caret.skipBlankChars();
|
||||
|
||||
caret.canContinueAtChar(',', 1);
|
||||
|
||||
}
|
||||
|
||||
if(!caret.canContinueAtChar(']', 1)){
|
||||
if(!caret.hasError()){
|
||||
caret.setError("[oatpp::json::Deserializer::deserializeCollection()]: Error. ']' - expected", ERROR_CODE_ARRAY_SCOPE_CLOSE);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return collection;
|
||||
|
||||
} else {
|
||||
caret.setError("[oatpp::json::Deserializer::deserializeCollection()]: Error. '[' - expected", ERROR_CODE_ARRAY_SCOPE_OPEN);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
oatpp::Void Deserializer::deserializeMap(Deserializer* deserializer, utils::parser::Caret& caret, const Type* const type) {
|
||||
|
||||
if(caret.isAtText("null", true)){
|
||||
return oatpp::Void(type);
|
||||
}
|
||||
|
||||
if(caret.canContinueAtChar('{', 1)) {
|
||||
|
||||
auto dispatcher = static_cast<const data::mapping::type::__class::Map::PolymorphicDispatcher*>(type->polymorphicDispatcher);
|
||||
auto map = dispatcher->createObject();
|
||||
|
||||
auto keyType = dispatcher->getKeyType();
|
||||
if(keyType->classId != oatpp::String::Class::CLASS_ID){
|
||||
throw std::runtime_error("[oatpp::json::Deserializer::deserializeMap()]: Invalid json map key. Key should be String");
|
||||
}
|
||||
auto valueType = dispatcher->getValueType();
|
||||
|
||||
caret.skipBlankChars();
|
||||
|
||||
while (!caret.isAtChar('}') && caret.canContinue()) {
|
||||
|
||||
caret.skipBlankChars();
|
||||
auto key = Utils::parseString(caret);
|
||||
if(caret.hasError()){
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
caret.skipBlankChars();
|
||||
if(!caret.canContinueAtChar(':', 1)){
|
||||
caret.setError("[oatpp::json::Deserializer::deserializeMap()]: Error. ':' - expected", ERROR_CODE_OBJECT_SCOPE_COLON_MISSING);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
caret.skipBlankChars();
|
||||
|
||||
auto item = deserializer->deserialize(caret, valueType);
|
||||
if(caret.hasError()){
|
||||
return nullptr;
|
||||
}
|
||||
dispatcher->addItem(map, key, item);
|
||||
|
||||
caret.skipBlankChars();
|
||||
caret.canContinueAtChar(',', 1);
|
||||
|
||||
}
|
||||
|
||||
if(!caret.canContinueAtChar('}', 1)){
|
||||
if(!caret.hasError()){
|
||||
caret.setError("[oatpp::json::Deserializer::deserializeMap()]: Error. '}' - expected", ERROR_CODE_OBJECT_SCOPE_CLOSE);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return map;
|
||||
|
||||
} else {
|
||||
caret.setError("[oatpp::json::Deserializer::deserializeMap()]: Error. '{' - expected", ERROR_CODE_OBJECT_SCOPE_OPEN);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
oatpp::Void Deserializer::deserializeObject(Deserializer* deserializer, utils::parser::Caret& caret, const Type* const type) {
|
||||
|
||||
if(caret.isAtText("null", true)){
|
||||
return oatpp::Void(type);
|
||||
}
|
||||
|
||||
if(caret.canContinueAtChar('{', 1)) {
|
||||
|
||||
auto dispatcher = static_cast<const oatpp::data::mapping::type::__class::AbstractObject::PolymorphicDispatcher*>(type->polymorphicDispatcher);
|
||||
auto object = dispatcher->createObject();
|
||||
const auto& fieldsMap = dispatcher->getProperties()->getMap();
|
||||
|
||||
caret.skipBlankChars();
|
||||
|
||||
std::vector<std::pair<oatpp::BaseObject::Property*, oatpp::String>> polymorphs;
|
||||
while (!caret.isAtChar('}') && caret.canContinue()) {
|
||||
|
||||
caret.skipBlankChars();
|
||||
auto key = Utils::parseStringToStdString(caret);
|
||||
if(caret.hasError()){
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto fieldIterator = fieldsMap.find(key);
|
||||
if(fieldIterator != fieldsMap.end()){
|
||||
|
||||
caret.skipBlankChars();
|
||||
if(!caret.canContinueAtChar(':', 1)){
|
||||
caret.setError("[oatpp::json::Deserializer::readObject()]: Error. ':' - expected", ERROR_CODE_OBJECT_SCOPE_COLON_MISSING);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
caret.skipBlankChars();
|
||||
|
||||
auto field = fieldIterator->second;
|
||||
|
||||
if(field->info.typeSelector && field->type == oatpp::Any::Class::getType()) {
|
||||
auto label = caret.putLabel();
|
||||
skipValue(caret);
|
||||
polymorphs.emplace_back(field, label.toString()); // store polymorphs for later processing.
|
||||
} else {
|
||||
auto value = deserializer->deserialize(caret, field->type);
|
||||
if(field->info.required && value == nullptr) {
|
||||
throw std::runtime_error("[oatpp::json::Deserializer::deserialize()]: "
|
||||
"Error. " + std::string(type->nameQualifier) + "::"
|
||||
+ std::string(field->name) + " is required!");
|
||||
}
|
||||
field->set(static_cast<oatpp::BaseObject *>(object.get()), value);
|
||||
}
|
||||
|
||||
} else if (deserializer->getConfig()->allowUnknownFields) {
|
||||
caret.skipBlankChars();
|
||||
if(!caret.canContinueAtChar(':', 1)){
|
||||
caret.setError("[oatpp::json::Deserializer::readObject()/if(config->allowUnknownFields){}]: Error. ':' - expected", ERROR_CODE_OBJECT_SCOPE_COLON_MISSING);
|
||||
return nullptr;
|
||||
}
|
||||
caret.skipBlankChars();
|
||||
skipValue(caret);
|
||||
} else {
|
||||
caret.setError("[oatpp::json::Deserializer::readObject()]: Error. Unknown field", ERROR_CODE_OBJECT_SCOPE_UNKNOWN_FIELD);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
caret.skipBlankChars();
|
||||
caret.canContinueAtChar(',', 1);
|
||||
|
||||
}
|
||||
|
||||
if(!caret.canContinueAtChar('}', 1)){
|
||||
if(!caret.hasError()){
|
||||
caret.setError("[oatpp::json::Deserializer::readObject()]: Error. '}' - expected", ERROR_CODE_OBJECT_SCOPE_CLOSE);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for(auto& p : polymorphs) {
|
||||
utils::parser::Caret polyCaret(p.second);
|
||||
auto selectedType = p.first->info.typeSelector->selectType(static_cast<oatpp::BaseObject *>(object.get()));
|
||||
auto value = deserializer->deserialize(polyCaret, selectedType);
|
||||
if(p.first->info.required && value == nullptr) {
|
||||
throw std::runtime_error("[oatpp::json::Deserializer::deserialize()]: "
|
||||
"Error. " + std::string(type->nameQualifier) + "::"
|
||||
+ std::string(p.first->name) + " is required!");
|
||||
}
|
||||
oatpp::Any any(value);
|
||||
p.first->set(static_cast<oatpp::BaseObject *>(object.get()), oatpp::Void(any.getPtr(), p.first->type));
|
||||
}
|
||||
|
||||
return object;
|
||||
|
||||
} else {
|
||||
caret.setError("[oatpp::json::Deserializer::readObject()]: Error. '{' - expected", ERROR_CODE_OBJECT_SCOPE_OPEN);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
oatpp::Void Deserializer::deserialize(utils::parser::Caret& caret, const Type* const type) {
|
||||
auto id = static_cast<v_uint32>(type->classId.id);
|
||||
auto& method = m_methods[id];
|
||||
if(method) {
|
||||
return (*method)(this, caret, type);
|
||||
} else {
|
||||
|
||||
auto* interpretation = type->findInterpretation(m_config->enabledInterpretations);
|
||||
if(interpretation) {
|
||||
return interpretation->fromInterpretation(deserialize(caret, interpretation->getInterpretationType()));
|
||||
}
|
||||
|
||||
throw std::runtime_error("[oatpp::json::Deserializer::deserialize()]: "
|
||||
"Error. No deserialize method for type '" + std::string(type->classId.name) + "'");
|
||||
}
|
||||
}
|
||||
|
||||
const std::shared_ptr<Deserializer::Config>& Deserializer::getConfig() {
|
||||
return m_config;
|
||||
}
|
||||
|
||||
}}
|
||||
|
@ -26,6 +26,9 @@
|
||||
#define oatpp_json_Deserializer_hpp
|
||||
|
||||
#include "./Utils.hpp"
|
||||
|
||||
#include "oatpp/data/mapping/TreeToObjectMapper.hpp"
|
||||
|
||||
#include "oatpp/utils/parser/Caret.hpp"
|
||||
#include "oatpp/Types.hpp"
|
||||
|
||||
@ -38,50 +41,6 @@ namespace oatpp { namespace json {
|
||||
* Deserialize oatpp DTO object from json. See [Data Transfer Object(DTO) component](https://oatpp.io/docs/components/dto/).
|
||||
*/
|
||||
class Deserializer {
|
||||
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:
|
||||
|
||||
/**
|
||||
* "'{' - expected"
|
||||
*/
|
||||
static constexpr v_int32 ERROR_CODE_OBJECT_SCOPE_OPEN = 1;
|
||||
|
||||
/**
|
||||
* "'}' - expected"
|
||||
*/
|
||||
static constexpr v_int32 ERROR_CODE_OBJECT_SCOPE_CLOSE = 2;
|
||||
|
||||
/**
|
||||
* "Unknown field"
|
||||
*/
|
||||
static constexpr v_int32 ERROR_CODE_OBJECT_SCOPE_UNKNOWN_FIELD = 3;
|
||||
|
||||
/**
|
||||
* "':' - expected"
|
||||
*/
|
||||
static constexpr v_int32 ERROR_CODE_OBJECT_SCOPE_COLON_MISSING = 4;
|
||||
|
||||
/**
|
||||
* "'[' - expected"
|
||||
*/
|
||||
static constexpr v_int32 ERROR_CODE_ARRAY_SCOPE_OPEN = 5;
|
||||
|
||||
/**
|
||||
* "']' - expected"
|
||||
*/
|
||||
static constexpr v_int32 ERROR_CODE_ARRAY_SCOPE_CLOSE = 6;
|
||||
|
||||
/**
|
||||
* "'true' or 'false' - expected"
|
||||
*/
|
||||
static constexpr v_int32 ERROR_CODE_VALUE_BOOLEAN = 7;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -89,123 +48,36 @@ public:
|
||||
*/
|
||||
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>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not fail if unknown field is found in json.
|
||||
* "unknown field" is the one which is not present in DTO object class.
|
||||
*/
|
||||
bool allowUnknownFields = true;
|
||||
|
||||
/**
|
||||
* Enable type interpretations.
|
||||
*/
|
||||
std::vector<std::string> enabledInterpretations = {};
|
||||
|
||||
};
|
||||
|
||||
public:
|
||||
typedef oatpp::Void (*DeserializerMethod)(Deserializer*, utils::parser::Caret&, const Type* const);
|
||||
private:
|
||||
static void skipScope(oatpp::utils::parser::Caret& caret, v_char8 charOpen, v_char8 charClose);
|
||||
static void skipString(oatpp::utils::parser::Caret& caret);
|
||||
static void skipToken(oatpp::utils::parser::Caret& caret);
|
||||
static void skipValue(oatpp::utils::parser::Caret& caret);
|
||||
private:
|
||||
static const Type* guessNumberType(oatpp::utils::parser::Caret& caret);
|
||||
static const Type* guessType(oatpp::utils::parser::Caret& caret);
|
||||
private:
|
||||
|
||||
template<class T>
|
||||
static oatpp::Void deserializeInt(Deserializer* deserializer, utils::parser::Caret& caret, const Type* const type){
|
||||
struct MappingState {
|
||||
|
||||
(void) deserializer;
|
||||
(void) type;
|
||||
Config* config;
|
||||
data::mapping::Tree* tree;
|
||||
utils::parser::Caret* caret;
|
||||
|
||||
if(caret.isAtText("null", true)){
|
||||
return oatpp::Void(T::Class::getType());
|
||||
} else {
|
||||
//TODO: shall we handle overflow cases like
|
||||
// oatpp::String json = "128";
|
||||
// auto value = jsonObjectMapper->readFromString<oatpp::Int8>(json); // UInt8 will overflow to -128
|
||||
return T(static_cast<typename T::UnderlyingType>(caret.parseInt()));
|
||||
}
|
||||
std::list<oatpp::String> errorStack;
|
||||
|
||||
}
|
||||
oatpp::String errorStacktrace() const;
|
||||
|
||||
template<class T>
|
||||
static oatpp::Void deserializeUInt(Deserializer* deserializer, utils::parser::Caret& caret, const Type* const type){
|
||||
|
||||
(void) deserializer;
|
||||
(void) type;
|
||||
|
||||
if(caret.isAtText("null", true)){
|
||||
return oatpp::Void(T::Class::getType());
|
||||
} else {
|
||||
//TODO: shall we handle overflow cases like
|
||||
// oatpp::String json = "256";
|
||||
// auto value = jsonObjectMapper->readFromString<oatpp::UInt8>(json); // UInt8 will overflow to 0
|
||||
return T(static_cast<typename T::UnderlyingType>(caret.parseUnsignedInt()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static oatpp::Void deserializeFloat32(Deserializer* deserializer, utils::parser::Caret& caret, const Type* const type);
|
||||
static oatpp::Void deserializeFloat64(Deserializer* deserializer, utils::parser::Caret& caret, const Type* const type);
|
||||
static oatpp::Void deserializeBoolean(Deserializer* deserializer, utils::parser::Caret& caret, const Type* const type);
|
||||
static oatpp::Void deserializeString(Deserializer* deserializer, utils::parser::Caret& caret, const Type* const type);
|
||||
static oatpp::Void deserializeAny(Deserializer* deserializer, utils::parser::Caret& caret, const Type* const type);
|
||||
static oatpp::Void deserializeEnum(Deserializer* deserializer, utils::parser::Caret& caret, const Type* const type);
|
||||
|
||||
static oatpp::Void deserializeCollection(Deserializer* deserializer, utils::parser::Caret& caret, const Type* type);
|
||||
static oatpp::Void deserializeMap(Deserializer* deserializer, utils::parser::Caret& caret, const Type* const type);
|
||||
|
||||
static oatpp::Void deserializeObject(Deserializer* deserializer, utils::parser::Caret& caret, const Type* const type);
|
||||
};
|
||||
|
||||
private:
|
||||
std::shared_ptr<Config> m_config;
|
||||
std::vector<DeserializerMethod> m_methods;
|
||||
|
||||
static void deserializeNull(MappingState& state);
|
||||
static void deserializeNumber(MappingState& state);
|
||||
static void deserializeBoolean(MappingState& state);
|
||||
static void deserializeString(MappingState& state);
|
||||
|
||||
static void deserializeArray(MappingState& state);
|
||||
static void deserializeMap(MappingState& state);
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param config
|
||||
*/
|
||||
Deserializer(const std::shared_ptr<Config>& config = std::make_shared<Config>());
|
||||
|
||||
/**
|
||||
* Set deserializer method for type.
|
||||
* @param classId - &id:oatpp::data::mapping::type::ClassId;.
|
||||
* @param method - `typedef oatpp::Void (*DeserializerMethod)(Deserializer*, utils::parser::Caret&, const Type* const)`.
|
||||
*/
|
||||
void setDeserializerMethod(const data::mapping::type::ClassId& classId, DeserializerMethod method);
|
||||
|
||||
/**
|
||||
* Deserialize text.
|
||||
* @param caret - &id:oatpp::utils::parser::Caret;.
|
||||
* @param type - &id:oatpp::data::mapping::type::Type;
|
||||
* @return - `oatpp::Void` over deserialized object.
|
||||
*/
|
||||
oatpp::Void deserialize(utils::parser::Caret& caret, const Type* const type);
|
||||
|
||||
/**
|
||||
* Get deserializer config.
|
||||
* @return
|
||||
*/
|
||||
const std::shared_ptr<Config>& getConfig();
|
||||
static void deserialize(MappingState& state);
|
||||
|
||||
};
|
||||
|
||||
|
@ -27,21 +27,20 @@
|
||||
namespace oatpp { namespace json {
|
||||
|
||||
ObjectMapper::ObjectMapper(const std::shared_ptr<Serializer::Config>& serializerConfig,
|
||||
const std::shared_ptr<Deserializer::Config>& deserializerConfig)
|
||||
const std::shared_ptr<DeserializerConfig>& deserializerConfig)
|
||||
: data::mapping::ObjectMapper(getMapperInfo())
|
||||
, m_serializer(std::make_shared<Serializer>(serializerConfig))
|
||||
, m_deserializer(std::make_shared<Deserializer>(deserializerConfig))
|
||||
, m_deserializerConfig(deserializerConfig)
|
||||
{}
|
||||
|
||||
ObjectMapper::ObjectMapper(const std::shared_ptr<Serializer>& serializer,
|
||||
const std::shared_ptr<Deserializer>& deserializer)
|
||||
ObjectMapper::ObjectMapper(const std::shared_ptr<Serializer>& serializer)
|
||||
: data::mapping::ObjectMapper(getMapperInfo())
|
||||
, m_serializer(serializer)
|
||||
, m_deserializer(deserializer)
|
||||
, m_deserializerConfig(std::make_shared<DeserializerConfig>())
|
||||
{}
|
||||
|
||||
std::shared_ptr<ObjectMapper> ObjectMapper::createShared(const std::shared_ptr<Serializer::Config>& serializerConfig,
|
||||
const std::shared_ptr<Deserializer::Config>& deserializerConfig)
|
||||
const std::shared_ptr<DeserializerConfig>& deserializerConfig)
|
||||
{
|
||||
return std::make_shared<ObjectMapper>(serializerConfig, deserializerConfig);
|
||||
}
|
||||
@ -49,7 +48,7 @@ std::shared_ptr<ObjectMapper> ObjectMapper::createShared(const std::shared_ptr<S
|
||||
std::shared_ptr<ObjectMapper> ObjectMapper::createShared(const std::shared_ptr<Serializer>& serializer,
|
||||
const std::shared_ptr<Deserializer>& deserializer)
|
||||
{
|
||||
return std::make_shared<ObjectMapper>(serializer, deserializer);
|
||||
return std::make_shared<ObjectMapper>(serializer);
|
||||
}
|
||||
|
||||
void ObjectMapper::write(data::stream::ConsistentOutputStream* stream,
|
||||
@ -58,15 +57,45 @@ void ObjectMapper::write(data::stream::ConsistentOutputStream* stream,
|
||||
}
|
||||
|
||||
oatpp::Void ObjectMapper::read(oatpp::utils::parser::Caret& caret, const oatpp::data::mapping::type::Type* const type) const {
|
||||
return m_deserializer->deserialize(caret, type);
|
||||
|
||||
data::mapping::Tree tree;
|
||||
|
||||
{
|
||||
Deserializer::MappingState state;
|
||||
state.caret = ⁁
|
||||
state.tree = &tree;
|
||||
state.config = m_deserializerConfig.get();
|
||||
|
||||
Deserializer::deserialize(state);
|
||||
|
||||
if (!state.errorStack.empty()) {
|
||||
//return nullptr;
|
||||
throw utils::parser::ParsingError(state.errorStacktrace(), 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
data::mapping::TreeToObjectMapper::MappingState state;
|
||||
state.tree = &tree;
|
||||
state.config = m_deserializerConfig.get();
|
||||
|
||||
const auto & result = m_treeToObjectMapper.map(state, type);
|
||||
if(!state.errorStacktrace()->empty()) {
|
||||
throw utils::parser::ParsingError(state.errorStacktrace(), 0, 0);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<Serializer> ObjectMapper::getSerializer() {
|
||||
return m_serializer;
|
||||
}
|
||||
|
||||
std::shared_ptr<Deserializer> ObjectMapper::getDeserializer() {
|
||||
return m_deserializer;
|
||||
std::shared_ptr<ObjectMapper::DeserializerConfig> ObjectMapper::getDeserializerConfig() {
|
||||
return m_deserializerConfig;
|
||||
}
|
||||
|
||||
}}
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "./Serializer.hpp"
|
||||
#include "./Deserializer.hpp"
|
||||
|
||||
#include "oatpp/data/mapping/TreeToObjectMapper.hpp"
|
||||
#include "oatpp/data/mapping/ObjectMapper.hpp"
|
||||
|
||||
namespace oatpp { namespace json {
|
||||
@ -43,9 +44,21 @@ private:
|
||||
static Info info("application/json");
|
||||
return info;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
class DeserializerConfig : public data::mapping::TreeToObjectMapper::Config, public Deserializer::Config {
|
||||
public:
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
std::shared_ptr<Serializer> m_serializer;
|
||||
std::shared_ptr<Deserializer> m_deserializer;
|
||||
std::shared_ptr<DeserializerConfig> m_deserializerConfig;
|
||||
private:
|
||||
data::mapping::TreeToObjectMapper m_treeToObjectMapper;
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
@ -53,15 +66,14 @@ public:
|
||||
* @param deserializerConfig - &id:oatpp::json::Deserializer::Config;.
|
||||
*/
|
||||
ObjectMapper(const std::shared_ptr<Serializer::Config>& serializerConfig,
|
||||
const std::shared_ptr<Deserializer::Config>& deserializerConfig);
|
||||
const std::shared_ptr<DeserializerConfig>& deserializerConfig);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param serializer
|
||||
* @param deserializer
|
||||
*/
|
||||
ObjectMapper(const std::shared_ptr<Serializer>& serializer = std::make_shared<Serializer>(),
|
||||
const std::shared_ptr<Deserializer>& deserializer = std::make_shared<Deserializer>());
|
||||
ObjectMapper(const std::shared_ptr<Serializer>& serializer = std::make_shared<Serializer>());
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -72,7 +84,7 @@ public:
|
||||
*/
|
||||
static std::shared_ptr<ObjectMapper>
|
||||
createShared(const std::shared_ptr<Serializer::Config>& serializerConfig,
|
||||
const std::shared_ptr<Deserializer::Config>& deserializerConfig);
|
||||
const std::shared_ptr<DeserializerConfig>& deserializerConfig);
|
||||
|
||||
/**
|
||||
* Create shared ObjectMapper.
|
||||
@ -110,7 +122,7 @@ public:
|
||||
* Get deserializer.
|
||||
* @return
|
||||
*/
|
||||
std::shared_ptr<Deserializer> getDeserializer();
|
||||
std::shared_ptr<DeserializerConfig> getDeserializerConfig();
|
||||
|
||||
};
|
||||
|
||||
|
@ -79,7 +79,7 @@ namespace {
|
||||
|
||||
void runTests() {
|
||||
|
||||
/*
|
||||
|
||||
oatpp::Environment::printCompilationConfig();
|
||||
|
||||
OATPP_LOGD("Tests", "oatpp::String size=%lu", sizeof(oatpp::String))
|
||||
@ -96,7 +96,7 @@ void runTests() {
|
||||
OATPP_LOGD("CLASS", "%d --> '%s'", i, name)
|
||||
i ++;
|
||||
}
|
||||
|
||||
/*
|
||||
OATPP_RUN_TEST(oatpp::test::LoggerTest);
|
||||
OATPP_RUN_TEST(oatpp::base::CommandLineArgumentsTest);
|
||||
|
||||
@ -112,35 +112,35 @@ void runTests() {
|
||||
//OATPP_RUN_TEST(oatpp::data::mapping::TreeTest);
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::TreeToObjectMapperTest);
|
||||
|
||||
/*
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::type::ObjectWrapperTest);
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::type::TypeTest);
|
||||
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::type::StringTest);
|
||||
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::type::PrimitiveTest);
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::type::ListTest);
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::type::VectorTest);
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::type::UnorderedSetTest);
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::type::PairListTest);
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::type::UnorderedMapTest);
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::type::AnyTest);
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::type::EnumTest);
|
||||
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::type::ObjectTest);
|
||||
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::type::InterpretationTest);
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::TypeResolverTest);
|
||||
|
||||
OATPP_RUN_TEST(oatpp::data::resource::InMemoryDataTest);
|
||||
|
||||
OATPP_RUN_TEST(oatpp::async::ConditionVariableTest);
|
||||
OATPP_RUN_TEST(oatpp::async::LockTest);
|
||||
|
||||
OATPP_RUN_TEST(oatpp::utils::parser::CaretTest);
|
||||
|
||||
OATPP_RUN_TEST(oatpp::provider::PoolTest);
|
||||
OATPP_RUN_TEST(oatpp::provider::PoolTemplateTest);
|
||||
// OATPP_RUN_TEST(oatpp::data::mapping::type::ObjectWrapperTest);
|
||||
// OATPP_RUN_TEST(oatpp::data::mapping::type::TypeTest);
|
||||
//
|
||||
// OATPP_RUN_TEST(oatpp::data::mapping::type::StringTest);
|
||||
//
|
||||
// OATPP_RUN_TEST(oatpp::data::mapping::type::PrimitiveTest);
|
||||
// OATPP_RUN_TEST(oatpp::data::mapping::type::ListTest);
|
||||
// OATPP_RUN_TEST(oatpp::data::mapping::type::VectorTest);
|
||||
// OATPP_RUN_TEST(oatpp::data::mapping::type::UnorderedSetTest);
|
||||
// OATPP_RUN_TEST(oatpp::data::mapping::type::PairListTest);
|
||||
// OATPP_RUN_TEST(oatpp::data::mapping::type::UnorderedMapTest);
|
||||
// OATPP_RUN_TEST(oatpp::data::mapping::type::AnyTest);
|
||||
// OATPP_RUN_TEST(oatpp::data::mapping::type::EnumTest);
|
||||
//
|
||||
// OATPP_RUN_TEST(oatpp::data::mapping::type::ObjectTest);
|
||||
//
|
||||
// OATPP_RUN_TEST(oatpp::data::mapping::type::InterpretationTest);
|
||||
// OATPP_RUN_TEST(oatpp::data::mapping::TypeResolverTest);
|
||||
//
|
||||
// OATPP_RUN_TEST(oatpp::data::resource::InMemoryDataTest);
|
||||
//
|
||||
// OATPP_RUN_TEST(oatpp::async::ConditionVariableTest);
|
||||
// OATPP_RUN_TEST(oatpp::async::LockTest);
|
||||
//
|
||||
// OATPP_RUN_TEST(oatpp::utils::parser::CaretTest);
|
||||
//
|
||||
// OATPP_RUN_TEST(oatpp::provider::PoolTest);
|
||||
// OATPP_RUN_TEST(oatpp::provider::PoolTemplateTest);
|
||||
|
||||
OATPP_RUN_TEST(oatpp::json::EnumTest);
|
||||
OATPP_RUN_TEST(oatpp::json::BooleanTest);
|
||||
@ -150,7 +150,7 @@ void runTests() {
|
||||
OATPP_RUN_TEST(oatpp::json::DeserializerTest);
|
||||
OATPP_RUN_TEST(oatpp::json::DTOMapperPerfTest);
|
||||
OATPP_RUN_TEST(oatpp::json::DTOMapperTest);
|
||||
|
||||
/*
|
||||
OATPP_RUN_TEST(oatpp::test::encoding::Base64Test);
|
||||
OATPP_RUN_TEST(oatpp::test::encoding::UnicodeTest);
|
||||
OATPP_RUN_TEST(oatpp::test::encoding::UrlTest);
|
||||
|
@ -182,7 +182,7 @@ void InterpretationTest::onRun() {
|
||||
}
|
||||
|
||||
{
|
||||
auto config = mapper.getDeserializer()->getConfig();
|
||||
auto config = mapper.getDeserializerConfig();
|
||||
config->enabledInterpretations = {"test"};
|
||||
}
|
||||
|
||||
|
@ -307,12 +307,12 @@ void DeserializerTest::onRun(){
|
||||
OATPP_ASSERT(dto->any.getStoredType() == Float64::Class::getType())
|
||||
OATPP_ASSERT(fabs(dto->any.retrieve<Float64>() - 1.2345e30) < std::numeric_limits<double>::epsilon())
|
||||
}
|
||||
OATPP_LOGD(TAG, "Any: Unsigned Integer")
|
||||
OATPP_LOGD(TAG, "Any: Big Integer")
|
||||
{
|
||||
auto dto = mapper->readFromString<oatpp::Object<AnyDto>>(R"({"any":12345678901234567890,"another":1.1})");
|
||||
auto dto = mapper->readFromString<oatpp::Object<AnyDto>>(R"({"any":9223372036854775807,"another":1.1})");
|
||||
OATPP_ASSERT(dto)
|
||||
OATPP_ASSERT(dto->any.getStoredType() == UInt64::Class::getType())
|
||||
OATPP_ASSERT(dto->any.retrieve<UInt64>() == 12345678901234567890u)
|
||||
OATPP_ASSERT(dto->any.getStoredType() == Int64::Class::getType())
|
||||
OATPP_ASSERT(dto->any.retrieve<Int64>() == 9223372036854775807)
|
||||
}
|
||||
OATPP_LOGD(TAG, "Any: Signed Integer")
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user