mirror of
https://github.com/oatpp/oatpp.git
synced 2024-11-27 08:30:07 +08:00
data::mapping. Introduce Type::Interpretation.
This commit is contained in:
parent
a2c9209b7a
commit
d6911eb77a
@ -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)
|
||||
{}
|
||||
|
||||
}}}}
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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) + "'");
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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) + "'");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
194
test/oatpp/core/data/mapping/type/InterpretationTest.cpp
Normal file
194
test/oatpp/core/data/mapping/type/InterpretationTest.cpp
Normal 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);
|
||||
|
||||
}
|
||||
|
||||
}}}}}}
|
42
test/oatpp/core/data/mapping/type/InterpretationTest.hpp
Normal file
42
test/oatpp/core/data/mapping/type/InterpretationTest.hpp
Normal 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
|
Loading…
Reference in New Issue
Block a user