Browse Source

Handling the case where JSON is null or empty.

Resolve #6191
pull/6196/head
maliming 6 years ago
parent
commit
243bfd6fc0
  1. 24
      framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs
  2. 20
      framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs
  3. 21
      framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs
  4. 131
      framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs
  5. 23
      framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/JsonConverters/EntityJsonConverter.cs

24
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs

@ -1,4 +1,5 @@
using System;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Options;
@ -20,7 +21,28 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return _clock.Normalize(reader.GetDateTime());
if (!_options.DefaultDateTimeFormat.IsNullOrWhiteSpace())
{
if (reader.TokenType == JsonTokenType.String)
{
var s = reader.GetString();
if (DateTime.TryParseExact(s, _options.DefaultDateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out var d1))
{
return _clock.Normalize(d1);
}
throw new JsonException($"{s} cannot parse to DateTime({_options.DefaultDateTimeFormat})!");
}
throw new JsonException("reader TokenType is not String!");
}
if (reader.TryGetDateTime(out var d2))
{
return _clock.Normalize(d2);
}
throw new JsonException("reader can't get datetime!");
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)

20
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs

@ -16,15 +16,21 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters
x.GetType() == typeof(AbpHasExtraPropertiesJsonConverterFactory));
var rootElement = JsonDocument.ParseValue(ref reader).RootElement;
var extensibleObject = JsonSerializer.Deserialize<T>(rootElement.GetRawText(), newOptions);
if (rootElement.ValueKind == JsonValueKind.Object)
{
var extensibleObject = JsonSerializer.Deserialize<T>(rootElement.GetRawText(), newOptions);
var extraProperties = rootElement.EnumerateObject().FirstOrDefault(x =>
x.Name.Equals(nameof(IHasExtraProperties.ExtraProperties), StringComparison.OrdinalIgnoreCase))
.Value.GetRawText();
var extraPropertyDictionary = JsonSerializer.Deserialize(extraProperties, typeof(ExtraPropertyDictionary), newOptions);
ObjectHelper.TrySetProperty(extensibleObject, x => x.ExtraProperties, () => extraPropertyDictionary);
var extraProperties = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IHasExtraProperties.ExtraProperties), StringComparison.OrdinalIgnoreCase));
if (extraProperties.Value.ValueKind == JsonValueKind.Object)
{
var extraPropertyDictionary = JsonSerializer.Deserialize(extraProperties.Value.GetRawText(), typeof(ExtraPropertyDictionary), newOptions);
ObjectHelper.TrySetProperty(extensibleObject, x => x.ExtraProperties, () => extraPropertyDictionary);
}
return extensibleObject;
return extensibleObject;
}
throw new JsonException("RootElement ValueKind is not Object!");
}
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)

21
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs

@ -1,4 +1,5 @@
using System;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Options;
@ -20,9 +21,25 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters
public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TryGetDateTime(out var dateTime))
if (!_options.DefaultDateTimeFormat.IsNullOrWhiteSpace())
{
return _clock.Normalize(dateTime);
if (reader.TokenType == JsonTokenType.String)
{
var s = reader.GetString();
if (DateTime.TryParseExact(s, _options.DefaultDateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out var d1))
{
return _clock.Normalize(d1);
}
throw new JsonException($"{s} cannot parse to DateTime({_options.DefaultDateTimeFormat})!");
}
throw new JsonException("reader TokenType is not String!");
}
if (reader.TryGetDateTime(out var d2))
{
return _clock.Normalize(d2);
}
return null;

131
framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs

