Add json serialization utils for objects to save/load from raw bytes

This commit is contained in:
Wojtek Figat
2022-01-02 01:29:31 +01:00
parent 32a73727b0
commit 0f9f3905ed
6 changed files with 170 additions and 4 deletions

View File

@@ -15,10 +15,7 @@ using Newtonsoft.Json.Serialization;
namespace FlaxEngine.Json
{
/// <summary>
/// Objects serialization tool (json format).
/// </summary>
public static class JsonSerializer
partial class JsonSerializer
{
internal class SerializerCache
{

View File

@@ -0,0 +1,30 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Core/ISerializable.h"
#include "Engine/Core/Types/Span.h"
#include "Engine/Core/Collections/Array.h"
/// <summary>
/// Objects serialization tool (json format).
/// </summary>
API_CLASS(Static, Namespace="FlaxEngine.Json") class FLAXENGINE_API JsonSerializer
{
DECLARE_SCRIPTING_TYPE_MINIMAL(JsonSerializer);
/// <summary>
/// Performs object Json serialization to the raw bytes.
/// </summary>
/// <param name="obj">The object to serialize (can be null).</param>
/// <returns>The output data.</returns>
API_FUNCTION() static Array<byte> SaveToBytes(ISerializable* obj);
/// <summary>
/// Performs object Json deserialization from the raw bytes.
/// </summary>
/// <param name="obj">The object to deserialize (can be null).</param>
/// <param name="data">The source data to read from.</param>
/// <param name="engineBuild">The engine build number of the saved data. Used to resolve old object formats when loading deprecated data.</param>
API_FUNCTION() static void LoadFromBytes(ISerializable* obj, const Span<byte>& data, int32 engineBuild);
};

View File

@@ -8,6 +8,7 @@
struct CommonValue;
struct Variant;
struct VariantType;
class ISerializable;
/// <summary>
/// Base class for all data read streams
@@ -204,6 +205,13 @@ public:
ReadBytes(data->Get(), size * sizeof(T));
}
/// <summary>
/// Deserializes object from Json by reading it as a raw data (ver+length+bytes).
/// </summary>
/// <remarks>Reads version number, data length and actual data bytes from the stream.</remarks>
/// <param name="obj">The object to deserialize.</param>
void ReadJson(ISerializable* obj);
public:
// [Stream]

View File

@@ -3,11 +3,16 @@
#include "ReadStream.h"
#include "WriteStream.h"
#include "JsonWriters.h"
#include "JsonSerializer.h"
#include "MemoryReadStream.h"
#include "Engine/Core/Types/CommonValue.h"
#include "Engine/Core/Types/Variant.h"
#include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Content/Asset.h"
#include "Engine/Core/Cache.h"
#include "Engine/Debug/DebugLog.h"
#include "Engine/Debug/Exceptions/JsonParseException.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Scripting/ManagedSerialization.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/ScriptingObject.h"
@@ -489,6 +494,29 @@ void ReadStream::ReadVariant(Variant* data)
}
}
void ReadStream::ReadJson(ISerializable* obj)
{
int32 engineBuild, size;
ReadInt32(&engineBuild);
ReadInt32(&size);
if (obj)
{
if (const auto memoryStream = dynamic_cast<MemoryReadStream*>(this))
{
JsonSerializer::LoadFromBytes(obj, Span<byte>((byte*)memoryStream->Read(size), size), engineBuild);
}
else
{
void* data = Allocator::Allocate(size);
ReadBytes(data, size);
JsonSerializer::LoadFromBytes(obj, Span<byte>((byte*)data, size), engineBuild);
Allocator::Free(data);
}
}
else
SetPosition(GetPosition() + size);
}
void WriteStream::WriteText(const StringView& text)
{
for (int32 i = 0; i < text.Length(); i++)
@@ -734,3 +762,57 @@ void WriteStream::WriteVariant(const Variant& data)
CRASH;
}
}
void WriteStream::WriteJson(ISerializable* obj, const void* otherObj)
{
WriteInt32(FLAXENGINE_VERSION_BUILD);
if (obj)
{
rapidjson_flax::StringBuffer buffer;
CompactJsonWriter writer(buffer);
writer.StartObject();
obj->Serialize(writer, otherObj);
writer.EndObject();
WriteInt32((int32)buffer.GetSize());
WriteBytes((byte*)buffer.GetString(), (int32)buffer.GetSize());
}
else
WriteInt32(0);
}
Array<byte> JsonSerializer::SaveToBytes(ISerializable* obj)
{
Array<byte> result;
if (obj)
{
rapidjson_flax::StringBuffer buffer;
CompactJsonWriter writer(buffer);
writer.StartObject();
obj->Serialize(writer, nullptr);
writer.EndObject();
result.Set((byte*)buffer.GetString(), (int32)buffer.GetSize());
}
return result;
}
void JsonSerializer::LoadFromBytes(ISerializable* obj, const Span<byte>& data, int32 engineBuild)
{
if (!obj || data.Length() == 0)
return;
ISerializable::SerializeDocument document;
{
PROFILE_CPU_NAMED("Json.Parse");
document.Parse((const char*)data.Get(), data.Length());
}
if (document.HasParseError())
{
Log::JsonParseException(document.GetParseError(), document.GetErrorOffset());
return;
}
auto modifier = Cache::ISerializeModifier.Get();
modifier->EngineBuild = engineBuild;
obj->Deserialize(document, modifier.Value);
}

View File

@@ -8,6 +8,7 @@
struct CommonValue;
struct Variant;
struct VariantType;
class ISerializable;
/// <summary>
/// Base class for all data write streams
@@ -240,6 +241,14 @@ public:
WriteBytes(data.Get(), size * sizeof(T));
}
/// <summary>
/// Serializes object to Json and writes it as a raw data (ver+length+bytes).
/// </summary>
/// <remarks>Writes version number, data length and actual data bytes to the stream.</remarks>
/// <param name="obj">The object to serialize.</param>
/// <param name="otherObj">The instance of the object to compare with and serialize only the modified properties. If null, then serialize all properties.</param>
void WriteJson(ISerializable* obj, const void* otherObj = nullptr);
public:
// [Stream]