data::mapping. Introduce Type::Interpretation.

This commit is contained in:
lganzzzo 2020-08-20 05:04:40 +03:00
parent a2c9209b7a
commit d6911eb77a
10 changed files with 338 additions and 5 deletions

View File

@ -98,12 +98,14 @@ Type::Type(const ClassId& pClassId,
const char* pNameQualifier,
Creator pCreator,
PropertiesGetter pPropertiesGetter,
void* pPolymorphicDispatcher)
void* pPolymorphicDispatcher,
InterpretationMap&& pInterpretationMap)
: classId(pClassId)
, nameQualifier(pNameQualifier)
, creator(pCreator)
, propertiesGetter(pPropertiesGetter)
, polymorphicDispatcher(pPolymorphicDispatcher)
, interpretationMap(pInterpretationMap)
{}
}}}}

View File

@ -332,6 +332,39 @@ public:
Void& getAsRef(void* object);
};
public:
class AbstractInterpretation {
public:
virtual Void toInterpretation(const Void& originalValue) const = 0;
virtual Void fromInterpretation(const Void& interValue) const = 0;
virtual Type* getInterpretationType() const = 0;
};
template<class OriginalWrapper, class InterWrapper>
class Interpretation : public AbstractInterpretation {
public:
Void toInterpretation(const Void& originalValue) const override {
return interpret(originalValue.staticCast<OriginalWrapper>());
}
Void fromInterpretation(const Void& interValue) const override {
return reproduce(interValue.staticCast<InterWrapper>());
}
Type* getInterpretationType() const override {
return InterWrapper::Class::getType();
}
public:
virtual InterWrapper interpret(const OriginalWrapper& value) const = 0;
virtual OriginalWrapper reproduce(const InterWrapper& value) const = 0;
};
typedef std::unordered_map<std::string, const AbstractInterpretation*> InterpretationMap;
public:
typedef Void (*Creator)();
@ -345,12 +378,14 @@ public:
* @param pCreator - function pointer of Creator - function to create instance of this type.
* @param pPropertiesGetter - function to get properties of the type.
* @param pPolymorphicDispatcher - dispatcher to correctly address methods of the type.
* @param pInterpretationMap - Map of type Interpretations.
*/
Type(const ClassId& pClassId,
const char* pNameQualifier,
Creator pCreator = nullptr,
PropertiesGetter pPropertiesGetter = nullptr,
void* pPolymorphicDispatcher = nullptr);
void* pPolymorphicDispatcher = nullptr,
InterpretationMap&& pInterpretationMap = {});
/**
* type class id.
@ -381,6 +416,11 @@ public:
* PolymorphicDispatcher - is an object to forward polymorphic calls to a correct object of type `Type`.
*/
const void* const polymorphicDispatcher;
/**
* Map of type Interpretations.
*/
const InterpretationMap interpretationMap;
};

View File

@ -358,12 +358,29 @@ oatpp::Void Deserializer::deserializeObject(Deserializer* deserializer, parser::
}
const oatpp::Type::AbstractInterpretation* Deserializer::findTypeInterpretation(const oatpp::Type* type) {
const auto& intMap = type->interpretationMap;
for(auto& name : m_config->enableInterpretations) {
auto it = intMap.find(name);
if(it != intMap.end()) {
return it->second;
}
}
return nullptr;
}
oatpp::Void Deserializer::deserialize(parser::Caret& caret, const Type* const type) {
auto id = type->classId.id;
auto& method = m_methods[id];
if(method) {
return (*method)(this, caret, type);
} else {
auto* interpretation = findTypeInterpretation(type);
if(interpretation) {
return interpretation->fromInterpretation(deserialize(caret, interpretation->getInterpretationType()));
}
throw std::runtime_error("[oatpp::parser::json::mapping::Deserializer::deserialize()]: "
"Error. No deserialize method for type '" + std::string(type->classId.name) + "'");
}

View File

@ -110,6 +110,11 @@ public:
*/
bool allowUnknownFields = true;
/**
* Enable type interpretations.
*/
std::vector<std::string> enableInterpretations = {};
};
public:
@ -279,6 +284,8 @@ private:
static oatpp::Void deserializeEnum(Deserializer* deserializer, parser::Caret& caret, const Type* const type);
static oatpp::Void deserializeObject(Deserializer* deserializer, parser::Caret& caret, const Type* const type);
private:
const oatpp::Type::AbstractInterpretation* findTypeInterpretation(const oatpp::Type* type);
private:
std::shared_ptr<Config> m_config;
std::vector<DeserializerMethod> m_methods;