@ -1,4 +1,6 @@
using Shouldly;
using System;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Data;
using Volo.Abp.Json.SystemTextJson;
using Volo.Abp.ObjectExtending;
@ -8,23 +10,23 @@ namespace Volo.Abp.Json
{
public class AbpSystemTextJsonSerializerProvider_Tests : AbpJsonTestBase
{
private readonly AbpSystemTextJsonSerializerProvider _jsonSerializer;
protected AbpSystemTextJsonSerializerProvider JsonSerializer;
public AbpSystemTextJsonSerializerProvider_Tests()
{
_jsonSerializer = GetRequiredService<AbpSystemTextJsonSerializerProvider>();
JsonSerializer = GetRequiredService<AbpSystemTextJsonSerializerProvider>();
}
[Fact]
public void Serialize_Deserialize_With_Boolean()
{
var json = "{\"name\":\"abp\",\"IsDeleted\":\"fAlSe\"}";
var file = _jsonSerializer.Deserialize<FileWithBoolean>(json);
var file = JsonSerializer.Deserialize<FileWithBoolean>(json);
file.Name.ShouldBe("abp");
file.IsDeleted.ShouldBeFalse();
file.IsDeleted = false;
var newJson = _jsonSerializer.Serialize(file);
var newJson = JsonSerializer.Serialize(file);
newJson.ShouldBe("{\"name\":\"abp\",\"isDeleted\":false}");
}
@ -32,19 +34,19 @@ namespace Volo.Abp.Json
public void Serialize_Deserialize_With_Nullable_Boolean()
{
var json = "{\"name\":\"abp\",\"IsDeleted\":null}";
var file = _jsonSerializer.Deserialize<FileWithNullableBoolean>(json);
var file = JsonSerializer.Deserialize<FileWithNullableBoolean>(json);
file.Name.ShouldBe("abp");
file.IsDeleted.ShouldBeNull();
var newJson = _jsonSerializer.Serialize(file);
var newJson = JsonSerializer.Serialize(file);
newJson.ShouldBe("{\"name\":\"abp\",\"isDeleted\":null}");
json = "{\"name\":\"abp\",\"IsDeleted\":\"true\"}";
file = _jsonSerializer.Deserialize<FileWithNullableBoolean>(json);
file = JsonSerializer.Deserialize<FileWithNullableBoolean>(json);
file.IsDeleted.ShouldNotBeNull();
file.IsDeleted.Value.ShouldBeTrue();
newJson = _jsonSerializer.Serialize(file);
newJson = JsonSerializer.Serialize(file);
newJson.ShouldBe("{\"name\":\"abp\",\"isDeleted\":true}");
}
@ -52,11 +54,11 @@ namespace Volo.Abp.Json
public void Serialize_Deserialize_With_Enum()
{
var json = "{\"name\":\"abp\",\"type\":\"Exe\"}";
var file = _jsonSerializer.Deserialize<FileWithEnum>(json);
var file = JsonSerializer.Deserialize<FileWithEnum>(json);
file.Name.ShouldBe("abp");
file.Type.ShouldBe(FileType.Exe);
var newJson = _jsonSerializer.Serialize(file);
var newJson = JsonSerializer.Serialize(file);
newJson.ShouldBe("{\"name\":\"abp\",\"type\":2}");
}
@ -64,35 +66,73 @@ namespace Volo.Abp.Json
public void Serialize_Deserialize_With_Nullable_Enum()
{
var json = "{\"name\":\"abp\",\"type\":null}";
var file = _jsonSerializer.Deserialize<FileWithNullableEnum>(json);
var file = JsonSerializer.Deserialize<FileWithNullableEnum>(json);
file.Name.ShouldBe("abp");
file.Type.ShouldBeNull();
var newJson = _jsonSerializer.Serialize(file);
var newJson = JsonSerializer.Serialize(file);
newJson.ShouldBe("{\"name\":\"abp\",\"type\":null}");
json = "{\"name\":\"abp\",\"type\":\"Exe\"}";
file = _jsonSerializer.Deserialize<FileWithNullableEnum>(json);
file = JsonSerializer.Deserialize<FileWithNullableEnum>(json);
file.Type.ShouldNotBeNull();
file.Type.ShouldBe(FileType.Exe);
newJson = _jsonSerializer.Serialize(file);
newJson = JsonSerializer.Serialize(file);
newJson.ShouldBe("{\"name\":\"abp\",\"type\":2}");
}
[Fact]
public void Serialize_Deserialize_ExtensibleObject()
{
var json = "{\"name\":\"test\",\"extraProperties\":{\"One\":\"123\",\"Two\":456}}";
var extensibleObject = _jsonSerializer.Deserialize<TestExtensibleObjectClass>(json);
var extensibleObject = JsonSerializer.Deserialize<TestExtensibleObjectClass>(json);
extensibleObject.GetProperty("One").ShouldBe("123");
extensibleObject.GetProperty("Two").ShouldBe(456);
var newJson = _jsonSerializer.Serialize(extensibleObject);
var newJson = JsonSerializer.Serialize(extensibleObject);
newJson.ShouldBe(json);
}
[Fact]
public void Serialize_Deserialize_ExtensibleObject_With_ExtraProperties_String()
{
var json = "{\"name\":\"test\"}";
var extensibleObject = JsonSerializer.Deserialize<TestExtensibleObjectClass>(json);
extensibleObject.ExtraProperties.ShouldNotBeNull();
extensibleObject.ExtraProperties.ShouldBeEmpty();
}
[Fact]
public void Serialize_Deserialize_With_Datetime()
{
var json = "{\"name\":\"abp\",\"creationTime\":\"2020-11-20T00:00:00\"}";
var file = JsonSerializer.Deserialize<FileWithDatetime>(json);
file.CreationTime.Year.ShouldBe(2020);
file.CreationTime.Month.ShouldBe(11);
file.CreationTime.Day.ShouldBe(20);
}
[Fact]
public void Serialize_Deserialize_With_Nullable_Datetime()
{
var json = "{\"name\":\"abp\",\"creationTime\":null}";
var file = JsonSerializer.Deserialize<FileWithNullableDatetime>(json);
file.CreationTime.ShouldBeNull();
json = "{\"name\":\"abp\"}";
file = JsonSerializer.Deserialize<FileWithNullableDatetime>(json);
file.CreationTime.ShouldBeNull();
json = "{\"name\":\"abp\",\"creationTime\":\"2020-11-20T00:00:00\"}";
file = JsonSerializer.Deserialize<FileWithNullableDatetime>(json);
file.CreationTime.ShouldNotBeNull();
file.CreationTime.Value.Year.ShouldBe(2020);
file.CreationTime.Value.Month.ShouldBe(11);
file.CreationTime.Value.Day.ShouldBe(20);
}
class TestExtensibleObjectClass : ExtensibleObject
{
public string Name { get; set; }
@ -131,5 +171,60 @@ namespace Volo.Abp.Json
Zip = 0,
Exe = 2
}
protected class FileWithDatetime
{
public string Name { get; set; }
public DateTime CreationTime { get; set; }
}
protected class FileWithNullableDatetime
{
public string Name { get; set; }
public DateTime? CreationTime { get; set; }
}
}
public class FormatAbpSystemTextJsonSerializerProvider_Tests : AbpSystemTextJsonSerializerProvider_Tests
{
protected override void AfterAddApplication(IServiceCollection services)
{
services.Configure<AbpJsonOptions>(options =>
{
options.DefaultDateTimeFormat = "yyyy*MM*dd";
});
}
[Fact]
public void Serialize_Deserialize_With_Format_Datetime()
{
var json = "{\"name\":\"abp\",\"creationTime\":\"2020*11*20\"}";
var file = JsonSerializer.Deserialize<FileWithDatetime>(json);
file.CreationTime.Year.ShouldBe(2020);
file.CreationTime.Month.ShouldBe(11);
file.CreationTime.Day.ShouldBe(20);
}
[Fact]
public void Serialize_Deserialize_With_Nullable_Format_Datetime()
{
var json = "{\"name\":\"abp\",\"creationTime\":null}";
var file = JsonSerializer.Deserialize<FileWithNullableDatetime>(json);
file.CreationTime.ShouldBeNull();
json = "{\"name\":\"abp\"}";
file = JsonSerializer.Deserialize<FileWithNullableDatetime>(json);
file.CreationTime.ShouldBeNull();
json = "{\"name\":\"abp\",\"creationTime\":\"2020*11*20\"}";
file = JsonSerializer.Deserialize<FileWithNullableDatetime>(json);
file.CreationTime.ShouldNotBeNull();
file.CreationTime.Value.Year.ShouldBe(2020);
file.CreationTime.Value.Month.ShouldBe(11);
file.CreationTime.Value.Day.ShouldBe(20);
}
}
}

