#pragma once #include #include #include #include #include #include #include class TypeRegistry; #define JSONObjectValidationBuilder \ Framework::Validator::ObjectValidationBuilder< \ Framework::Validator::DataValidator> template class SimpleTypeFactory : public Framework::ReferenceCounter { public: SimpleTypeFactory() : ReferenceCounter() {}; virtual T fromJson(Framework::JSON::JSONValue* zJson) const = 0; virtual Framework::JSON::JSONValue* toJson(T value) const = 0; virtual Framework::Validator::DataValidator* getValidator() const = 0; }; /* * Used to convert an object of type T to a JSONValue and vice versa. * Can be registered at the TypeRegistry to be used by the JSON system */ template class ObjectTypeFactory : public SimpleTypeFactory { public: ObjectTypeFactory() : SimpleTypeFactory() {}; T* fromJson(Framework::JSON::JSONValue* zJson) const final override { return fromJson(zJson->asObject()); } Framework::JSON::JSONValue* toJson(T* value) const final override { return toJsonObject(value); } virtual Framework::Validator::DataValidator* getValidator() const override { return addToValidator( Framework::Validator::DataValidator::buildForObject()) ->finishObject(); }; virtual JSONObjectValidationBuilder* addToValidator( JSONObjectValidationBuilder* builder) const = 0; protected: virtual T* fromJson(Framework::JSON::JSONObject* zJson) const = 0; virtual Framework::JSON::JSONObject* toJsonObject(T* zObject) const = 0; }; /* * Used to convert an object of type S witch inherits from type T to a * JSONValue and vice versa. Can be registered at the TypeRegistry to be * used by the JSON */ template::value>> class SubTypeFactory : public ObjectTypeFactory { public: SubTypeFactory() : ObjectTypeFactory() {}; virtual Framework::Validator::DataValidator* getValidator() const final override { Framework::Text referenceId = "_type_"; referenceId.append() << typeid(T).name() << "_" << getTypeToken(); return this ->addToValidator( Framework::Validator::DataValidator::buildForObject() ->withRequiredString("type") ->withExactMatch(getTypeToken()) ->finishString() ->setReferenceId(referenceId)) ->finishObject(); }; virtual const char* getTypeToken() const = 0; virtual const char* getTypeName() const { return typeid(S).name(); } }; template class SubTypeFactoryRef : public Framework::ReferenceCounter { private: std::function typetokenFunc; std::function fromJsonFunc; std::function toJsonFunc; std::function getValidatorFunc; Framework::ReferenceCounter* factory; public: SubTypeFactoryRef(std::function typetokenFunc, std::function fromJsonFunc, std::function toJsonFunc, std::function getValidatorFunc, Framework::ReferenceCounter* factory) : ReferenceCounter(), typetokenFunc(typetokenFunc), fromJsonFunc(fromJsonFunc), toJsonFunc(toJsonFunc), getValidatorFunc(getValidatorFunc), factory(factory) {} ~SubTypeFactoryRef() { factory->release(); } T* fromJson(Framework::JSON::JSONValue* zJson) const { return fromJsonFunc(zJson); } Framework::JSON::JSONValue* toJson(T* zObject) const { return toJsonFunc(zObject); } Framework::Validator::DataValidator* getValidator() const { return getValidatorFunc(); } const char* getTypeToken() const { return typetokenFunc(); } }; template class PolymorphTypeFactory : public ObjectTypeFactory { private: Framework::RCArray> factories; Framework::RCArray typeNames; static thread_local bool insideGetValidator; public: PolymorphTypeFactory() : ObjectTypeFactory() {} T* fromJson(Framework::JSON::JSONObject* zJson) const override { for (SubTypeFactoryRef* factory : factories) { if (zJson->zValue("type")->asString()->getString().istGleich( factory->getTypeToken())) { return factory->fromJson(zJson); } } Framework::Logging::error() << "No Sub Type Factory for typetoken " << zJson->zValue("type")->asString()->getString() << " of type " << typeid(T).name() << " was found."; return 0; } Framework::JSON::JSONObject* toJsonObject(T* zObject) const override { auto name = typeNames.begin(); for (SubTypeFactoryRef* factory : factories) { if (name->istGleich(typeid(*zObject).name())) { Framework::JSON::JSONObject* result = factory->toJson(zObject)->asObject(); result->addValue("type", new Framework::JSON::JSONString(factory->getTypeToken())); return result; } name++; } Framework::Logging::error() << "No Sub Type Factory for subtype " << typeid(*zObject).name() << " of type " << typeid(T).name() << " was found."; return new Framework::JSON::JSONObject(); } JSONObjectValidationBuilder* addToValidator( JSONObjectValidationBuilder* builder) const override { Framework::Logging::error() << "Can not add polymorph json validator to an object " "validation builder"; throw "Can not add polymorph json " "validator to an object " "validation builder"; } Framework::Validator::DataValidator* getValidator() const override { Framework::Validator::DataValidator* result; if (!insideGetValidator) { insideGetValidator = true; auto validator = Framework::Validator::DataValidator::buildForOneOf() ->typeSpecifiedByAttribute("type"); for (SubTypeFactoryRef* factory : factories) { validator = validator->addAcceptedType(factory->getValidator()); } result = validator->finishOneOf(); insideGetValidator = false; } else { auto validator = Framework::Validator::DataValidator::buildForOneOf() ->typeSpecifiedByAttribute("type"); for (SubTypeFactoryRef* factory : factories) { validator = validator->addAcceptedType( Framework::Validator::DataValidator::buildForReference( ((Framework::Text("_type_") += typeid(T).name()) += "_") += factory->getTypeToken())); } result = validator->finishOneOf(); } return result; } template::value>> void addFactory(SubTypeFactory* factory) { factories.add(new SubTypeFactoryRef( [factory]() { return factory->getTypeToken(); }, [factory](Framework::JSON::JSONValue* zJson) { S* value = factory->fromJson(zJson); if (value) { return dynamic_cast(value); } return (T*)0; }, [factory](T* zObject) { return factory->toJson(dynamic_cast(zObject)); }, [factory]() { return factory->getValidator(); }, dynamic_cast(factory))); typeNames.add(new Framework::Text(factory->getTypeName())); } }; template thread_local bool PolymorphTypeFactory::insideGetValidator = false; class TypeFatoryRef : public Framework::ReferenceCounter { private: std::function fromJsonFunc; std::function toJsonFunc; std::function getValidatorFunc; Framework::ReferenceCounter* factory; public: TypeFatoryRef( std::function fromJsonFunc, std::function toJsonFunc, std::function getValidatorFunc, Framework::ReferenceCounter* factory) : ReferenceCounter(), fromJsonFunc(fromJsonFunc), toJsonFunc(toJsonFunc), getValidatorFunc(getValidatorFunc), factory(factory) {} ~TypeFatoryRef() { factory->release(); } void* fromJson(Framework::JSON::JSONValue* zJson) const { return fromJsonFunc(zJson); } Framework::JSON::JSONValue* toJson(void* zObject) const { return toJsonFunc(zObject); } Framework::Validator::DataValidator* getValidator() const { return getValidatorFunc(); } Framework::ReferenceCounter* zFactory() const { return factory; } }; class TypeRegistry : public Framework::ReferenceCounter { private: Framework::RCTrie parsableTypes; Framework::RCArray parsableTypeNames; public: TypeRegistry(); template::value>> void registerSubType(SubTypeFactory* factory) { Framework::Text typeId = typeid(T).name(); TypeFatoryRef* typeFactoryRef = parsableTypes.z(typeId, typeId.getLength()); if (!typeFactoryRef) { PolymorphTypeFactory* polymorphFactory = new PolymorphTypeFactory(); registerType(polymorphFactory); typeFactoryRef = parsableTypes.z(typeId, typeId.getLength()); parsableTypeNames.add(new Framework::Text(typeId)); } PolymorphTypeFactory* polymorphFactory = dynamic_cast*>( typeFactoryRef->zFactory()); if (!polymorphFactory) { Framework::Logging::error() << Framework::Text("Type not registered as Polymorphic type: ") + typeId; throw Framework::Text("Type not registered as Polymorphic type: ") + typeId; } polymorphFactory->addFactory(factory); } template void registerType(ObjectTypeFactory* factory) { registerType(typeid(T).name(), factory); } template void registerType(Framework::Text typeId, SimpleTypeFactory* factory) { TypeFatoryRef* typeFactoryRef = parsableTypes.z(typeId, typeId.getLength()); if (typeFactoryRef) { Framework::Logging::error() << Framework::Text("Type already registered: ") + typeId; throw Framework::Text("Type already registered: ") + typeId; } typeFactoryRef = new TypeFatoryRef( [factory](Framework::JSON::JSONValue* zJson) { return (void*)factory->fromJson(zJson); }, [factory](void* zObject) { return factory->toJson((T)zObject); }, [factory]() { return factory->getValidator(); }, factory); parsableTypes.set(typeId, typeId.getLength(), typeFactoryRef); parsableTypeNames.add(new Framework::Text(typeId)); } template T fromJson(Framework::Text typeId, Framework::JSON::JSONValue* zJson) const { TypeFatoryRef* typeFactoryRef = parsableTypes.z(typeId, typeId.getLength()); if (!typeFactoryRef) { Framework::Logging::error() << Framework::Text("Type not registered: ") + typeId; throw Framework::Text("Type not registered: ") + typeId; } return (T)(typeFactoryRef->fromJson(zJson)); } template T* fromJson(Framework::JSON::JSONValue* zJson) const { return fromJson(typeid(T).name(), zJson); } template Framework::JSON::JSONValue* toJson(T* zObject) const { return toJson(typeid(T).name(), zObject); } template Framework::JSON::JSONValue* toJson(Framework::Text typeId, T zObject) const { TypeFatoryRef* typeFactoryRef = parsableTypes.z(typeId, typeId.getLength()); if (!typeFactoryRef) { Framework::Logging::error() << Framework::Text("Type not registered: ") + typeId; throw Framework::Text("Type not registered: ") + typeId; } return typeFactoryRef->toJson(zObject); } template Framework::Validator::DataValidator* getValidator() const { return getValidator(typeid(T).name()); } template Framework::Validator::DataValidator* getValidator( Framework::Text typeId) const { TypeFatoryRef* typeFactoryRef = parsableTypes.z(typeId, typeId.getLength()); if (!typeFactoryRef) { Framework::Logging::error() << Framework::Text("Type not registered: ") + typeId; throw Framework::Text("Type not registered: ") + typeId; } return typeFactoryRef->getValidator(); } template Framework::JSON::JSONValue* getValidParts( Framework::JSON::JSONValue* zJson) const { Framework::RCArray invalidParts; Framework::Validator::DataValidator* validator = getValidator(); Framework::JSON::JSONValue* result = validator->getValidParts(zJson, &invalidParts); for (Framework::Validator::ValidationResult* invalidPart : invalidParts) { Framework::Logging::error() << invalidPart->getInvalidInfo(); } return result; } void writeSyntaxInfo(Framework::Text folderPath) const; };