UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
JsonSerializerMacros.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreMinimal.h"
16#include "JsonGlobals.h"
17
21#define BEGIN_JSON_SERIALIZER \
22 virtual void Serialize(FJsonSerializerBase& Serializer, bool bFlatObject) override \
23 { \
24 if (!bFlatObject) { Serializer.StartObject(); }
25
26#define END_JSON_SERIALIZER \
27 if (!bFlatObject) { Serializer.EndObject(); } \
28 }
29
30#define JSON_SERIALIZE(JsonName, JsonValue) \
31 Serializer.Serialize(TEXTVIEW(JsonName), JsonValue)
32
33#define JSON_SERIALIZE_NAME(JsonName, JsonValue) \
34 if (Serializer.IsLoading()) \
35 { \
36 FString NameStr; \
37 Serializer.Serialize(TEXTVIEW(JsonName), NameStr); \
38 JsonValue = FName(*NameStr); \
39 } \
40 else \
41 { \
42 FString NameStr = JsonValue.ToString(); \
43 Serializer.Serialize(TEXTVIEW(JsonName), NameStr); \
44 }
45
46#define JSON_SERIALIZE_WITHDEFAULT(JsonName, JsonValue, DefaultJsonValue) \
47 if (Serializer.IsLoading()) \
48 { \
49 if (!Serializer.GetObject()->HasField(TEXTVIEW(JsonName))) \
50 { \
51 JsonValue = DefaultJsonValue; \
52 } \
53 } \
54 Serializer.Serialize(TEXTVIEW(JsonName), JsonValue);
55
56#define JSON_SERIALIZE_OPTIONAL(JsonName, OptionalJsonValue) \
57 if (Serializer.IsLoading()) \
58 { \
59 if (Serializer.GetObject()->HasField(TEXTVIEW(JsonName))) \
60 { \
61 Serializer.Serialize(TEXTVIEW(JsonName), OptionalJsonValue.Emplace()); \
62 } \
63 } \
64 else \
65 { \
66 if (OptionalJsonValue.IsSet()) \
67 { \
68 Serializer.Serialize(TEXTVIEW(JsonName), OptionalJsonValue.GetValue()); \
69 } \
70 }
71
72#define JSON_SERIALIZE_OPTIONAL_MAP(JsonName, JsonMap) \
73 if (Serializer.IsLoading() && !JsonMap.IsSet() && Serializer.GetObject().IsValid() && Serializer.GetObject()->HasTypedField<EJson::Object>(TEXTVIEW(JsonName))) \
74 { \
75 JsonMap.Emplace(); \
76 } \
77 \
78 if (JsonMap.IsSet()) \
79 { \
80 Serializer.SerializeMap(TEXTVIEW(JsonName), JsonMap.GetValue()); \
81 }
82
83#define JSON_SERIALIZE_OPTIONAL_ARRAY(JsonName, JsonArray) \
84 if (Serializer.IsLoading() && !JsonArray.IsSet() && Serializer.GetObject().IsValid() && Serializer.GetObject()->HasTypedField<EJson::Array>(TEXTVIEW(JsonName))) \
85 { \
86 JsonArray.Emplace(); \
87 } \
88 \
89 if (JsonArray.IsSet()) \
90 { \
91 Serializer.SerializeArray(TEXTVIEW(JsonName), JsonArray.GetValue()); \
92 }
93
94#define JSON_SERIALIZE_ARRAY(JsonName, JsonArray) \
95 Serializer.SerializeArray(TEXTVIEW(JsonName), JsonArray)
96
97#define JSON_SERIALIZE_ARRAY_WITHDEFAULT(JsonName, JsonArray, DefaultArray) \
98 if (Serializer.IsLoading()) \
99 { \
100 if (!Serializer.GetObject()->HasField(TEXTVIEW(JsonName))) \
101 { \
102 JsonArray = DefaultArray; \
103 } \
104 } \
105 Serializer.SerializeArray(TEXTVIEW(JsonName), JsonArray);
106
107#define JSON_SERIALIZE_OBJECT_WITHDEFAULT(JsonName, JsonObject, DefaultObject) \
108 if (Serializer.IsLoading()) \
109 { \
110 if (!Serializer.GetObject()->HasField(TEXTVIEW(JsonName))) \
111 { \
112 JsonObject = DefaultObject; \
113 } \
114 } \
115 Serializer.SerializeArray(TEXTVIEW(JsonName), JsonArray);
116
117#define JSON_SERIALIZE_MAP(JsonName, JsonMap) \
118 Serializer.SerializeMap(TEXTVIEW(JsonName), JsonMap)
119
120#define JSON_SERIALIZE_SIMPLECOPY(JsonMap) \
121 Serializer.SerializeSimpleMap(JsonMap)
122
123#define JSON_SERIALIZE_MAP_SAFE(JsonName, JsonMap) \
124 Serializer.SerializeMapSafe(TEXTVIEW(JsonName), JsonMap)
125
126#define JSON_SERIALIZE_RAW_JSON_STRING(JsonName, JsonValue) \
127 if (Serializer.IsLoading()) \
128 { \
129 using CharType = TElementType_T<decltype(JsonValue)>; \
130 if (Serializer.GetObject()->HasTypedField<EJson::Object>(TEXTVIEW(JsonName))) \
131 { \
132 TSharedPtr<FJsonObject> JsonObject = Serializer.GetObject()->GetObjectField(TEXTVIEW(JsonName)); \
133 if (JsonObject.IsValid()) \
134 { \
135 auto Writer = TJsonWriterFactory<CharType, TCondensedJsonPrintPolicy<CharType>>::Create(&JsonValue); \
136 FJsonSerializer::Serialize(JsonObject.ToSharedRef(), Writer); \
137 } \
138 } \
139 else \
140 { \
141 JsonValue = TString<CharType>(); \
142 } \
143 } \
144 else \
145 { \
146 if (!JsonValue.IsEmpty()) \
147 { \
148 Serializer.WriteIdentifierPrefix(TEXTVIEW(JsonName)); \
149 Serializer.WriteRawJSONValue(*JsonValue); \
150 } \
151 }
152
153#define JSON_SERIALIZE_ARRAY_SERIALIZABLE(JsonName, JsonArray, ElementType) \
154 if (Serializer.IsLoading()) \
155 { \
156 if (Serializer.GetObject()->HasTypedField<EJson::Array>(TEXTVIEW(JsonName))) \
157 { \
158 for (auto It = Serializer.GetObject()->GetArrayField(TEXTVIEW(JsonName)).CreateConstIterator(); It; ++It) \
159 { \
160 ElementType& Obj = JsonArray.AddDefaulted_GetRef(); \
161 Obj.FromJson((*It)->AsObject()); \
162 } \
163 } \
164 } \
165 else \
166 { \
167 Serializer.StartArray(TEXTVIEW(JsonName)); \
168 for (auto It = JsonArray.CreateIterator(); It; ++It) \
169 { \
170 It->Serialize(Serializer, false); \
171 } \
172 Serializer.EndArray(); \
173 }
174
175#define JSON_SERIALIZE_ARRAY_SERIALIZABLE_WITHDEFAULT(JsonName, JsonArray, ElementType, DefaultArray) \
176 if (Serializer.IsLoading()) \
177 { \
178 if (Serializer.GetObject()->HasTypedField<EJson::Array>(TEXTVIEW(JsonName))) \
179 { \
180 for (auto It = Serializer.GetObject()->GetArrayField(TEXTVIEW(JsonName)).CreateConstIterator(); It; ++It) \
181 { \
182 ElementType& Obj = JsonArray.AddDefaulted_GetRef(); \
183 Obj.FromJson((*It)->AsObject()); \
184 } \
185 } \
186 else \
187 { \
188 JsonArray = DefaultArray; \
189 } \
190 } \
191 else \
192 { \
193 Serializer.StartArray(TEXTVIEW(JsonName)); \
194 for (auto It = JsonArray.CreateIterator(); It; ++It) \
195 { \
196 It->Serialize(Serializer, false); \
197 } \
198 Serializer.EndArray(); \
199 }
200
201#define JSON_SERIALIZE_OPTIONAL_ARRAY_SERIALIZABLE(JsonName, OptionalJsonArray, ElementType) \
202 if (Serializer.IsLoading()) \
203 { \
204 if (Serializer.GetObject()->HasTypedField<EJson::Array>(TEXTVIEW(JsonName))) \
205 { \
206 TArray<ElementType>& JsonArray = OptionalJsonArray.Emplace(); \
207 for (auto It = Serializer.GetObject()->GetArrayField(TEXTVIEW(JsonName)).CreateConstIterator(); It; ++It) \
208 { \
209 ElementType& Obj = JsonArray.AddDefaulted_GetRef(); \
210 Obj.FromJson((*It)->AsObject()); \
211 } \
212 } \
213 } \
214 else \
215 { \
216 if (OptionalJsonArray.IsSet()) \
217 { \
218 Serializer.StartArray(TEXTVIEW(JsonName)); \
219 for (auto It = OptionalJsonArray->CreateIterator(); It; ++It) \
220 { \
221 It->Serialize(Serializer, false); \
222 } \
223 Serializer.EndArray(); \
224 } \
225 }
226
227#define JSON_SERIALIZE_MAP_SERIALIZABLE(JsonName, JsonMap, ElementType) \
228 if (Serializer.IsLoading()) \
229 { \
230 if (Serializer.GetObject()->HasTypedField<EJson::Object>(TEXTVIEW(JsonName))) \
231 { \
232 TSharedPtr<FJsonObject> JsonObj = Serializer.GetObject()->GetObjectField(TEXTVIEW(JsonName)); \
233 for (auto MapIt = JsonObj->Values.CreateConstIterator(); MapIt; ++MapIt) \
234 { \
235 ElementType NewEntry; \
236 NewEntry.FromJson(MapIt.Value()->AsObject()); \
237 JsonMap.Add(MapIt.Key(), NewEntry); \
238 } \
239 } \
240 } \
241 else \
242 { \
243 Serializer.StartObject(TEXTVIEW(JsonName)); \
244 for (auto It = JsonMap.CreateIterator(); It; ++It) \
245 { \
246 Serializer.StartObject(MakeStringView(It.Key())); \
247 It.Value().Serialize(Serializer, true); \
248 Serializer.EndObject(); \
249 } \
250 Serializer.EndObject(); \
251 }
252
253#define JSON_SERIALIZE_MAP_ARRAY_SERIALIZABLE(JsonName, JsonMap, ElementType) \
254 if (Serializer.IsLoading()) \
255 { \
256 if (Serializer.GetObject()->HasTypedField<EJson::Object>(TEXTVIEW(JsonName))) \
257 { \
258 TSharedPtr<FJsonObject> JsonObj = Serializer.GetObject()->GetObjectField(TEXTVIEW(JsonName)); \
259 for (auto MapIt = JsonObj->Values.CreateConstIterator(); MapIt; ++MapIt) \
260 { \
261 TArray<ElementType> NewEntry; \
262 for (auto ArrayIt : MapIt.Value()->AsArray()) \
263 { \
264 NewEntry.Add_GetRef(ElementType()).FromJson(ArrayIt->AsObject()); \
265 } \
266 JsonMap.Add(MapIt.Key(), NewEntry); \
267 } \
268 } \
269 } \
270 else \
271 { \
272 Serializer.StartObject(TEXTVIEW(JsonName)); \
273 for (auto It = JsonMap.CreateIterator(); It; ++It) \
274 { \
275 Serializer.StartArray(It.Key()); \
276 for (auto ArrayEntry : It.Value()) \
277 { \
278 ArrayEntry.Serialize(Serializer, false); \
279 } \
280 Serializer.EndArray(); \
281 } \
282 Serializer.EndObject(); \
283 }
284
285// Use this to read/write JsonValue with its own keys and values corresponding to its members
286#define JSON_SERIALIZE_MEMBERS_OF(JsonValue) \
287 JsonValue.Serialize(Serializer, /*bIsFlatObject*/true)
288
289#define JSON_SERIALIZE_SERIALIZABLE(JsonName, JsonValue) UE_DEPRECATED_MACRO(5.6, "JSON_SERIALIZE_SERIALIZABLE has been deprecated, use JSON_SERIALIZE_MEMBERS_OF instead") JSON_SERIALIZE_MEMBERS_OF(JsonValue)
290
291// Use this when JsonSerializableObject will be read/write as json object, while JsonName is the key
292#define JSON_SERIALIZE_OBJECT_SERIALIZABLE(JsonName, JsonSerializableObject) \
293 /* Process the JsonName field differently because it is an object */ \
294 if (Serializer.IsLoading()) \
295 { \
296 /* Read in the value from the JsonName field */ \
297 if (Serializer.GetObject()->HasTypedField<EJson::Object>(TEXTVIEW(JsonName))) \
298 { \
299 TSharedPtr<FJsonObject> JsonObj = Serializer.GetObject()->GetObjectField(TEXTVIEW(JsonName)); \
300 if (JsonObj.IsValid()) \
301 { \
302 (JsonSerializableObject).FromJson(JsonObj); \
303 } \
304 } \
305 } \
306 else \
307 { \
308 /* Write the value to the Name field */ \
309 Serializer.StartObject(TEXTVIEW(JsonName)); \
310 (JsonSerializableObject).Serialize(Serializer, true); \
311 Serializer.EndObject(); \
312 }
313
314#define JSON_SERIALIZE_OBJECT_SERIALIZABLE_WITHDEFAULT(JsonName, JsonSerializableObject, JsonSerializableObjectDefault) \
315 /* Process the JsonName field differently because it is an object */ \
316 if (Serializer.IsLoading()) \
317 { \
318 /* Read in the value from the JsonName field */ \
319 if (Serializer.GetObject()->HasTypedField<EJson::Object>(TEXTVIEW(JsonName))) \
320 { \
321 TSharedPtr<FJsonObject> JsonObj = Serializer.GetObject()->GetObjectField(TEXTVIEW(JsonName)); \
322 if (JsonObj.IsValid()) \
323 { \
324 (JsonSerializableObject).FromJson(JsonObj); \
325 } \
326 } \
327 else \
328 { \
329 JsonSerializableObject = JsonSerializableObjectDefault; \
330 } \
331 } \
332 else \
333 { \
334 /* Write the value to the Name field */ \
335 Serializer.StartObject(TEXTVIEW(JsonName)); \
336 (JsonSerializableObject).Serialize(Serializer, true); \
337 Serializer.EndObject(); \
338 }
339
340#define JSON_SERIALIZE_OPTIONAL_OBJECT_SERIALIZABLE(JsonName, JsonSerializableObject) \
341 if (Serializer.IsLoading()) \
342 { \
343 using ObjectType = TRemoveReference<decltype(JsonSerializableObject.GetValue())>::Type; \
344 if (Serializer.GetObject()->HasTypedField<EJson::Object>(TEXTVIEW(JsonName))) \
345 { \
346 TSharedPtr<FJsonObject> JsonObj = Serializer.GetObject()->GetObjectField(TEXTVIEW(JsonName)); \
347 if (JsonObj.IsValid()) \
348 { \
349 JsonSerializableObject = ObjectType{}; \
350 JsonSerializableObject.GetValue().FromJson(JsonObj); \
351 } \
352 } \
353 } \
354 else \
355 { \
356 if (JsonSerializableObject.IsSet()) \
357 { \
358 Serializer.StartObject(TEXTVIEW(JsonName)); \
359 (JsonSerializableObject.GetValue()).Serialize(Serializer, true); \
360 Serializer.EndObject(); \
361 } \
362 }
363
364#define JSON_SERIALIZE_DATETIME_UNIX_TIMESTAMP(JsonName, JsonDateTime) \
365 if (Serializer.IsLoading()) \
366 { \
367 int64 UnixTimestampValue; \
368 Serializer.Serialize(TEXTVIEW(JsonName), UnixTimestampValue); \
369 JsonDateTime = FDateTime::FromUnixTimestamp(UnixTimestampValue); \
370 } \
371 else \
372 { \
373 int64 UnixTimestampValue = JsonDateTime.ToUnixTimestamp(); \
374 Serializer.Serialize(TEXTVIEW(JsonName), UnixTimestampValue); \
375 }
376
377#define JSON_SERIALIZE_DATETIME_UNIX_TIMESTAMP_MILLISECONDS(JsonName, JsonDateTime) \
378if (Serializer.IsLoading()) \
379{ \
380 int64 UnixTimestampValueInMilliseconds; \
381 Serializer.Serialize(TEXTVIEW(JsonName), UnixTimestampValueInMilliseconds); \
382 JsonDateTime = FDateTime::FromUnixTimestamp(UnixTimestampValueInMilliseconds / 1000); \
383} \
384else \
385{ \
386 int64 UnixTimestampValueInMilliseconds = JsonDateTime.ToUnixTimestamp() * 1000; \
387 Serializer.Serialize(TEXTVIEW(JsonName), UnixTimestampValueInMilliseconds); \
388}
389
390#define JSON_SERIALIZE_ENUM(JsonName, JsonEnum) \
391if (Serializer.IsLoading()) \
392{ \
393 FString JsonTextValue; \
394 Serializer.Serialize(TEXTVIEW(JsonName), JsonTextValue); \
395 LexFromString(JsonEnum, *JsonTextValue); \
396} \
397else \
398{ \
399 FString JsonTextValue = LexToString(JsonEnum); \
400 Serializer.Serialize(TEXTVIEW(JsonName), JsonTextValue); \
401}
402
403#define JSON_SERIALIZE_ENUM_ARRAY(JsonName, JsonArray, EnumType) \
404if (Serializer.IsLoading()) \
405{ \
406 if (Serializer.GetObject()->HasTypedField<EJson::Array>(TEXTVIEW(JsonName))) \
407 { \
408 EnumType EnumValue; \
409 for (auto It = Serializer.GetObject()->GetArrayField(TEXTVIEW(JsonName)).CreateConstIterator(); It; ++It) \
410 { \
411 LexFromString(EnumValue, *(*It)->AsString()); \
412 JsonArray.Add(EnumValue); \
413 } \
414 } \
415} \
416else \
417{ \
418 Serializer.StartArray(TEXTVIEW(JsonName)); \
419 for (EnumType& EnumValue : JsonArray) \
420 { \
421 FString JsonTextValue = LexToString(EnumValue); \
422 Serializer.Serialize(TEXTVIEW(JsonName), JsonTextValue); \
423 } \
424 Serializer.EndArray(); \
425}
426
430#define JSON_SERIALIZE_PRIVATE_VARIANT_BEGIN(JsonName, JsonValue) \
431 TSharedPtr<FJsonObject> VariantJsonObj; \
432 FString VariantTypeStr; \
433 if (VariantValue != nullptr) \
434 { \
435 if (Serializer.IsLoading()) \
436 { \
437 if (Serializer.GetObject()->HasTypedField<EJson::Object>(TEXTVIEW(JsonName))) \
438 { \
439 VariantJsonObj = Serializer.GetObject()->GetObjectField(TEXTVIEW(JsonName)); \
440 if (VariantJsonObj.IsValid()) \
441 { \
442 VariantTypeStr = VariantJsonObj->GetStringField(TEXTVIEW("Type")); \
443 const TSharedPtr<FJsonObject>* VariantValueObject = nullptr; \
444 if (VariantJsonObj->TryGetObjectField(TEXTVIEW("Value"), VariantValueObject); VariantValueObject != nullptr) \
445 { \
446 VariantJsonObj = *VariantValueObject; \
447 } \
448 else \
449 { \
450 VariantJsonObj = {}; \
451 } \
452 } \
453 } \
454 } \
455 else \
456 { \
457 Serializer.StartObject(TEXTVIEW(JsonName)); \
458 } \
459 }
460
461#define JSON_SERIALIZE_PRIVATE_VARIANT_END() \
462 if (VariantValue != nullptr) \
463 { \
464 if (!Serializer.IsLoading()) \
465 { \
466 Serializer.EndObject(); \
467 } \
468 }
469
473#define JSON_SERIALIZE_VARIANT_BEGIN(JsonName, JsonValue) \
474 if (true) \
475 { \
476 auto* VariantValue = &JsonValue; \
477 JSON_SERIALIZE_PRIVATE_VARIANT_BEGIN(JsonName, JsonValue)
478
479#define JSON_SERIALIZE_VARIANT_END() \
480 JSON_SERIALIZE_PRIVATE_VARIANT_END() \
481 }
482
486#define JSON_SERIALIZE_OPTIONAL_VARIANT_BEGIN(JsonName, JsonValue) \
487 if (true) \
488 { \
489 if (Serializer.IsLoading()) \
490 { \
491 if (Serializer.GetObject()->HasTypedField<EJson::Object>(TEXTVIEW(JsonName))) \
492 { \
493 JsonValue.Emplace(); \
494 } \
495 } \
496 auto* VariantValue = JsonValue.IsSet() ? &JsonValue.GetValue() : nullptr; \
497 JSON_SERIALIZE_PRIVATE_VARIANT_BEGIN(JsonName, JsonValue)
498
499#define JSON_SERIALIZE_OPTIONAL_VARIANT_END() \
500 JSON_SERIALIZE_PRIVATE_VARIANT_END() \
501 }
502
506#define JSON_SERIALIZE_VARIANT_IFTYPE_SERIALIZABLE(TypeName, Type) \
507 if (VariantValue != nullptr) \
508 { \
509 if (Serializer.IsLoading()) \
510 { \
511 if (VariantJsonObj.IsValid() && VariantTypeStr == TEXTVIEW(TypeName)) \
512 { \
513 VariantValue->Emplace<Type>(); \
514 VariantValue->Get<Type>().FromJson(VariantJsonObj); \
515 } \
516 } \
517 else \
518 { \
519 /* created Value + Type */ \
520 if (VariantValue->IsType<Type>()) \
521 { \
522 VariantTypeStr = TEXTVIEW(TypeName); \
523 Serializer.Serialize(TEXTVIEW("Type"), VariantTypeStr); \
524 Serializer.StartObject(TEXTVIEW("Value")); \
525 VariantValue->Get<Type>().Serialize(Serializer, true); \
526 Serializer.EndObject(); \
527 } \
528 } \
529 }