#include "WingJson.h" #include "WingTypes.h" #include "WingServer.h" #include "UObject/UnrealType.h" #include "UObject/EnumProperty.h" #include "Dom/JsonValue.h" bool WingJson::PopulateFromJson(FWingProperty& P, const FJsonObject* Json, bool AllOptional) { FString JsonKey = P.Prop->GetName(); bool bOptional = AllOptional || P.Prop->HasMetaData(TEXT("Optional")); if (!Json->HasField(JsonKey)) { if (!bOptional) { UWingServer::Printf(TEXT("ERROR: Missing required parameter '%s'\n"), *JsonKey); return false; } return true; } void* ValuePtr = P.Prop->ContainerPtrToValuePtr(P.Container); // Special handling for FWingJsonObject and FWingJsonArray if (FStructProperty* StructProp = CastField(P.Prop)) { if (StructProp->Struct == FWingJsonObject::StaticStruct()) { if (!Json->HasTypedField(JsonKey)) { UWingServer::Printf(TEXT("ERROR: '%s' must be an object\n"), *JsonKey); return false; } static_cast(ValuePtr)->Json = Json->GetObjectField(JsonKey); return true; } if (StructProp->Struct == FWingJsonArray::StaticStruct()) { if (!Json->HasTypedField(JsonKey)) { UWingServer::Printf(TEXT("ERROR: '%s' must be an array\n"), *JsonKey); return false; } static_cast(ValuePtr)->Array = Json->GetArrayField(JsonKey); return true; } } // Handle based on JSON value type. TSharedPtr JsonValue = Json->TryGetField(JsonKey); if (JsonValue->Type == EJson::Number) { double D = JsonValue->AsNumber(); if (FIntProperty* IntProp = CastField(P.Prop)) { IntProp->SetPropertyValue(ValuePtr, (int32)D); return true; } if (FFloatProperty* FloatProp = CastField(P.Prop)) { FloatProp->SetPropertyValue(ValuePtr, (float)D); return true; } if (FDoubleProperty* DoubleProp = CastField(P.Prop)) { DoubleProp->SetPropertyValue(ValuePtr, D); return true; } if (FByteProperty* ByteProp = CastField(P.Prop)) { ByteProp->SetPropertyValue(ValuePtr, (uint8)D); return true; } UWingServer::Printf(TEXT("ERROR: '%s' received a number but expects %s\n"), *JsonKey, *P.Prop->GetCPPType()); return false; } if (JsonValue->Type == EJson::Boolean) { if (FBoolProperty* BoolProp = CastField(P.Prop)) { BoolProp->SetPropertyValue(ValuePtr, JsonValue->AsBool()); return true; } UWingServer::Printf(TEXT("ERROR: '%s' received a boolean but expects %s\n"), *JsonKey, *P.Prop->GetCPPType()); return false; } if (JsonValue->Type == EJson::String) { return P.SetText(JsonValue->AsString()); } UWingServer::Printf(TEXT("ERROR: '%s' must be a string, number, or boolean\n"), *JsonKey); return false; } bool WingJson::PopulateFromJson( TArray& Props, const FJsonObject* Json, bool AllOptional) { bool Ok = true; // Build a set of known property names for the unknown-field check. TSet KnownKeys; for (const FWingProperty& P : Props) KnownKeys.Add(P.Prop->GetName()); // Check for unknown fields in the JSON for (const auto& KV : Json->Values) { if (!KnownKeys.Contains(KV.Key)) { UWingServer::Printf(TEXT("ERROR: Unknown parameter '%s'\n"), *KV.Key); Ok = false; } } // Populate each property from JSON for (FWingProperty& P : Props) { if (!PopulateFromJson(P, Json, AllOptional)) Ok = false; } return Ok; } bool WingJson::PopulateFromJson( UStruct* StructType, void* Container, const FJsonObject* Json) { TArray Props = FWingProperty::GetAll(StructType, Container, (EPropertyFlags)0); return PopulateFromJson(Props, Json); } bool WingJson::PopulateFromJson( UStruct* StructType, void* Container, const TSharedPtr& JsonValue) { if (!JsonValue.IsValid() || (JsonValue->Type != EJson::Object)) { UWingServer::Print(TEXT("ERROR: Expected a JSON object\n")); return false; } return PopulateFromJson(StructType, Container, JsonValue->AsObject().Get()); }