mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 10:58:30 -05:00
add flag converters nullable serialization (#857)
This commit is contained in:
committed by
Kevin Cunnane
parent
55c82fbcc4
commit
c6e3b33c35
@@ -0,0 +1,3 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Microsoft.SqlTools.Hosting.UnitTests")]
|
||||
@@ -18,7 +18,7 @@ namespace Microsoft.SqlTools.DataProtocol.Contracts.Utilities
|
||||
public override bool CanRead => true;
|
||||
|
||||
#region Public Methods
|
||||
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType.IsEnum && objectType.GetCustomAttribute(typeof(FlagsAttribute)) != null;
|
||||
@@ -26,16 +26,21 @@ namespace Microsoft.SqlTools.DataProtocol.Contracts.Utilities
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
// TODO: Fix to handle nullables properly
|
||||
|
||||
int[] values = JArray.Load(reader).Values<int>().ToArray();
|
||||
var jToken = JToken.Load(reader);
|
||||
if (jToken.Type == JTokenType.Null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
FieldInfo[] enumFields = objectType.GetFields(BindingFlags.Public | BindingFlags.Static);
|
||||
int[] values = ((JArray)jToken).Values<int>().ToArray();
|
||||
var pureType = NullableUtils.GetUnderlyingTypeIfNullable(objectType);
|
||||
|
||||
FieldInfo[] enumFields = pureType.GetFields(BindingFlags.Public | BindingFlags.Static);
|
||||
int setFlags = 0;
|
||||
foreach (FieldInfo enumField in enumFields)
|
||||
{
|
||||
int enumValue = (int) enumField.GetValue(null);
|
||||
|
||||
int enumValue = (int)enumField.GetValue(null);
|
||||
|
||||
// If there is a serialize value set for the enum value, look for that instead of the int value
|
||||
SerializeValueAttribute serializeValue = enumField.GetCustomAttribute<SerializeValueAttribute>();
|
||||
int searchValue = serializeValue?.Value ?? enumValue;
|
||||
@@ -45,7 +50,7 @@ namespace Microsoft.SqlTools.DataProtocol.Contracts.Utilities
|
||||
}
|
||||
}
|
||||
|
||||
return Enum.ToObject(objectType, setFlags);
|
||||
return Enum.ToObject(pureType, setFlags);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
@@ -56,22 +61,22 @@ namespace Microsoft.SqlTools.DataProtocol.Contracts.Utilities
|
||||
{
|
||||
// Make sure the flag is set before doing expensive reflection
|
||||
int enumValue = (int)enumField.GetValue(null);
|
||||
if (((int) value & enumValue) == 0)
|
||||
if (((int)value & enumValue) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// If there is a serialize value set for the member, use that instead of the int value
|
||||
SerializeValueAttribute serializeValue = enumField.GetCustomAttribute<SerializeValueAttribute>();
|
||||
int flagValue = serializeValue?.Value ?? enumValue;
|
||||
int flagValue = serializeValue?.Value ?? enumValue;
|
||||
setFlags.Add(flagValue);
|
||||
}
|
||||
|
||||
string joinedFlags = string.Join(", ", setFlags);
|
||||
writer.WriteRawValue($"[{joinedFlags}]");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
internal class SerializeValueAttribute : Attribute
|
||||
@@ -82,6 +87,6 @@ namespace Microsoft.SqlTools.DataProtocol.Contracts.Utilities
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,33 +14,32 @@ using Newtonsoft.Json.Serialization;
|
||||
namespace Microsoft.SqlTools.DataProtocol.Contracts.Utilities
|
||||
{
|
||||
internal class FlagsStringConverter : JsonConverter
|
||||
{
|
||||
{
|
||||
public override bool CanWrite => true;
|
||||
public override bool CanRead => true;
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType.IsEnum && objectType.GetCustomAttribute(typeof(FlagsAttribute)) != null;
|
||||
}
|
||||
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
// TODO: Fix to handle nullables properly
|
||||
|
||||
JToken jToken = JToken.Load(reader);
|
||||
if (jToken.Type == JTokenType.Null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string[] values = ((JArray) jToken).Values<string>().ToArray();
|
||||
string[] values = ((JArray)jToken).Values<string>().ToArray();
|
||||
var pureType = NullableUtils.GetUnderlyingTypeIfNullable(objectType);
|
||||
|
||||
FieldInfo[] enumFields = objectType.GetFields(BindingFlags.Public | BindingFlags.Static);
|
||||
FieldInfo[] enumFields = pureType.GetFields(BindingFlags.Public | BindingFlags.Static);
|
||||
int setFlags = 0;
|
||||
foreach (FieldInfo enumField in enumFields)
|
||||
{
|
||||
{
|
||||
// If there is a serialize value set for the enum value, look for the instead of the int value
|
||||
SerializeValueAttribute serializeValue = enumField.GetCustomAttribute<SerializeValueAttribute>();
|
||||
string searchValue = serializeValue?.Value ?? enumField.Name;
|
||||
@@ -48,15 +47,15 @@ namespace Microsoft.SqlTools.DataProtocol.Contracts.Utilities
|
||||
{
|
||||
searchValue = char.ToLowerInvariant(searchValue[0]) + searchValue.Substring(1);
|
||||
}
|
||||
|
||||
|
||||
// If the value is in the json array, or the int value into the flags
|
||||
if (Array.IndexOf(values, searchValue) >= 0)
|
||||
{
|
||||
setFlags |= (int) enumField.GetValue(null);
|
||||
setFlags |= (int)enumField.GetValue(null);
|
||||
}
|
||||
}
|
||||
|
||||
return Enum.ToObject(objectType, setFlags);
|
||||
return Enum.ToObject(pureType, setFlags);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
@@ -66,12 +65,12 @@ namespace Microsoft.SqlTools.DataProtocol.Contracts.Utilities
|
||||
foreach (FieldInfo enumField in enumFields)
|
||||
{
|
||||
// Make sure the flag is set before doing any other work
|
||||
int enumValue = (int) enumField.GetValue(null);
|
||||
if (((int) value & enumValue) == 0)
|
||||
int enumValue = (int)enumField.GetValue(null);
|
||||
if (((int)value & enumValue) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// If there is a serialize value set for the member, use that instead of the int value
|
||||
SerializeValueAttribute serializeValue = enumField.GetCustomAttribute<SerializeValueAttribute>();
|
||||
string flagValue = serializeValue?.Value ?? enumField.Name;
|
||||
@@ -85,9 +84,9 @@ namespace Microsoft.SqlTools.DataProtocol.Contracts.Utilities
|
||||
string joinedFlags = string.Join(", ", setFlags);
|
||||
writer.WriteRawValue($"[{joinedFlags}]");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
internal class SerializeValueAttribute : Attribute
|
||||
{
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.SqlTools.DataProtocol.Contracts.Utilities
|
||||
{
|
||||
internal static class NullableUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether the type is <see cref="Nullable{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="t">The type.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if <paramref name="t"/> is <see cref="Nullable{T}"/>; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public static bool IsNullable(Type t)
|
||||
{
|
||||
return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unwraps the <see cref="Nullable{T}"/> if necessary and returns the underlying value type.
|
||||
/// </summary>
|
||||
/// <param name="t">The type.</param>
|
||||
/// <returns>The underlying value type the <see cref="Nullable{T}"/> type was produced from,
|
||||
/// or the <paramref name="t"/> type if the type is not <see cref="Nullable{T}"/>.
|
||||
/// </returns>
|
||||
public static Type GetUnderlyingTypeIfNullable(Type t)
|
||||
{
|
||||
return IsNullable(t) ? Nullable.GetUnderlyingType(t) : t;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user