View File

@ -171,6 +171,17 @@ void Serializer::serializeObject(Serializer* serializer,
}
const oatpp::Type::AbstractInterpretation* Serializer::findTypeInterpretation(const oatpp::Type* type) {
const auto& intMap = type->interpretationMap;
for(auto& name : m_config->enableInterpretations) {
auto it = intMap.find(name);
if(it != intMap.end()) {
return it->second;
}
}
return nullptr;
}
void Serializer::serialize(data::stream::ConsistentOutputStream* stream,
const oatpp::Void& polymorph)
{
@ -179,8 +190,16 @@ void Serializer::serialize(data::stream::ConsistentOutputStream* stream,
if(method) {
(*method)(this, stream, polymorph);
} else {
throw std::runtime_error("[oatpp::parser::json::mapping::Serializer::serialize()]: "
"Error. No serialize method for type '" + std::string(polymorph.valueType->classId.name) + "'");
auto* interpretation = findTypeInterpretation(polymorph.valueType);
if(interpretation) {
serialize(stream, interpretation->toInterpretation(polymorph));
} else {
throw std::runtime_error("[oatpp::parser::json::mapping::Serializer::serialize()]: "
"Error. No serialize method for type '" +
std::string(polymorph.valueType->classId.name) + "'");
}
}
}

View File

@ -91,6 +91,11 @@ public:
*/
oatpp::String beautifierNewLine = "\n";
/**
* Enable type interpretations.
*/
std::vector<std::string> enableInterpretations = {};
};
public:
typedef void (*SerializerMethod)(Serializer*,
@ -182,6 +187,8 @@ private:
void serialize(data::stream::ConsistentOutputStream* stream, const oatpp::Void& polymorph);
private:
const oatpp::Type::AbstractInterpretation* findTypeInterpretation(const oatpp::Type* type);
private:
std::shared_ptr<Config> m_config;
std::vector<SerializerMethod> m_methods;

View File

@ -19,6 +19,8 @@ add_executable(oatppAllTests
oatpp/core/data/mapping/type/AnyTest.hpp
oatpp/core/data/mapping/type/EnumTest.cpp
oatpp/core/data/mapping/type/EnumTest.hpp
oatpp/core/data/mapping/type/InterpretationTest.cpp
oatpp/core/data/mapping/type/InterpretationTest.hpp
oatpp/core/data/mapping/type/ListTest.cpp
oatpp/core/data/mapping/type/ListTest.hpp
oatpp/core/data/mapping/type/ObjectTest.cpp

View File

@ -40,6 +40,8 @@
#include "oatpp/core/data/mapping/type/TypeTest.hpp"
#include "oatpp/core/data/mapping/type/AnyTest.hpp"
#include "oatpp/core/data/mapping/type/EnumTest.hpp"
#include "oatpp/core/data/mapping/type/InterpretationTest.hpp"
#include "oatpp/core/data/stream/BufferStreamTest.hpp"
#include "oatpp/core/data/stream/ChunkedBufferTest.hpp"
#include "oatpp/core/data/share/LazyStringMapTest.hpp"
@ -99,9 +101,10 @@ void runTests() {
OATPP_RUN_TEST(oatpp::test::core::data::mapping::type::UnorderedMapTest);
OATPP_RUN_TEST(oatpp::test::core::data::mapping::type::AnyTest);
OATPP_RUN_TEST(oatpp::test::core::data::mapping::type::EnumTest);
OATPP_RUN_TEST(oatpp::test::core::data::mapping::type::ObjectTest);
OATPP_RUN_TEST(oatpp::test::core::data::mapping::type::InterpretationTest);
OATPP_RUN_TEST(oatpp::test::async::LockTest);
OATPP_RUN_TEST(oatpp::test::parser::CaretTest);

View File

@ -0,0 +1,194 @@
/***************************************************************************
*
* Project _____ __ ____ _ _
* ( _ ) /__\ (_ _)_| |_ _| |_
* )(_)( /(__)\ )( (_ _)(_ _)
* (_____)(__)(__)(__) |_| |_|
*
*
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
***************************************************************************/
#include "InterpretationTest.hpp"
#include "oatpp/parser/json/mapping/ObjectMapper.hpp"
#include "oatpp/core/Types.hpp"
#include "oatpp/core/macro/codegen.hpp"
namespace oatpp { namespace test { namespace core { namespace data { namespace mapping { namespace type {
namespace {
#include OATPP_CODEGEN_BEGIN(DTO)
struct VPoint {
v_int32 x;
v_int32 y;
v_int32 z;
};
struct VLine {
VPoint p1;
VPoint p2;
};
namespace __class {
class PointClass;
class LineClass;
}
typedef oatpp::data::mapping::type::Primitive<VPoint, __class::PointClass> Point;
typedef oatpp::data::mapping::type::Primitive<VLine, __class::LineClass> Line;
namespace __class {
class PointClass {
private:
class PointDto : public oatpp::DTO {
DTO_INIT(PointDto, DTO)
DTO_FIELD(Int32, x);
DTO_FIELD(Int32, y);
DTO_FIELD(Int32, z);
};
class Inter : public oatpp::Type::Interpretation<Point, oatpp::Object<PointDto>> {
public:
oatpp::Object<PointDto> interpret(const Point& value) const override {
auto dto = PointDto::createShared();
dto->x = value->x;
dto->y = value->y;
dto->z = value->z;
return dto;
}
Point reproduce(const oatpp::Object<PointDto>& value) const override {
return Point({value->x, value->y, value->z});
}
};
public:
static const oatpp::ClassId CLASS_ID;
static oatpp::Type* getType(){
static Type type(
CLASS_ID, nullptr, nullptr, nullptr, nullptr,
{
{"test", new Inter()}
}
);
return &type;
}
};
const oatpp::ClassId PointClass::CLASS_ID("test::Point");
class LineClass {
private:
class LineDto : public oatpp::DTO {
DTO_INIT(LineDto, DTO)
DTO_FIELD(Point, p1);
DTO_FIELD(Point, p2);
};
class Inter : public oatpp::Type::Interpretation<Line, oatpp::Object<LineDto>> {
public:
oatpp::Object<LineDto> interpret(const Line& value) const override {
auto dto = LineDto::createShared();
dto->p1 = {value->p1.x, value->p1.y, value->p1.z};
dto->p2 = {value->p2.x, value->p2.y, value->p2.z};
return dto;
}
Line reproduce(const oatpp::Object<LineDto>& value) const override {
return Line({{value->p1->x, value->p1->y, value->p1->z},
{value->p2->x, value->p2->y, value->p2->z}});
}
};
public:
static const oatpp::ClassId CLASS_ID;
static oatpp::Type* getType(){
static Type type(
CLASS_ID, nullptr, nullptr, nullptr, nullptr,
{
{"test", new Inter()}
}
);
return &type;
}
};
const oatpp::ClassId LineClass::CLASS_ID("test::Line");
}
#include OATPP_CODEGEN_END(DTO)
}
void InterpretationTest::onRun() {
oatpp::parser::json::mapping::ObjectMapper mapper;
{
auto config = mapper.getSerializer()->getConfig();
config->enableInterpretations = {"test"};
config->useBeautifier = false;
}
{
auto config = mapper.getDeserializer()->getConfig();
config->enableInterpretations = {"test"};
}
Point p1 ({1, 2, 3});
Point p2 ({11, 12, 13});
Line l ({p1, p2});
auto json1 = mapper.writeToString(l);
OATPP_LOGD(TAG, "json1='%s'", json1->c_str());
auto rl = mapper.readFromString<Line>(json1);
auto json2 = mapper.writeToString(rl);
OATPP_LOGD(TAG, "json2='%s'", json2->c_str());
OATPP_ASSERT(json1 == json2);
}
}}}}}}

View File

@ -0,0 +1,42 @@
/***************************************************************************
*
* Project _____ __ ____ _ _
* ( _ ) /__\ (_ _)_| |_ _| |_
* )(_)( /(__)\ )( (_ _)(_ _)
* (_____)(__)(__)(__) |_| |_|
*
*
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
***************************************************************************/
#ifndef oatpp_test_core_data_mapping_type_InterpretationTest_hpp
#define oatpp_test_core_data_mapping_type_InterpretationTest_hpp
#include "oatpp-test/UnitTest.hpp"
namespace oatpp { namespace test { namespace core { namespace data { namespace mapping { namespace type {
class InterpretationTest : public UnitTest{
public:
InterpretationTest():UnitTest("TEST[core::data::mapping::type::InterpretationTest]"){}
void onRun() override;
};
}}}}}}
#endif // oatpp_test_core_data_mapping_type_InterpretationTest_hpp