Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added integer converter, disabled throwing exceptions on invalid json #7

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/Citrina/Json/CitrinaJsonConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ public static class CitrinaJsonConverter
Converters =
{
new UnixDateConverter(),
new BooleanConverter()
new BooleanConverter(),
new NumberConverter(),
},
ContractResolver = new SnakeCaseContractResolver()
ContractResolver = new SnakeCaseContractResolver(),
Error = (a,b) => b.ErrorContext.Handled = true,
};

public static T Deserialize<T>(string data)
Expand Down
85 changes: 85 additions & 0 deletions src/Citrina/Json/Converters/NumberConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;

namespace Citrina.Json.Converters
{
internal class NumberConverter : JsonConverter
{
private static readonly CultureInfo invariantCulture = CultureInfo.InvariantCulture;
private static readonly Type
intType = typeof(int),
intQType = typeof(int?),
uintType = typeof(uint),
uintQType = typeof(uint?),
longType = typeof(long),
longQType = typeof(long?),
ulongType = typeof(ulong),
ulongQType = typeof(ulong?),
shortType = typeof(short),
shortQType = typeof(short?),
ushortType = typeof(ushort),
ushortQType = typeof(ushort?),
byteType = typeof(byte),
byteQType = typeof(byte?),
sbyteType = typeof(sbyte),
sbyteQType = typeof(sbyte?);
private static readonly HashSet<Type> types = new HashSet<Type>{
intType, intQType, uintType, uintQType, longType, longQType,
ulongType, ulongQType, shortType, shortQType, ushortType, ushortQType,
byteType, byteQType, sbyteType, sbyteQType
};
private static readonly HashSet<Type> nulltypes = new HashSet<Type>{
intQType, uintQType, longQType, ulongQType, shortQType, ushortQType, byteQType, sbyteQType,
};

private static readonly Dictionary<Type, Type> nullBase = new Dictionary<Type, Type>{
{ intQType, intType },
{ uintQType, uintType },
{ longQType, longType },
{ ulongQType, ulongType },
{ shortQType, shortType },
{ ushortQType, ushortType },
{ byteQType, byteType },
{ sbyteQType, sbyteType },
};

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
switch (reader.TokenType)
{
case JsonToken.Null:
if (nulltypes.Contains(objectType))
{
return null;
}
throw new JsonSerializationException($"Unexpected null token for a non-nullable field");
case JsonToken.Integer:
case JsonToken.Float:
return Convert.ChangeType(
reader.Value,
objectType = nullBase.ContainsKey(objectType) ? nullBase[objectType] : objectType
);
case JsonToken.String:
if (!long.TryParse(reader.Value as string, NumberStyles.Any, invariantCulture, out var value))
if (!double.TryParse(reader.Value as string, NumberStyles.Any, invariantCulture, out var dvalue))
throw new FormatException($"Invalid input string: {reader.Value}");
else
value = (long)Convert.ChangeType(value, longType);
objectType = nullBase.ContainsKey(objectType) ? nullBase[objectType] : objectType;
if (objectType == longType)//short path
return value;
return Convert.ChangeType(value, objectType);
default:
throw new JsonSerializationException($"Unexpected token type: {reader.TokenType}");
}
}

public override bool CanConvert(Type objectType) => types.Contains(objectType);
public override bool CanRead => true;
public override bool CanWrite => false;
}
}