#pragma once #include #include #include "Array.h" #include "ReferenceCounter.h" #include "Text.h" #include "Trie.h" #include "Writer.h" #include "XML.h" namespace Framework { namespace JSON { enum class JSONType { NULL_, BOOLEAN, NUMBER, STRING, ARRAY, OBJECT }; class JSONArray; class JSONObject; class JSONBool; class JSONNumber; class JSONString; class JSONValue : public virtual ReferenceCounter { private: JSONType type; protected: __declspec(dllexport) JSONValue(JSONType type); public: __declspec(dllexport) JSONValue(); __declspec(dllexport) virtual ~JSONValue(); __declspec(dllexport) JSONType getType() const; __declspec(dllexport) virtual Text toString() const; __declspec(dllexport) virtual JSONValue* clone() const; __declspec(dllexport) JSONBool* asBool() const; __declspec(dllexport) JSONNumber* asNumber() const; __declspec(dllexport) JSONString* asString() const; __declspec(dllexport) JSONArray* asArray() const; __declspec(dllexport) JSONObject* asObject() const; }; class JSONBool : public JSONValue { private: bool b; public: __declspec(dllexport) JSONBool(bool b); __declspec(dllexport) bool getBool() const; __declspec(dllexport) Text toString() const override; __declspec(dllexport) JSONValue* clone() const override; }; class JSONNumber : public JSONValue { private: double number; public: __declspec(dllexport) JSONNumber(double num); __declspec(dllexport) double getNumber() const; __declspec(dllexport) Text toString() const override; __declspec(dllexport) JSONValue* clone() const override; }; class JSONString : public JSONValue { private: Text string; public: __declspec(dllexport) JSONString(Text string); __declspec(dllexport) Text getString() const; __declspec(dllexport) Text toString() const override; __declspec(dllexport) JSONValue* clone() const override; }; class JSONArray : public JSONValue { private: RCArray* array; public: __declspec(dllexport) JSONArray(); __declspec(dllexport) JSONArray(Text string); __declspec(dllexport) JSONArray(const JSONArray& arr); __declspec(dllexport) ~JSONArray(); __declspec(dllexport) JSONArray& operator=(const JSONArray& arr); __declspec(dllexport) void addValue(JSONValue* value); __declspec(dllexport) void setValue(int i, JSONValue* value); __declspec(dllexport) void removeValue(int i); __declspec(dllexport) JSONValue* getValue(int i) const; __declspec(dllexport) JSONValue* zValue(int i) const; __declspec(dllexport) int getLength() const; __declspec(dllexport) bool isValueOfType( int i, JSONType type) const; //! Gibt einen Iterator zurück. //! Mit ++ kann durch die Liste iteriert werden __declspec(dllexport) ArrayIterator begin() const; __declspec(dllexport) ArrayIterator end() const; template RCArray* toRCArray(std::function map) const { return toRCArray([](JSONValue& v) { return 1; }, map); } template RCArray* toRCArray(std::function filter, std::function map) const { RCArray* result = new RCArray(); for (auto v : *array) { if (filter(*v)) { result->add(map(*v)); } } return result; } template Array* toArray(std::function map) const { return toArray([](JSONValue& v) { return 1; }, map); ; } template Array* toArray(std::function filter, std::function map) const { Array* result = new Array(); for (auto v : *array) { if (filter(*v)) { result->add(map(*v)); } } return result; } __declspec(dllexport) Text toString() const override; __declspec(dllexport) JSONValue* clone() const override; template static JSONArray* fromRCArray( Framework::RCArray& arr, std::function map) { JSONArray* array = new JSONArray(); for (T* v : arr) { array->addValue(map(*v)); } return array; } template static JSONArray* fromArray( Framework::Array& arr, std::function map) { JSONArray* array = new JSONArray(); for (T v : arr) { array->addValue(map(v)); } return array; } }; class JSONObject : public JSONValue { private: Array* fields; RCArray* values; public: __declspec(dllexport) JSONObject(); __declspec(dllexport) JSONObject(Text string); __declspec(dllexport) JSONObject(const JSONObject& obj); __declspec(dllexport) ~JSONObject(); __declspec(dllexport) JSONObject& operator=(const JSONObject& obj); __declspec(dllexport) bool addValue(Text field, JSONValue* value); __declspec(dllexport) bool removeValue(Text field); __declspec(dllexport) bool hasValue(Text field); __declspec(dllexport) JSONValue* getValue(Text field); __declspec(dllexport) JSONValue* zValue(Text field); __declspec(dllexport) ArrayIterator getFields(); __declspec(dllexport) ArrayIterator getValues(); __declspec(dllexport) int getFieldCount() const; __declspec(dllexport) bool isValueOfType( Text field, JSONType type) const; template T* parseTo(T* initialState, std::function parser) const { auto fieldsI = fields->begin(); auto valuesI = values->begin(); while (fieldsI && valuesI) { parser(initialState, fieldsI, *(JSONValue*)valuesI); fieldsI++; valuesI++; } return initialState; } __declspec(dllexport) Text toString() const override; __declspec(dllexport) JSONValue* clone() const override; }; __declspec(dllexport) JSONValue* loadJSONFromFile(Text path); namespace Parser { __declspec(dllexport) int findObjectEndInArray(const char* str); __declspec(dllexport) Text removeWhitespace(const char* str); __declspec(dllexport) JSONValue* getValue(const char* str); __declspec(dllexport) int findFieldEndInObject(const char* str); __declspec(dllexport) int findValueEndInObject(const char* str); }; // namespace Parser namespace Validator { class JSONValidationResult : public Framework::ReferenceCounter { public: __declspec(dllexport) JSONValidationResult(); __declspec(dllexport) virtual ~JSONValidationResult(); virtual bool isValid() const = 0; __declspec(dllexport) void logInvalidInfo( std::source_location location = std::source_location::current()) const; virtual Text getInvalidInfo(int indent = 0) const = 0; virtual JSONValue* getValidPart(RCArray* zRemovedPartsValidationResults) = 0; virtual Text getPath() const = 0; virtual void addBasePath(Text basePath) = 0; virtual bool isDifferent( const JSONValidationResult* zResult) const = 0; }; class JSONTypeMissmatch : public JSONValidationResult { private: Text path; JSONValue* foundValue; XML::Element* expected; JSONValidationResult* reason; public: __declspec(dllexport) JSONTypeMissmatch(Text path, JSONValue* foundValue, XML::Element* expected, JSONValidationResult* reason); __declspec(dllexport) ~JSONTypeMissmatch(); __declspec(dllexport) bool isValid() const override; __declspec(dllexport) Text getInvalidInfo(int indent) const override; protected: __declspec(dllexport) JSONValue* getValidPart( RCArray* zRemovedPartsValidationResults) override; __declspec(dllexport) Text getPath() const override; __declspec(dllexport) bool isDifferent( const JSONValidationResult* zResult) const override; __declspec(dllexport) void addBasePath(Text basePath) override; }; class JSONUnknownValue : public JSONValidationResult { private: Text path; JSONValue* foundValue; public: __declspec(dllexport) JSONUnknownValue(Text path, JSONValue* foundValue); __declspec(dllexport) ~JSONUnknownValue(); __declspec(dllexport) bool isValid() const override; __declspec(dllexport) Text getInvalidInfo(int indent) const override; __declspec(dllexport) JSONValue* getValidPart( RCArray* zRemovedPartsValidationResults) override; __declspec(dllexport) Text getPath() const override; __declspec(dllexport) bool isDifferent( const JSONValidationResult* zResult) const override; __declspec(dllexport) void addBasePath(Text basePath) override; }; class JSONMissingValue : public JSONValidationResult { private: Text path; XML::Element* expected; public: __declspec(dllexport) JSONMissingValue(Text path, XML::Element* expected); __declspec(dllexport) ~JSONMissingValue(); __declspec(dllexport) bool isValid() const override; __declspec(dllexport) Text getInvalidInfo(int indent) const override; __declspec(dllexport) JSONValue* getValidPart( RCArray* zRemovedPartsValidationResults) override; __declspec(dllexport) Text getPath() const override; __declspec(dllexport) bool isDifferent( const JSONValidationResult* zResult) const override; __declspec(dllexport) void addBasePath(Text basePath) override; }; class JSONMissingOneOf : public JSONValidationResult { private: Text path; RCArray expected; public: __declspec(dllexport) JSONMissingOneOf(Text path, XML::Editor expected); __declspec(dllexport) ~JSONMissingOneOf(); __declspec(dllexport) bool isValid() const override; __declspec(dllexport) Text getInvalidInfo(int indent) const override; __declspec(dllexport) JSONValue* getValidPart( RCArray* zRemovedPartsValidationResults) override; __declspec(dllexport) Text getPath() const override; __declspec(dllexport) bool isDifferent( const JSONValidationResult* zResult) const override; __declspec(dllexport) void addBasePath(Text basePath) override; }; class JSONNoTypeMatching : public JSONValidationResult { private: Text path; JSONValue* foundValue; RCArray expected; RCArray reasons; public: __declspec(dllexport) JSONNoTypeMatching(Text path, JSONValue* foundValue, RCArray& expected, RCArray& reasons); __declspec(dllexport) ~JSONNoTypeMatching(); __declspec(dllexport) bool isValid() const override; __declspec(dllexport) Text getInvalidInfo(int indent) const override; __declspec(dllexport) JSONValue* getValidPart( RCArray* zRemovedPartsValidationResults) override; __declspec(dllexport) Text getPath() const override; __declspec(dllexport) bool isDifferent( const JSONValidationResult* zResult) const override; __declspec(dllexport) void addBasePath(Text basePath) override; }; class JSONValidValue : public JSONValidationResult { private: Text path; JSONValue* value; public: __declspec(dllexport) JSONValidValue(Text path, JSONValue* value); __declspec(dllexport) ~JSONValidValue(); __declspec(dllexport) bool isValid() const override; __declspec(dllexport) Text getInvalidInfo(int indent) const override; __declspec(dllexport) JSONValue* getValidPart( RCArray* zRemovedPartsValidationResults) override; __declspec(dllexport) Text getPath() const override; __declspec(dllexport) bool isDifferent( const JSONValidationResult* zResult) const override; __declspec(dllexport) void addBasePath(Text basePath) override; }; template class StringValidationBuilder; template class NumberValidationBuilder; template class BoolValidationBuilder; template class ObjectValidationBuilder; template class ArrayValidationBuilder; template class OneOfValidationBuilder; class JSONValidator : public Framework::ReferenceCounter { private: XML::Element* constraints; Trie typeConstraints; public: __declspec(dllexport) JSONValidator(XML::Element* constraints); __declspec(dllexport) ~JSONValidator(); __declspec(dllexport) JSONValidationResult* validate( JSONValue* zValue) const; __declspec(dllexport) bool isValid(JSONValue* zValue) const; /** * returns the valid part of the json by performing the * following operations in the specified order untill no further * changes are made: * - invalid or unknown object properties are removed * - missing object properties with default values are added if * missing * - invalid array elements are removed * * @param zValue the json value to to extract the valid part * without increased reference counter * @return the valid part or 0 if no valid part exists */ __declspec(dllexport) JSONValue* getValidParts( JSONValue* zValue, RCArray* zRemovedPartsValidationResults) const; __declspec(dllexport) XML::Element* zConstraints(); private: __declspec(dllexport) JSONValidationResult* validate( JSONValue* zValue, XML::Element* zConstraints, Text path) const; __declspec(dllexport) JSONValidationResult* validateMultipleTypes( JSONValue* zChildValue, XML::Element* zPossibleChildConstraints, Text childPath) const; public: __declspec(dllexport) static StringValidationBuilder< JSONValidator>* buildForString(); __declspec(dllexport) static NumberValidationBuilder< JSONValidator>* buildForNumber(); __declspec(dllexport) static BoolValidationBuilder< JSONValidator>* buildForBool(); __declspec(dllexport) static ObjectValidationBuilder< JSONValidator>* buildForObject(); __declspec(dllexport) static ArrayValidationBuilder< JSONValidator>* buildForArray(); __declspec(dllexport) static OneOfValidationBuilder< JSONValidator>* buildForOneOf(); __declspec( dllexport) static JSONValidator* buildForObjectReference(Text objectId); }; template class StringValidationBuilder { private: XML::Element element; std::function builder; public: StringValidationBuilder( std::function builder) : element(""), builder(builder) {} StringValidationBuilder* withExactMatch(Text value) { element.setAttribute("equals", value); return this; } StringValidationBuilder* whichContainsMatch(Text value) { element.setAttribute("contains", value); return this; } StringValidationBuilder* whichStartsWithMatch(Text value) { element.setAttribute("startsWith", value); return this; } StringValidationBuilder* whichEndsWithMatch(Text value) { element.setAttribute("endsWith", value); return this; } StringValidationBuilder* whichIsOneOf(RCArray values) { JSONArray arr; for (Text* str : values) arr.addValue(new JSONString(str->getText())); element.setAttribute("oneOf", arr.toString()); return this; } StringValidationBuilder* whichIsOneOf( std::initializer_list values) { JSONArray arr; for (Text str : values) arr.addValue(new JSONString(str)); element.setAttribute("oneOf", arr.toString()); return this; } StringValidationBuilder* whichIs(Text value) { JSONArray arr; arr.addValue(new JSONString(value)); element.setAttribute("oneOf", arr.toString()); return this; } StringValidationBuilder* withDefault(Text value) { element.setAttribute( "default", JSONString(value).toString()); return this; } StringValidationBuilder* withDefaultNull() { element.setAttribute("default", "null"); return this; } StringValidationBuilder* whichCanBeNull() { element.setAttribute("nullable", "true"); return this; } StringValidationBuilder* whichIsOptional() { element.setAttribute("optional", "true"); return this; } T* finishString() { T* result = builder(element); delete this; return result; } }; template class NumberValidationBuilder { private: XML::Element element; std::function builder; public: NumberValidationBuilder( std::function builder) : element(""), builder(builder) {} NumberValidationBuilder* whichIs(double value) { element.setAttribute("equals", Text(value)); return this; } NumberValidationBuilder* whichIsLessOrEqual(double value) { element.setAttribute("lessOrEqual", Text(value)); return this; } NumberValidationBuilder* whichIsGreaterOrEqual(double value) { element.setAttribute("greaterOrEqual", Text(value)); return this; } NumberValidationBuilder* whichIsLessThen(double value) { element.setAttribute("less", Text(value)); return this; } NumberValidationBuilder* whichIsGreaterThen(double value) { element.setAttribute("greater", Text(value)); return this; } NumberValidationBuilder* withDefault(double value) { element.setAttribute( "default", JSONNumber(value).toString()); return this; } NumberValidationBuilder* withDefaultNull() { element.setAttribute("default", "null"); return this; } NumberValidationBuilder* whichCanBeNull() { element.setAttribute("nullable", "true"); return this; } NumberValidationBuilder* whichIsOptional() { element.setAttribute("optional", "true"); return this; } T* finishNumber() { T* result = builder(element); delete this; return result; } }; template class BoolValidationBuilder { private: XML::Element element; std::function builder; public: BoolValidationBuilder( std::function builder) : element(""), builder(builder) {} BoolValidationBuilder* whichIs(bool value) { element.setAttribute("equals", value ? "true" : "false"); return this; } BoolValidationBuilder* withDefault(bool value) { element.setAttribute("default", JSONBool(value).toString()); return this; } BoolValidationBuilder* withDefaultNull() { element.setAttribute("default", "null"); return this; } BoolValidationBuilder* whichCanBeNull() { element.setAttribute("nullable", "true"); return this; } BoolValidationBuilder* whichIsOptional() { element.setAttribute("optional", "true"); return this; } T* finishBool() { T* result = builder(element); delete this; return result; } }; template class ArrayValidationBuilder; template class ObjectValidationBuilder { private: XML::Element element; std::function builder; public: ObjectValidationBuilder( std::function builder) : element(""), builder(builder) {} ObjectValidationBuilder* setObjectReferenceId(Text id) { element.setAttribute("id", id); return this; } NumberValidationBuilder>* withRequiredNumber(Text name) { return new NumberValidationBuilder< ObjectValidationBuilder>( [this, name](XML::Element& e) { if (!element.selectChildsByAttribute("name", name) .exists()) { XML::Element* attr = new XML::Element(""); attr->setAttribute("name", name); element.addChild(attr); } element.selectChildsByAttribute("name", name) .addChild(e.dublicate()); return this; }); } StringValidationBuilder>* withRequiredString(Text name) { return new StringValidationBuilder< ObjectValidationBuilder>( [this, name](XML::Element& e) { if (!element.selectChildsByAttribute("name", name) .exists()) { XML::Element* attr = new XML::Element(""); attr->setAttribute("name", name); element.addChild(attr); } element.selectChildsByAttribute("name", name) .addChild(e.dublicate()); return this; }); } BoolValidationBuilder>* withRequiredBool(Text name) { return new BoolValidationBuilder< ObjectValidationBuilder>( [this, name](XML::Element& e) { if (!element.selectChildsByAttribute("name", name) .exists()) { XML::Element* attr = new XML::Element(""); attr->setAttribute("name", name); element.addChild(attr); } element.selectChildsByAttribute("name", name) .addChild(e.dublicate()); return this; }); } ArrayValidationBuilder>* withRequiredArray(Text name) { return new ArrayValidationBuilder< ObjectValidationBuilder>( [this, name](XML::Element& e) { if (!element.selectChildsByAttribute("name", name) .exists()) { XML::Element* attr = new XML::Element(""); attr->setAttribute("name", name); element.addChild(attr); } element.selectChildsByAttribute("name", name) .addChild(e.dublicate()); return this; }); } ObjectValidationBuilder>* withRequiredObject(Text name) { return new ObjectValidationBuilder< ObjectValidationBuilder>( [this, name](XML::Element& e) { if (!element.selectChildsByAttribute("name", name) .exists()) { XML::Element* attr = new XML::Element(""); attr->setAttribute("name", name); element.addChild(attr); } element.selectChildsByAttribute("name", name) .addChild(e.dublicate()); return this; }); } ObjectValidationBuilder* withRequiredAttribute( Text name, JSONValidator* validator) { if (!element.selectChildsByAttribute("name", name).exists()) { XML::Element* attr = new XML::Element(""); attr->setAttribute("name", name); element.addChild(attr); } element.selectChildsByAttribute("name", name) .addChild(validator->zConstraints()->dublicate()); validator->release(); return this; } ObjectValidationBuilder* withDefault(JSONObject* obj) { element.setAttribute("default", obj->toString()); obj->release(); return this; } ObjectValidationBuilder* withDefaultNull() { element.setAttribute("default", "null"); return this; } ObjectValidationBuilder* whichCanBeNull() { element.setAttribute("nullable", "true"); return this; } ObjectValidationBuilder* whichIsOptional() { element.setAttribute("optional", "true"); return this; } ArrayValidationBuilder* typeOfValuesSpecifiedByAttribute( Text valueName, Text attributeName) { if (!element.selectChildsByAttribute("name", valueName) .exists()) { XML::Element* attr = new XML::Element(""); attr->setAttribute("name", valueName); element.addChild(attr); } element.selectChildsByAttribute("name", valueName) .setAttribute("typeSpecifiedBy", attributeName); return this; } ObjectValidationBuilder* removeInvalidEntries() { element.setAttribute("removeInvalidEntries", "true"); return this; } ObjectValidationBuilder* allowAdditionalAttriutes() { element.setAttribute("allowAdditionalAttributes", "true"); return this; } T* finishObject() { T* result = builder(element); delete this; return result; } }; template class ArrayValidationBuilder { private: XML::Element element; std::function builder; public: ArrayValidationBuilder( std::function builder) : element(""), builder(builder) {} StringValidationBuilder>* addAcceptedStringInArray() { return new StringValidationBuilder< ArrayValidationBuilder>([this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } NumberValidationBuilder>* addAcceptedNumberInArray() { return new NumberValidationBuilder< ArrayValidationBuilder>([this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } BoolValidationBuilder>* addAcceptedBooleanInArray() { return new BoolValidationBuilder>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } ObjectValidationBuilder>* addAcceptedObjectInArray() { return new ObjectValidationBuilder< ArrayValidationBuilder>([this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } ArrayValidationBuilder>* addAcceptedArrayInArray() { return new ArrayValidationBuilder< ArrayValidationBuilder>([this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } ArrayValidationBuilder* addAcceptedTypeInArray( JSONValidator* validator) { element.addChild(validator->zConstraints()->dublicate()); validator->release(); return this; } ArrayValidationBuilder* acceptNullsInArray() { element.setAttribute("nullsEnabled", "true"); return this; } ArrayValidationBuilder* withDefault(JSONArray* array) { element.setAttribute("default", array->toString()); array->release(); return this; } ArrayValidationBuilder* withDefaultNull() { element.setAttribute("default", "null"); return this; } ArrayValidationBuilder* whichCanBeNull() { element.setAttribute("nullable", "true"); return this; } ArrayValidationBuilder* whichIsOptional() { element.setAttribute("optional", "true"); return this; } ArrayValidationBuilder* typeSpecifiedByAttribute(Text name) { element.setAttribute("typeSpecifiedBy", name); return this; } ArrayValidationBuilder* removeInvalidEntries() { element.setAttribute("removeInvalidEntries", "true"); return this; } T* finishArray() { T* result = builder(element); delete this; return result; } }; template class OneOfValidationBuilder { private: XML::Element element; std::function builder; public: OneOfValidationBuilder( std::function builder) : element(""), builder(builder) {} StringValidationBuilder>* addAcceptedStringInArray() { return new StringValidationBuilder< OneOfValidationBuilder>([this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } NumberValidationBuilder>* addAcceptedNumberInArray() { return new NumberValidationBuilder< OneOfValidationBuilder>([this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } BoolValidationBuilder>* addAcceptedBooleanInArray() { return new BoolValidationBuilder>( [this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } ObjectValidationBuilder>* addAcceptedObjectInArray() { return new ObjectValidationBuilder< OneOfValidationBuilder>([this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } ArrayValidationBuilder>* addAcceptedArrayInArray() { return new ArrayValidationBuilder< OneOfValidationBuilder>([this](XML::Element& e) { element.addChild(e.dublicate()); return this; }); } OneOfValidationBuilder* addAcceptedType( JSONValidator* validator) { element.addChild(validator->zConstraints()->dublicate()); validator->release(); return this; } OneOfValidationBuilder* typeSpecifiedByAttribute(Text name) { element.setAttribute("typeSpecifiedBy", name); return this; } T* finishOneOf() { T* result = builder(element); delete this; return result; } }; } // namespace Validator } // namespace JSON } // namespace Framework