23
framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/JsonConverters/EntityJsonConverter.cs

@ -6,21 +6,28 @@ using Volo.Abp.Domain.Entities;
namespace Volo.Abp.MemoryDb.JsonConverters
{
public class EntityJsonConverter<TEntity, TKey> : JsonConverter<TEntity>
where TEntity : IEntity<TKey>
where TEntity : Entity<TKey>
{
public override TEntity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var jsonDocument = JsonDocument.ParseValue(ref reader);
var entity = (TEntity)JsonSerializer.Deserialize(jsonDocument.RootElement.GetRawText(), typeToConvert);
var idJsonElement = jsonDocument.RootElement.GetProperty(nameof(IEntity<object>.Id));
var id = JsonSerializer.Deserialize<TKey>(idJsonElement.GetRawText());
if (id != null)
if (jsonDocument.RootElement.ValueKind == JsonValueKind.Object)
{
EntityHelper.TrySetId(entity, () => id);
var entity = (TEntity)JsonSerializer.Deserialize(jsonDocument.RootElement.GetRawText(), typeToConvert);
var idJsonElement = jsonDocument.RootElement.GetProperty(nameof(Entity<object>.Id));
if (idJsonElement.ValueKind != JsonValueKind.Undefined)
{
var id = JsonSerializer.Deserialize<TKey>(idJsonElement.GetRawText());
if (id != null)
{
EntityHelper.TrySetId(entity, () => id);
}
}
return entity;
}
return entity;
throw new JsonException("RootElement ValueKind is not Object!");
}
public override void Write(Utf8JsonWriter writer, TEntity value, JsonSerializerOptions options)

Loading…
Cancel
Save