mirror of https://github.com/Squidex/squidex.git
Browse Source
* Started conversion. * Made progress. * More fixes. * Fix tests * Fix null writing. * More fixes * Fix rule formatting.pull/908/head
committed by
GitHub
190 changed files with 2819 additions and 2088 deletions
@ -1,105 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using MongoDB.Bson; |
|
||||
using MongoDB.Bson.IO; |
|
||||
using NewtonsoftJsonReader = Newtonsoft.Json.JsonReader; |
|
||||
using NewtonsoftJsonToken = Newtonsoft.Json.JsonToken; |
|
||||
|
|
||||
namespace Squidex.Infrastructure.MongoDb |
|
||||
{ |
|
||||
public sealed class BsonJsonReader : NewtonsoftJsonReader |
|
||||
{ |
|
||||
private readonly IBsonReader bsonReader; |
|
||||
|
|
||||
public BsonJsonReader(IBsonReader bsonReader) |
|
||||
{ |
|
||||
Guard.NotNull(bsonReader); |
|
||||
|
|
||||
this.bsonReader = bsonReader; |
|
||||
} |
|
||||
|
|
||||
public override bool Read() |
|
||||
{ |
|
||||
if (bsonReader.State is BsonReaderState.Initial or BsonReaderState.ScopeDocument or BsonReaderState.Type) |
|
||||
{ |
|
||||
bsonReader.ReadBsonType(); |
|
||||
} |
|
||||
|
|
||||
if (bsonReader.State == BsonReaderState.Name) |
|
||||
{ |
|
||||
SetToken(NewtonsoftJsonToken.PropertyName, bsonReader.ReadName().UnescapeBson()); |
|
||||
} |
|
||||
else if (bsonReader.State == BsonReaderState.Value) |
|
||||
{ |
|
||||
switch (bsonReader.CurrentBsonType) |
|
||||
{ |
|
||||
case BsonType.Document: |
|
||||
SetToken(NewtonsoftJsonToken.StartObject); |
|
||||
bsonReader.ReadStartDocument(); |
|
||||
break; |
|
||||
case BsonType.Array: |
|
||||
SetToken(NewtonsoftJsonToken.StartArray); |
|
||||
bsonReader.ReadStartArray(); |
|
||||
break; |
|
||||
case BsonType.Undefined: |
|
||||
SetToken(NewtonsoftJsonToken.Undefined); |
|
||||
bsonReader.ReadUndefined(); |
|
||||
break; |
|
||||
case BsonType.Null: |
|
||||
SetToken(NewtonsoftJsonToken.Null); |
|
||||
bsonReader.ReadNull(); |
|
||||
break; |
|
||||
case BsonType.String: |
|
||||
SetToken(NewtonsoftJsonToken.String, bsonReader.ReadString()); |
|
||||
break; |
|
||||
case BsonType.Binary: |
|
||||
SetToken(NewtonsoftJsonToken.Bytes, bsonReader.ReadBinaryData().Bytes); |
|
||||
break; |
|
||||
case BsonType.Boolean: |
|
||||
SetToken(NewtonsoftJsonToken.Boolean, bsonReader.ReadBoolean()); |
|
||||
break; |
|
||||
case BsonType.DateTime: |
|
||||
SetToken(NewtonsoftJsonToken.Date, bsonReader.ReadDateTime()); |
|
||||
break; |
|
||||
case BsonType.Int32: |
|
||||
SetToken(NewtonsoftJsonToken.Integer, bsonReader.ReadInt32()); |
|
||||
break; |
|
||||
case BsonType.Int64: |
|
||||
SetToken(NewtonsoftJsonToken.Integer, bsonReader.ReadInt64()); |
|
||||
break; |
|
||||
case BsonType.Double: |
|
||||
SetToken(NewtonsoftJsonToken.Float, bsonReader.ReadDouble()); |
|
||||
break; |
|
||||
case BsonType.Decimal128: |
|
||||
SetToken(NewtonsoftJsonToken.Float, Decimal128.ToDouble(bsonReader.ReadDecimal128())); |
|
||||
break; |
|
||||
default: |
|
||||
ThrowHelper.NotSupportedException(); |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
else if (bsonReader.State == BsonReaderState.EndOfDocument) |
|
||||
{ |
|
||||
SetToken(NewtonsoftJsonToken.EndObject); |
|
||||
bsonReader.ReadEndDocument(); |
|
||||
} |
|
||||
else if (bsonReader.State == BsonReaderState.EndOfArray) |
|
||||
{ |
|
||||
SetToken(NewtonsoftJsonToken.EndArray); |
|
||||
bsonReader.ReadEndArray(); |
|
||||
} |
|
||||
|
|
||||
if (bsonReader.State == BsonReaderState.Initial) |
|
||||
{ |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
return !bsonReader.IsAtEndOfFile(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,91 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using MongoDB.Bson; |
||||
|
using MongoDB.Bson.Serialization; |
||||
|
using MongoDB.Bson.Serialization.Serializers; |
||||
|
using Squidex.Infrastructure.Json.Objects; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.MongoDb |
||||
|
{ |
||||
|
public sealed class BsonJsonValueSerializer : SerializerBase<JsonValue> |
||||
|
{ |
||||
|
public static void Register() |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
BsonSerializer.RegisterSerializer(new BsonJsonValueSerializer()); |
||||
|
} |
||||
|
catch (BsonSerializationException) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override JsonValue Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) |
||||
|
{ |
||||
|
var reader = context.Reader; |
||||
|
|
||||
|
switch (reader.CurrentBsonType) |
||||
|
{ |
||||
|
case BsonType.Undefined: |
||||
|
reader.ReadUndefined(); |
||||
|
return JsonValue.Null; |
||||
|
case BsonType.Null: |
||||
|
reader.ReadNull(); |
||||
|
return JsonValue.Null; |
||||
|
case BsonType.Boolean: |
||||
|
return reader.ReadBoolean(); |
||||
|
case BsonType.Double: |
||||
|
return reader.ReadDouble(); |
||||
|
case BsonType.Int32: |
||||
|
return reader.ReadInt32(); |
||||
|
case BsonType.Int64: |
||||
|
return reader.ReadInt64(); |
||||
|
case BsonType.String: |
||||
|
return reader.ReadString(); |
||||
|
case BsonType.Array: |
||||
|
return BsonSerializer.Deserialize<JsonArray>(reader); |
||||
|
case BsonType.Document: |
||||
|
return BsonSerializer.Deserialize<JsonObject>(reader); |
||||
|
default: |
||||
|
ThrowHelper.NotSupportedException("Unsupported Representation."); |
||||
|
return default!; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, JsonValue value) |
||||
|
{ |
||||
|
var writer = context.Writer; |
||||
|
|
||||
|
switch (value.Value) |
||||
|
{ |
||||
|
case null: |
||||
|
writer.WriteNull(); |
||||
|
break; |
||||
|
case bool b: |
||||
|
writer.WriteBoolean(b); |
||||
|
break; |
||||
|
case string s: |
||||
|
writer.WriteString(s); |
||||
|
break; |
||||
|
case double n: |
||||
|
writer.WriteDouble(n); |
||||
|
break; |
||||
|
case JsonArray a: |
||||
|
BsonSerializer.Serialize(writer, a); |
||||
|
break; |
||||
|
case JsonObject o: |
||||
|
BsonSerializer.Serialize(writer, o); |
||||
|
break; |
||||
|
default: |
||||
|
ThrowHelper.NotSupportedException(); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,190 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using MongoDB.Bson.IO; |
|
||||
using NewtonsoftJsonWriter = Newtonsoft.Json.JsonWriter; |
|
||||
|
|
||||
namespace Squidex.Infrastructure.MongoDb |
|
||||
{ |
|
||||
public sealed class BsonJsonWriter : NewtonsoftJsonWriter |
|
||||
{ |
|
||||
private readonly IBsonWriter bsonWriter; |
|
||||
|
|
||||
public BsonJsonWriter(IBsonWriter bsonWriter) |
|
||||
{ |
|
||||
Guard.NotNull(bsonWriter); |
|
||||
|
|
||||
this.bsonWriter = bsonWriter; |
|
||||
} |
|
||||
|
|
||||
public override void WritePropertyName(string name) |
|
||||
{ |
|
||||
bsonWriter.WriteName(name.EscapeJson()); |
|
||||
} |
|
||||
|
|
||||
public override void WritePropertyName(string name, bool escape) |
|
||||
{ |
|
||||
bsonWriter.WriteName(name.EscapeJson()); |
|
||||
} |
|
||||
|
|
||||
public override void WriteStartArray() |
|
||||
{ |
|
||||
bsonWriter.WriteStartArray(); |
|
||||
} |
|
||||
|
|
||||
public override void WriteEndArray() |
|
||||
{ |
|
||||
bsonWriter.WriteEndArray(); |
|
||||
} |
|
||||
|
|
||||
public override void WriteStartObject() |
|
||||
{ |
|
||||
bsonWriter.WriteStartDocument(); |
|
||||
} |
|
||||
|
|
||||
public override void WriteEndObject() |
|
||||
{ |
|
||||
bsonWriter.WriteEndDocument(); |
|
||||
} |
|
||||
|
|
||||
public override void WriteNull() |
|
||||
{ |
|
||||
bsonWriter.WriteNull(); |
|
||||
} |
|
||||
|
|
||||
public override void WriteUndefined() |
|
||||
{ |
|
||||
bsonWriter.WriteUndefined(); |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(string? value) |
|
||||
{ |
|
||||
if (value == null) |
|
||||
{ |
|
||||
bsonWriter.WriteNull(); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
bsonWriter.WriteString(value); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(int value) |
|
||||
{ |
|
||||
bsonWriter.WriteInt32(value); |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(uint value) |
|
||||
{ |
|
||||
bsonWriter.WriteInt32((int)value); |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(long value) |
|
||||
{ |
|
||||
bsonWriter.WriteInt64(value); |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(ulong value) |
|
||||
{ |
|
||||
bsonWriter.WriteInt64((long)value); |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(float value) |
|
||||
{ |
|
||||
bsonWriter.WriteDouble(value); |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(double value) |
|
||||
{ |
|
||||
bsonWriter.WriteDouble(value); |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(bool value) |
|
||||
{ |
|
||||
bsonWriter.WriteBoolean(value); |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(short value) |
|
||||
{ |
|
||||
bsonWriter.WriteInt32(value); |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(ushort value) |
|
||||
{ |
|
||||
bsonWriter.WriteInt32(value); |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(char value) |
|
||||
{ |
|
||||
bsonWriter.WriteInt32(value); |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(byte value) |
|
||||
{ |
|
||||
bsonWriter.WriteInt32(value); |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(sbyte value) |
|
||||
{ |
|
||||
bsonWriter.WriteInt32(value); |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(decimal value) |
|
||||
{ |
|
||||
bsonWriter.WriteDecimal128(value); |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(DateTime value) |
|
||||
{ |
|
||||
bsonWriter.WriteString(value.ToIso8601()); |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(DateTimeOffset value) |
|
||||
{ |
|
||||
bsonWriter.WriteString(value.UtcDateTime.ToIso8601()); |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(byte[]? value) |
|
||||
{ |
|
||||
if (value == null) |
|
||||
{ |
|
||||
bsonWriter.WriteNull(); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
bsonWriter.WriteBytes(value); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(Uri? value) |
|
||||
{ |
|
||||
if (value == null) |
|
||||
{ |
|
||||
bsonWriter.WriteNull(); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
bsonWriter.WriteString(value.ToString()); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(TimeSpan value) |
|
||||
{ |
|
||||
bsonWriter.WriteString(value.ToString()); |
|
||||
} |
|
||||
|
|
||||
public override void WriteValue(Guid value) |
|
||||
{ |
|
||||
bsonWriter.WriteString(value.ToString()); |
|
||||
} |
|
||||
|
|
||||
public override void Flush() |
|
||||
{ |
|
||||
bsonWriter.Flush(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,31 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System.Linq.Expressions; |
|
||||
using MongoDB.Driver; |
|
||||
|
|
||||
namespace Squidex.Infrastructure.MongoDb |
|
||||
{ |
|
||||
public sealed class FieldDefinitionBuilder<T> |
|
||||
{ |
|
||||
public static readonly FieldDefinitionBuilder<T> Instance = new FieldDefinitionBuilder<T>(); |
|
||||
|
|
||||
private FieldDefinitionBuilder() |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
public FieldDefinition<T, TResult> Build<TResult>(Expression<Func<T, TResult>> expression) |
|
||||
{ |
|
||||
return new ExpressionFieldDefinition<T, TResult>(expression); |
|
||||
} |
|
||||
|
|
||||
public FieldDefinition<T, TResult> Build<TResult>(string name) |
|
||||
{ |
|
||||
return new StringFieldDefinition<T, TResult>(name); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,98 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using Newtonsoft.Json; |
|
||||
using Newtonsoft.Json.Serialization; |
|
||||
|
|
||||
namespace Squidex.Infrastructure.Json.Newtonsoft |
|
||||
{ |
|
||||
public sealed class ConverterContractResolver : CamelCasePropertyNamesContractResolver |
|
||||
{ |
|
||||
private readonly JsonConverter[] converters; |
|
||||
private readonly object lockObject = new object(); |
|
||||
private Dictionary<Type, JsonConverter?> converterCache = new Dictionary<Type, JsonConverter?>(); |
|
||||
|
|
||||
public ConverterContractResolver(params JsonConverter[] converters) |
|
||||
{ |
|
||||
NamingStrategy = new CamelCaseNamingStrategy(false, true); |
|
||||
|
|
||||
this.converters = converters; |
|
||||
|
|
||||
foreach (var converter in converters) |
|
||||
{ |
|
||||
if (converter is ISupportedTypes supportedTypes) |
|
||||
{ |
|
||||
foreach (var type in supportedTypes.SupportedTypes) |
|
||||
{ |
|
||||
converterCache[type] = converter; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
protected override JsonArrayContract CreateArrayContract(Type objectType) |
|
||||
{ |
|
||||
if (objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(IReadOnlyList<>)) |
|
||||
{ |
|
||||
var implementationType = typeof(List<>).MakeGenericType(objectType.GetGenericArguments()); |
|
||||
|
|
||||
return base.CreateArrayContract(implementationType); |
|
||||
} |
|
||||
|
|
||||
return base.CreateArrayContract(objectType); |
|
||||
} |
|
||||
|
|
||||
protected override JsonDictionaryContract CreateDictionaryContract(Type objectType) |
|
||||
{ |
|
||||
if (objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(IReadOnlyDictionary<,>)) |
|
||||
{ |
|
||||
var implementationType = typeof(Dictionary<,>).MakeGenericType(objectType.GetGenericArguments()); |
|
||||
|
|
||||
return base.CreateDictionaryContract(implementationType); |
|
||||
} |
|
||||
|
|
||||
return base.CreateDictionaryContract(objectType); |
|
||||
} |
|
||||
|
|
||||
protected override JsonConverter? ResolveContractConverter(Type objectType) |
|
||||
{ |
|
||||
var result = base.ResolveContractConverter(objectType); |
|
||||
|
|
||||
if (result != null) |
|
||||
{ |
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
var cache = converterCache; |
|
||||
|
|
||||
if (cache == null || !cache.TryGetValue(objectType, out result)) |
|
||||
{ |
|
||||
foreach (var converter in converters) |
|
||||
{ |
|
||||
if (converter.CanConvert(objectType)) |
|
||||
{ |
|
||||
result = converter; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
lock (lockObject) |
|
||||
{ |
|
||||
cache = converterCache; |
|
||||
|
|
||||
var updatedCache = (cache != null) |
|
||||
? new Dictionary<Type, JsonConverter?>(cache) |
|
||||
: new Dictionary<Type, JsonConverter?>(); |
|
||||
updatedCache[objectType] = result; |
|
||||
|
|
||||
converterCache = updatedCache; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,49 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using Newtonsoft.Json; |
|
||||
|
|
||||
namespace Squidex.Infrastructure.Json.Newtonsoft |
|
||||
{ |
|
||||
public abstract class JsonClassConverter<T> : JsonConverter, ISupportedTypes where T : class |
|
||||
{ |
|
||||
public virtual IEnumerable<Type> SupportedTypes |
|
||||
{ |
|
||||
get { yield return typeof(T); } |
|
||||
} |
|
||||
|
|
||||
public sealed override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) |
|
||||
{ |
|
||||
if (reader.TokenType == JsonToken.Null) |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
return ReadValue(reader, objectType, serializer); |
|
||||
} |
|
||||
|
|
||||
protected abstract T? ReadValue(JsonReader reader, Type objectType, JsonSerializer serializer); |
|
||||
|
|
||||
public sealed override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) |
|
||||
{ |
|
||||
if (value == null) |
|
||||
{ |
|
||||
writer.WriteNull(); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
WriteValue(writer, (T)value, serializer); |
|
||||
} |
|
||||
|
|
||||
protected abstract void WriteValue(JsonWriter writer, T value, JsonSerializer serializer); |
|
||||
|
|
||||
public override bool CanConvert(Type objectType) |
|
||||
{ |
|
||||
return objectType == typeof(T); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,207 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using Newtonsoft.Json; |
|
||||
using Squidex.Infrastructure.Json.Objects; |
|
||||
|
|
||||
#pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator
|
|
||||
|
|
||||
namespace Squidex.Infrastructure.Json.Newtonsoft |
|
||||
{ |
|
||||
public class JsonValueConverter : JsonConverter, ISupportedTypes |
|
||||
{ |
|
||||
private readonly HashSet<Type> supportedTypes = new HashSet<Type> |
|
||||
{ |
|
||||
typeof(JsonValue) |
|
||||
}; |
|
||||
|
|
||||
public virtual IEnumerable<Type> SupportedTypes |
|
||||
{ |
|
||||
get => supportedTypes; |
|
||||
} |
|
||||
|
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) |
|
||||
{ |
|
||||
var previousDateParseHandling = reader.DateParseHandling; |
|
||||
|
|
||||
reader.DateParseHandling = DateParseHandling.None; |
|
||||
try |
|
||||
{ |
|
||||
return ReadJsonCore(reader); |
|
||||
} |
|
||||
finally |
|
||||
{ |
|
||||
reader.DateParseHandling = previousDateParseHandling; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private static JsonValue ReadJsonCore(JsonReader reader) |
|
||||
{ |
|
||||
switch (reader.TokenType) |
|
||||
{ |
|
||||
case JsonToken.Null: |
|
||||
return default; |
|
||||
case JsonToken.Undefined: |
|
||||
return default; |
|
||||
case JsonToken.String: |
|
||||
return new JsonValue((string)reader.Value!); |
|
||||
case JsonToken.Integer: |
|
||||
return new JsonValue((long)reader.Value!); |
|
||||
case JsonToken.Float: |
|
||||
return new JsonValue((double)reader.Value!); |
|
||||
case JsonToken.Boolean: |
|
||||
return (bool)reader.Value! ? JsonValue.True : JsonValue.False; |
|
||||
case JsonToken.StartObject: |
|
||||
{ |
|
||||
var result = new JsonObject(4); |
|
||||
|
|
||||
Dictionary<string, JsonValue> dictionary = result; |
|
||||
|
|
||||
while (reader.Read()) |
|
||||
{ |
|
||||
switch (reader.TokenType) |
|
||||
{ |
|
||||
case JsonToken.PropertyName: |
|
||||
var propertyName = reader.Value!.ToString()!; |
|
||||
|
|
||||
if (!reader.Read()) |
|
||||
{ |
|
||||
ThrowInvalidObjectException(); |
|
||||
} |
|
||||
|
|
||||
var value = ReadJsonCore(reader); |
|
||||
|
|
||||
dictionary.Add(propertyName, value); |
|
||||
break; |
|
||||
case JsonToken.EndObject: |
|
||||
result.TrimExcess(); |
|
||||
|
|
||||
return new JsonValue(result); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
ThrowInvalidObjectException(); |
|
||||
return default!; |
|
||||
} |
|
||||
|
|
||||
case JsonToken.StartArray: |
|
||||
{ |
|
||||
var result = new JsonArray(4); |
|
||||
|
|
||||
while (reader.Read()) |
|
||||
{ |
|
||||
switch (reader.TokenType) |
|
||||
{ |
|
||||
case JsonToken.Comment: |
|
||||
continue; |
|
||||
case JsonToken.EndArray: |
|
||||
result.TrimExcess(); |
|
||||
|
|
||||
return new JsonValue(result); |
|
||||
default: |
|
||||
var value = ReadJsonCore(reader); |
|
||||
|
|
||||
result.Add(value); |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
ThrowInvalidArrayException(); |
|
||||
return default!; |
|
||||
} |
|
||||
|
|
||||
case JsonToken.Comment: |
|
||||
reader.Read(); |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
ThrowUnsupportedTypeException(); |
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
private static void ThrowUnsupportedTypeException() |
|
||||
{ |
|
||||
throw new JsonSerializationException("Unsupported type."); |
|
||||
} |
|
||||
|
|
||||
private static void ThrowInvalidArrayException() |
|
||||
{ |
|
||||
throw new JsonSerializationException("Unexpected end when reading Array."); |
|
||||
} |
|
||||
|
|
||||
private static void ThrowInvalidObjectException() |
|
||||
{ |
|
||||
throw new JsonSerializationException("Unexpected end when reading Object."); |
|
||||
} |
|
||||
|
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) |
|
||||
{ |
|
||||
if (value == null) |
|
||||
{ |
|
||||
writer.WriteNull(); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
WriteJson(writer, (JsonValue)value); |
|
||||
} |
|
||||
|
|
||||
private static void WriteJson(JsonWriter writer, JsonValue value) |
|
||||
{ |
|
||||
switch (value.Value) |
|
||||
{ |
|
||||
case null: |
|
||||
writer.WriteNull(); |
|
||||
break; |
|
||||
case bool b: |
|
||||
writer.WriteValue(b); |
|
||||
break; |
|
||||
case string s: |
|
||||
writer.WriteValue(s); |
|
||||
break; |
|
||||
case double n: |
|
||||
if (n % 1 == 0) |
|
||||
{ |
|
||||
writer.WriteValue((long)n); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
writer.WriteValue(n); |
|
||||
} |
|
||||
|
|
||||
break; |
|
||||
case JsonArray a: |
|
||||
writer.WriteStartArray(); |
|
||||
|
|
||||
foreach (var item in a) |
|
||||
{ |
|
||||
WriteJson(writer, item); |
|
||||
} |
|
||||
|
|
||||
writer.WriteEndArray(); |
|
||||
break; |
|
||||
|
|
||||
case JsonObject o: |
|
||||
writer.WriteStartObject(); |
|
||||
|
|
||||
foreach (var (key, jsonValue) in o) |
|
||||
{ |
|
||||
writer.WritePropertyName(key); |
|
||||
|
|
||||
WriteJson(writer, jsonValue); |
|
||||
} |
|
||||
|
|
||||
writer.WriteEndObject(); |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public override bool CanConvert(Type objectType) |
|
||||
{ |
|
||||
return supportedTypes.Contains(objectType); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,98 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using Newtonsoft.Json; |
|
||||
using NewtonsoftException = Newtonsoft.Json.JsonException; |
|
||||
|
|
||||
namespace Squidex.Infrastructure.Json.Newtonsoft |
|
||||
{ |
|
||||
public sealed class NewtonsoftJsonSerializer : IJsonSerializer |
|
||||
{ |
|
||||
private readonly JsonSerializerSettings settings; |
|
||||
private readonly JsonSerializer serializer; |
|
||||
|
|
||||
public NewtonsoftJsonSerializer(JsonSerializerSettings settings) |
|
||||
{ |
|
||||
Guard.NotNull(settings); |
|
||||
|
|
||||
this.settings = settings; |
|
||||
|
|
||||
serializer = JsonSerializer.Create(settings); |
|
||||
} |
|
||||
|
|
||||
public string Serialize<T>(T value, bool intented = false) |
|
||||
{ |
|
||||
var formatting = intented ? Formatting.Indented : Formatting.None; |
|
||||
|
|
||||
return JsonConvert.SerializeObject(value, formatting, settings); |
|
||||
} |
|
||||
|
|
||||
public void Serialize<T>(T value, Stream stream, bool leaveOpen = false) |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
using (var writer = new StreamWriter(stream, leaveOpen: leaveOpen)) |
|
||||
{ |
|
||||
serializer.Serialize(writer, value); |
|
||||
|
|
||||
writer.Flush(); |
|
||||
} |
|
||||
} |
|
||||
catch (NewtonsoftException ex) |
|
||||
{ |
|
||||
ThrowHelper.JsonException(ex.Message, ex); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public T Deserialize<T>(string value, Type? actualType = null) |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
using (var textReader = new StringReader(value)) |
|
||||
{ |
|
||||
actualType ??= typeof(T); |
|
||||
|
|
||||
using (var reader = GetReader(textReader)) |
|
||||
{ |
|
||||
return (T)serializer.Deserialize(reader, actualType)!; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
catch (NewtonsoftException ex) |
|
||||
{ |
|
||||
ThrowHelper.JsonException(ex.Message, ex); |
|
||||
return default!; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public T Deserialize<T>(Stream stream, Type? actualType = null, bool leaveOpen = false) |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
using (var textReader = new StreamReader(stream, leaveOpen: leaveOpen)) |
|
||||
{ |
|
||||
actualType ??= typeof(T); |
|
||||
|
|
||||
using (var reader = GetReader(textReader)) |
|
||||
{ |
|
||||
return (T)serializer.Deserialize(reader, actualType)!; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
catch (NewtonsoftException ex) |
|
||||
{ |
|
||||
ThrowHelper.JsonException(ex.Message, ex); |
|
||||
return default!; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private static JsonTextReader GetReader(TextReader textReader) |
|
||||
{ |
|
||||
return new JsonTextReader(textReader); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,30 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using Newtonsoft.Json; |
|
||||
|
|
||||
namespace Squidex.Infrastructure.Json.Newtonsoft |
|
||||
{ |
|
||||
public sealed class SurrogateConverter<T, TSurrogate> : JsonClassConverter<T> where T : class where TSurrogate : ISurrogate<T>, new() |
|
||||
{ |
|
||||
protected override T? ReadValue(JsonReader reader, Type objectType, JsonSerializer serializer) |
|
||||
{ |
|
||||
var surrogate = serializer.Deserialize<TSurrogate>(reader); |
|
||||
|
|
||||
return surrogate?.ToSource(); |
|
||||
} |
|
||||
|
|
||||
protected override void WriteValue(JsonWriter writer, T value, JsonSerializer serializer) |
|
||||
{ |
|
||||
var surrogate = new TSurrogate(); |
|
||||
|
|
||||
surrogate.FromSource(value); |
|
||||
|
|
||||
serializer.Serialize(writer, surrogate); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,50 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System.ComponentModel; |
|
||||
using Newtonsoft.Json; |
|
||||
|
|
||||
namespace Squidex.Infrastructure.Json.Newtonsoft |
|
||||
{ |
|
||||
public sealed class TypeConverterJsonConverter<T> : JsonConverter, ISupportedTypes |
|
||||
{ |
|
||||
private readonly TypeConverter typeConverter = TypeDescriptor.GetConverter(typeof(T)); |
|
||||
|
|
||||
public IEnumerable<Type> SupportedTypes |
|
||||
{ |
|
||||
get { yield return typeof(T); } |
|
||||
} |
|
||||
|
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) |
|
||||
{ |
|
||||
if (reader.TokenType == JsonToken.Null) |
|
||||
{ |
|
||||
return default(T); |
|
||||
} |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
return typeConverter.ConvertFromInvariantString(reader.Value?.ToString()!); |
|
||||
} |
|
||||
catch (Exception ex) |
|
||||
{ |
|
||||
ThrowHelper.JsonException("Error while converting from string.", ex); |
|
||||
return default; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) |
|
||||
{ |
|
||||
writer.WriteValue(typeConverter.ConvertToInvariantString(value)); |
|
||||
} |
|
||||
|
|
||||
public override bool CanConvert(Type objectType) |
|
||||
{ |
|
||||
return objectType == typeof(T); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,45 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using Newtonsoft.Json.Serialization; |
|
||||
using Squidex.Infrastructure.Reflection; |
|
||||
|
|
||||
namespace Squidex.Infrastructure.Json.Newtonsoft |
|
||||
{ |
|
||||
public sealed class TypeNameSerializationBinder : DefaultSerializationBinder |
|
||||
{ |
|
||||
private readonly TypeNameRegistry typeNameRegistry; |
|
||||
|
|
||||
public TypeNameSerializationBinder(TypeNameRegistry typeNameRegistry) |
|
||||
{ |
|
||||
this.typeNameRegistry = typeNameRegistry; |
|
||||
} |
|
||||
|
|
||||
public override Type BindToType(string? assemblyName, string typeName) |
|
||||
{ |
|
||||
var type = typeNameRegistry.GetTypeOrNull(typeName); |
|
||||
|
|
||||
return type ?? base.BindToType(assemblyName, typeName); |
|
||||
} |
|
||||
|
|
||||
public override void BindToName(Type serializedType, out string? assemblyName, out string? typeName) |
|
||||
{ |
|
||||
assemblyName = null; |
|
||||
|
|
||||
var name = typeNameRegistry.GetNameOrNull(serializedType); |
|
||||
|
|
||||
if (name != null) |
|
||||
{ |
|
||||
typeName = name; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
base.BindToName(serializedType, out assemblyName, out typeName); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,16 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using GeoJSON.Net.Converters; |
|
||||
|
|
||||
namespace Squidex.Infrastructure.Json.Newtonsoft |
|
||||
{ |
|
||||
public sealed class WriteonlyGeoJsonConverter : GeoJsonConverter |
|
||||
{ |
|
||||
public override bool CanWrite => false; |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,54 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Text.Json; |
||||
|
using Squidex.Infrastructure.Reflection; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.Json.System |
||||
|
{ |
||||
|
public sealed class InheritanceConverter<T> : InheritanceConverterBase<T> where T : notnull |
||||
|
{ |
||||
|
private readonly TypeNameRegistry typeNameRegistry; |
||||
|
|
||||
|
public InheritanceConverter(TypeNameRegistry typeNameRegistry) |
||||
|
: base("$type") |
||||
|
{ |
||||
|
this.typeNameRegistry = typeNameRegistry; |
||||
|
} |
||||
|
|
||||
|
public override Type GetDiscriminatorType(string name, Type typeToConvert) |
||||
|
{ |
||||
|
var typeInfo = typeNameRegistry.GetTypeOrNull(name); |
||||
|
|
||||
|
if (typeInfo == null) |
||||
|
{ |
||||
|
typeInfo = Type.GetType(name); |
||||
|
} |
||||
|
|
||||
|
if (typeInfo == null) |
||||
|
{ |
||||
|
ThrowHelper.JsonException($"Object has invalid discriminator '{name}'."); |
||||
|
return default!; |
||||
|
} |
||||
|
|
||||
|
return typeInfo; |
||||
|
} |
||||
|
|
||||
|
public override string GetDiscriminatorValue(Type type) |
||||
|
{ |
||||
|
var typeName = typeNameRegistry.GetNameOrNull(type); |
||||
|
|
||||
|
if (typeName == null) |
||||
|
{ |
||||
|
// Use the type name as a fallback.
|
||||
|
typeName = type.AssemblyQualifiedName!; |
||||
|
} |
||||
|
|
||||
|
return typeName; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,95 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Text.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
using Squidex.Infrastructure.ObjectPool; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.Json.System |
||||
|
{ |
||||
|
public abstract class InheritanceConverterBase<T> : JsonConverter<T> where T : notnull |
||||
|
{ |
||||
|
private readonly JsonEncodedText discriminatorProperty; |
||||
|
|
||||
|
public string DiscriminatorName { get; } |
||||
|
|
||||
|
protected InheritanceConverterBase(string discriminatorName) |
||||
|
{ |
||||
|
discriminatorProperty = JsonEncodedText.Encode(discriminatorName); |
||||
|
|
||||
|
DiscriminatorName = discriminatorName; |
||||
|
} |
||||
|
|
||||
|
public abstract Type GetDiscriminatorType(string name, Type typeToConvert); |
||||
|
|
||||
|
public abstract string GetDiscriminatorValue(Type type); |
||||
|
|
||||
|
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) |
||||
|
{ |
||||
|
// Creating a copy of the reader (The derived deserialisation has to be done from the start)
|
||||
|
Utf8JsonReader typeReader = reader; |
||||
|
|
||||
|
if (typeReader.TokenType != JsonTokenType.StartObject) |
||||
|
{ |
||||
|
throw new JsonException(); |
||||
|
} |
||||
|
|
||||
|
if (!typeReader.Read() || typeReader.TokenType != JsonTokenType.PropertyName) |
||||
|
{ |
||||
|
throw new JsonException(); |
||||
|
} |
||||
|
|
||||
|
var propertyName = typeReader.GetString(); |
||||
|
|
||||
|
if (typeReader.Read() && typeReader.TokenType == JsonTokenType.String && propertyName == DiscriminatorName) |
||||
|
{ |
||||
|
var type = GetDiscriminatorType(typeReader.GetString()!, typeToConvert); |
||||
|
|
||||
|
return (T?)JsonSerializer.Deserialize(ref reader, type, options); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
using var document = JsonDocument.ParseValue(ref reader); |
||||
|
|
||||
|
if (!document.RootElement.TryGetProperty(DiscriminatorName, out var discriminator)) |
||||
|
{ |
||||
|
ThrowHelper.JsonException($"Object has no discriminator '{DiscriminatorName}."); |
||||
|
return default!; |
||||
|
} |
||||
|
|
||||
|
var type = GetDiscriminatorType(discriminator.GetString()!, typeToConvert); |
||||
|
|
||||
|
using var bufferWriter = DefaultPools.MemoryStream.GetStream(); |
||||
|
|
||||
|
using (var writer = new Utf8JsonWriter(bufferWriter)) |
||||
|
{ |
||||
|
document.RootElement.WriteTo(writer); |
||||
|
} |
||||
|
|
||||
|
return (T?)JsonSerializer.Deserialize(bufferWriter.ToArray(), type, options); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) |
||||
|
{ |
||||
|
var name = GetDiscriminatorValue(value.GetType()); |
||||
|
|
||||
|
writer.WriteStartObject(); |
||||
|
writer.WriteString(discriminatorProperty, name); |
||||
|
|
||||
|
using (var document = JsonSerializer.SerializeToDocument(value, value.GetType(), options)) |
||||
|
{ |
||||
|
foreach (var property in document.RootElement.EnumerateObject()) |
||||
|
{ |
||||
|
property.WriteTo(writer); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
writer.WriteEndObject(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,72 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Text.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
using SquidexJsonArray = Squidex.Infrastructure.Json.Objects.JsonArray; |
||||
|
using SquidexJsonObject = Squidex.Infrastructure.Json.Objects.JsonObject; |
||||
|
using SquidexJsonValue = Squidex.Infrastructure.Json.Objects.JsonValue; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.Json.System |
||||
|
{ |
||||
|
public sealed class JsonValueConverter : JsonConverter<SquidexJsonValue> |
||||
|
{ |
||||
|
public override bool HandleNull => true; |
||||
|
|
||||
|
public override SquidexJsonValue Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) |
||||
|
{ |
||||
|
switch (reader.TokenType) |
||||
|
{ |
||||
|
case JsonTokenType.True: |
||||
|
return SquidexJsonValue.True; |
||||
|
case JsonTokenType.False: |
||||
|
return SquidexJsonValue.False; |
||||
|
case JsonTokenType.Null: |
||||
|
return SquidexJsonValue.Null; |
||||
|
case JsonTokenType.Number: |
||||
|
return SquidexJsonValue.Create(reader.GetDouble()); |
||||
|
case JsonTokenType.String: |
||||
|
return SquidexJsonValue.Create(reader.GetString()); |
||||
|
case JsonTokenType.StartObject: |
||||
|
return JsonSerializer.Deserialize<SquidexJsonObject>(ref reader, options); |
||||
|
case JsonTokenType.StartArray: |
||||
|
return JsonSerializer.Deserialize<SquidexJsonArray>(ref reader, options); |
||||
|
default: |
||||
|
ThrowHelper.NotSupportedException(); |
||||
|
return default; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override void Write(Utf8JsonWriter writer, SquidexJsonValue value, JsonSerializerOptions options) |
||||
|
{ |
||||
|
switch (value.Value) |
||||
|
{ |
||||
|
case null: |
||||
|
writer.WriteNullValue(); |
||||
|
break; |
||||
|
case bool b: |
||||
|
writer.WriteBooleanValue(b); |
||||
|
break; |
||||
|
case string s: |
||||
|
writer.WriteStringValue(s); |
||||
|
break; |
||||
|
case double n: |
||||
|
writer.WriteNumberValue(n); |
||||
|
break; |
||||
|
case SquidexJsonArray a: |
||||
|
JsonSerializer.Serialize(writer, a, options); |
||||
|
break; |
||||
|
case SquidexJsonObject o: |
||||
|
JsonSerializer.Serialize(writer, o, options); |
||||
|
break; |
||||
|
default: |
||||
|
ThrowHelper.NotSupportedException(); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,69 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Linq.Expressions; |
||||
|
using System.Reflection; |
||||
|
using System.Reflection.Emit; |
||||
|
using System.Text.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
using Squidex.Infrastructure.Collections; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.Json.System |
||||
|
{ |
||||
|
public sealed class ReadonlyDictionaryConverterFactory : JsonConverterFactory |
||||
|
{ |
||||
|
private sealed class Converter<TKey, TValue, TInstance> : JsonConverter<TInstance> where TKey : notnull |
||||
|
{ |
||||
|
private readonly Type innerType = typeof(IReadOnlyDictionary<TKey, TValue>); |
||||
|
private readonly Func<IDictionary<TKey, TValue>, TInstance> creator; |
||||
|
|
||||
|
public Converter() |
||||
|
{ |
||||
|
creator = ReflectionHelper.CreateParameterizedConstructor<TInstance, IDictionary<TKey, TValue>>(); |
||||
|
} |
||||
|
|
||||
|
public override TInstance Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) |
||||
|
{ |
||||
|
var inner = JsonSerializer.Deserialize<Dictionary<TKey, TValue>>(ref reader, options)!; |
||||
|
|
||||
|
return creator(inner); |
||||
|
} |
||||
|
|
||||
|
public override void Write(Utf8JsonWriter writer, TInstance value, JsonSerializerOptions options) |
||||
|
{ |
||||
|
JsonSerializer.Serialize(writer, value, innerType, options); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override bool CanConvert(Type typeToConvert) |
||||
|
{ |
||||
|
return IsReadonlyDictionary(typeToConvert) || IsReadonlyDictionary(typeToConvert.BaseType); |
||||
|
} |
||||
|
|
||||
|
public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) |
||||
|
{ |
||||
|
var typeToCreate = IsReadonlyDictionary(typeToConvert) ? typeToConvert : typeToConvert.BaseType!; |
||||
|
|
||||
|
var concreteType = typeof(Converter<,,>).MakeGenericType( |
||||
|
new Type[] |
||||
|
{ |
||||
|
typeToCreate.GetGenericArguments()[0], |
||||
|
typeToCreate.GetGenericArguments()[1], |
||||
|
typeToConvert |
||||
|
}); |
||||
|
|
||||
|
var converter = (JsonConverter)Activator.CreateInstance(concreteType)!; |
||||
|
|
||||
|
return converter; |
||||
|
} |
||||
|
|
||||
|
private static bool IsReadonlyDictionary(Type? type) |
||||
|
{ |
||||
|
return type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ReadonlyDictionary<,>); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,65 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Text.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
using Squidex.Infrastructure.Collections; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.Json.System |
||||
|
{ |
||||
|
public sealed class ReadonlyListConverterFactory : JsonConverterFactory |
||||
|
{ |
||||
|
private sealed class Converter<T, TInstance> : JsonConverter<TInstance> |
||||
|
{ |
||||
|
private readonly Type innerType = typeof(IReadOnlyList<T>); |
||||
|
private readonly Func<IList<T>, TInstance> creator; |
||||
|
|
||||
|
public Converter() |
||||
|
{ |
||||
|
creator = ReflectionHelper.CreateParameterizedConstructor<TInstance, IList<T>>(); |
||||
|
} |
||||
|
|
||||
|
public override TInstance Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) |
||||
|
{ |
||||
|
var inner = JsonSerializer.Deserialize<List<T>>(ref reader, options)!; |
||||
|
|
||||
|
return creator(inner); |
||||
|
} |
||||
|
|
||||
|
public override void Write(Utf8JsonWriter writer, TInstance value, JsonSerializerOptions options) |
||||
|
{ |
||||
|
JsonSerializer.Serialize(writer, value, innerType, options); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override bool CanConvert(Type typeToConvert) |
||||
|
{ |
||||
|
return IsReadonlyList(typeToConvert) || IsReadonlyList(typeToConvert.BaseType); |
||||
|
} |
||||
|
|
||||
|
public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) |
||||
|
{ |
||||
|
var typeToCreate = IsReadonlyList(typeToConvert) ? typeToConvert : typeToConvert.BaseType!; |
||||
|
|
||||
|
var concreteType = typeof(Converter<,>).MakeGenericType( |
||||
|
new Type[] |
||||
|
{ |
||||
|
typeToCreate.GetGenericArguments()[0], |
||||
|
typeToConvert, |
||||
|
}); |
||||
|
|
||||
|
var converter = (JsonConverter)Activator.CreateInstance(concreteType)!; |
||||
|
|
||||
|
return converter; |
||||
|
} |
||||
|
|
||||
|
private static bool IsReadonlyList(Type? type) |
||||
|
{ |
||||
|
return type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ReadonlyList<>); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,46 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Reflection; |
||||
|
using System.Reflection.Emit; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.Json.System |
||||
|
{ |
||||
|
internal static class ReflectionHelper |
||||
|
{ |
||||
|
public static Func<TInput, TInstance> CreateParameterizedConstructor<TInstance, TInput>() |
||||
|
{ |
||||
|
var method = CreateParameterizedConstructor(typeof(TInstance), typeof(TInput)); |
||||
|
|
||||
|
return method.CreateDelegate<Func<TInput, TInstance>>(); |
||||
|
} |
||||
|
|
||||
|
private static DynamicMethod CreateParameterizedConstructor(Type type, Type parameterType) |
||||
|
{ |
||||
|
var constructor = |
||||
|
type.GetConstructors() |
||||
|
.Single(x => |
||||
|
x.GetParameters().Length == 1 && |
||||
|
x.GetParameters()[0].ParameterType == parameterType); |
||||
|
|
||||
|
var dynamicMethod = new DynamicMethod( |
||||
|
ConstructorInfo.ConstructorName, |
||||
|
type, |
||||
|
new[] { parameterType }, |
||||
|
typeof(ReflectionHelper).Module, |
||||
|
true); |
||||
|
|
||||
|
var generator = dynamicMethod.GetILGenerator(); |
||||
|
|
||||
|
generator.Emit(OpCodes.Ldarg_0); |
||||
|
generator.Emit(OpCodes.Newobj, constructor); |
||||
|
generator.Emit(OpCodes.Ret); |
||||
|
|
||||
|
return dynamicMethod; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,62 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.ComponentModel; |
||||
|
using System.Text.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.Json.System |
||||
|
{ |
||||
|
public sealed class StringConverter<T> : JsonConverter<T> where T : notnull |
||||
|
{ |
||||
|
private readonly Func<string, T> convertFromString; |
||||
|
private readonly Func<T, string?> convertToString; |
||||
|
|
||||
|
public StringConverter(Func<string, T> convertFromString, Func<T, string?>? convertToString = null) |
||||
|
{ |
||||
|
this.convertFromString = convertFromString; |
||||
|
this.convertToString = convertToString ?? (x => x.ToString()); |
||||
|
} |
||||
|
|
||||
|
public StringConverter() |
||||
|
{ |
||||
|
var typeConverter = TypeDescriptor.GetConverter(typeof(T)); |
||||
|
|
||||
|
convertFromString = x => (T)typeConverter.ConvertFromInvariantString(x)!; |
||||
|
convertToString = x => typeConverter.ConvertToInvariantString(x)!; |
||||
|
} |
||||
|
|
||||
|
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) |
||||
|
{ |
||||
|
var text = reader.GetString(); |
||||
|
try |
||||
|
{ |
||||
|
return convertFromString(text!); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
ThrowHelper.JsonException("Error while converting from string.", ex); |
||||
|
return default; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override T ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) |
||||
|
{ |
||||
|
return convertFromString(reader.GetString()!); |
||||
|
} |
||||
|
|
||||
|
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) |
||||
|
{ |
||||
|
writer.WriteStringValue(convertToString(value)); |
||||
|
} |
||||
|
|
||||
|
public override void WriteAsPropertyName(Utf8JsonWriter writer, T value, JsonSerializerOptions options) |
||||
|
{ |
||||
|
writer.WritePropertyName(convertToString(value)!); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Text.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.Json.System |
||||
|
{ |
||||
|
public sealed class SurrogateJsonConverter<T, TSurrogate> : JsonConverter<T> where T : class where TSurrogate : ISurrogate<T>, new() |
||||
|
{ |
||||
|
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) |
||||
|
{ |
||||
|
var surrogate = JsonSerializer.Deserialize<TSurrogate>(ref reader, options); |
||||
|
|
||||
|
return surrogate?.ToSource(); |
||||
|
} |
||||
|
|
||||
|
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) |
||||
|
{ |
||||
|
var surrogate = new TSurrogate(); |
||||
|
|
||||
|
surrogate.FromSource(value); |
||||
|
|
||||
|
JsonSerializer.Serialize(writer, surrogate, options); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,108 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Text.Json; |
||||
|
using SystemJsonException = System.Text.Json.JsonException; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.Json.System |
||||
|
{ |
||||
|
public sealed class SystemJsonSerializer : IJsonSerializer |
||||
|
{ |
||||
|
private readonly JsonSerializerOptions optionsNormal; |
||||
|
private readonly JsonSerializerOptions optionsIndented; |
||||
|
|
||||
|
public SystemJsonSerializer(JsonSerializerOptions options) |
||||
|
{ |
||||
|
optionsNormal = new JsonSerializerOptions(options) |
||||
|
{ |
||||
|
WriteIndented = false |
||||
|
}; |
||||
|
|
||||
|
optionsIndented = new JsonSerializerOptions(options) |
||||
|
{ |
||||
|
WriteIndented = true |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
public T Deserialize<T>(string value, Type? actualType = null) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
return (T)JsonSerializer.Deserialize(value, actualType ?? typeof(T), optionsNormal)!; |
||||
|
} |
||||
|
catch (SystemJsonException ex) |
||||
|
{ |
||||
|
ThrowHelper.JsonException(ex.Message, ex); |
||||
|
return default!; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public T Deserialize<T>(Stream stream, Type? actualType = null, bool leaveOpen = false) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
return (T)JsonSerializer.Deserialize(stream, actualType ?? typeof(T), optionsNormal)!; |
||||
|
} |
||||
|
catch (SystemJsonException ex) |
||||
|
{ |
||||
|
ThrowHelper.JsonException(ex.Message, ex); |
||||
|
return default!; |
||||
|
} |
||||
|
finally |
||||
|
{ |
||||
|
if (!leaveOpen) |
||||
|
{ |
||||
|
stream.Dispose(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public string Serialize<T>(T value, bool indented = false) |
||||
|
{ |
||||
|
return Serialize(value, typeof(T), indented); |
||||
|
} |
||||
|
|
||||
|
public string Serialize(object? value, Type type, bool intented = false) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var options = intented ? optionsIndented : optionsNormal; |
||||
|
|
||||
|
return JsonSerializer.Serialize(value, type, options); |
||||
|
} |
||||
|
catch (SystemJsonException ex) |
||||
|
{ |
||||
|
ThrowHelper.JsonException(ex.Message, ex); |
||||
|
return default!; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void Serialize<T>(T value, Stream stream, bool leaveOpen = false) |
||||
|
{ |
||||
|
Serialize(value, typeof(T), stream, leaveOpen); |
||||
|
} |
||||
|
|
||||
|
public void Serialize(object? value, Type type, Stream stream, bool leaveOpen = false) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
JsonSerializer.Serialize(stream, value, optionsNormal); |
||||
|
} |
||||
|
catch (SystemJsonException ex) |
||||
|
{ |
||||
|
ThrowHelper.JsonException(ex.Message, ex); |
||||
|
} |
||||
|
finally |
||||
|
{ |
||||
|
if (!leaveOpen) |
||||
|
{ |
||||
|
stream.Dispose(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue