diff --git a/AnyOf Solution.sln b/AnyOf Solution.sln
index 0c1234a..ff997aa 100644
--- a/AnyOf Solution.sln
+++ b/AnyOf Solution.sln
@@ -46,6 +46,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleAppUsesClassLibrarie
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClassLibraryCommon", "examples\ClassLibraryCommon\ClassLibraryCommon.csproj", "{C7307358-326A-42D2-889C-61D1DAE285D2}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AnyOf.Newtonsoft.Json", "src\AnyOf.Newtonsoft.Json\AnyOf.Newtonsoft.Json.csproj", "{3BD0104F-3E63-4223-A4AD-372E68A6B0CB}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -96,6 +98,10 @@ Global
{C7307358-326A-42D2-889C-61D1DAE285D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C7307358-326A-42D2-889C-61D1DAE285D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C7307358-326A-42D2-889C-61D1DAE285D2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3BD0104F-3E63-4223-A4AD-372E68A6B0CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3BD0104F-3E63-4223-A4AD-372E68A6B0CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3BD0104F-3E63-4223-A4AD-372E68A6B0CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3BD0104F-3E63-4223-A4AD-372E68A6B0CB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -113,6 +119,7 @@ Global
{6A1126B2-EFD3-4758-907C-31B010178D84} = {38805E90-A955-4097-97DC-537F7A0CD773}
{8F07BB3B-6C03-4533-89D0-D4C6106CCB0C} = {38805E90-A955-4097-97DC-537F7A0CD773}
{C7307358-326A-42D2-889C-61D1DAE285D2} = {38805E90-A955-4097-97DC-537F7A0CD773}
+ {3BD0104F-3E63-4223-A4AD-372E68A6B0CB} = {0B71158B-576B-4498-9D40-141D554D1272}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3586BB89-A981-4CD0-88DB-2DF513FE2B90}
diff --git a/src/AnyOf.Newtonsoft.Json/AnyOf.Newtonsoft.Json.csproj b/src/AnyOf.Newtonsoft.Json/AnyOf.Newtonsoft.Json.csproj
new file mode 100644
index 0000000..a444e27
--- /dev/null
+++ b/src/AnyOf.Newtonsoft.Json/AnyOf.Newtonsoft.Json.csproj
@@ -0,0 +1,19 @@
+
+
+
+ AnyOf.Newtonsoft.Json
+ net45;netstandard1.3;netstandard2.0;netstandard2.1
+ {31D0104F-3E63-4223-A4AD-372E68A6B0CB}
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/AnyOf.Newtonsoft.Json/AnyOfJsonConverter.cs b/src/AnyOf.Newtonsoft.Json/AnyOfJsonConverter.cs
new file mode 100644
index 0000000..3cd0653
--- /dev/null
+++ b/src/AnyOf.Newtonsoft.Json/AnyOfJsonConverter.cs
@@ -0,0 +1,149 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.Serialization;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+namespace RestEaseClientGeneratorConsoleApp
+{
+ public class AnyOfJsonConverter : JsonConverter
+ {
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ if (value == null)
+ {
+ if (serializer.NullValueHandling == NullValueHandling.Include)
+ {
+ serializer.Serialize(writer, value);
+ }
+ return;
+ }
+
+ var currentValue = GetPropertyValue(value, "CurrentValue");
+ serializer.Serialize(writer, currentValue);
+ }
+
+ ///
+ /// See
+ /// - https://stackoverflow.com/questions/8030538/how-to-implement-custom-jsonconverter-in-json-net
+ /// - https://stackoverflow.com/a/59286262/255966
+ ///
+ public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ {
+ var jObject = JObject.Load(reader);
+
+ Type mostSuitableType = null;
+ int countOfMaxMatchingProperties = -1;
+
+ // Take the names of elements from json data
+ var jObjectKeys = GetKeys(jObject);
+
+ // Take the public properties of the parent class
+ var objectTypeProps = objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public)
+ .Select(p => p.Name).ToHashSet();
+
+ // Trying to find the right "KnownType"
+ foreach (var knownType in GetPropertyValue(existingValue, "Types"))
+ {
+ // Select properties of the inheritor, except properties from the parent class and properties with "ignore" attributes
+ var notIgnoreProps = knownType.GetProperties(BindingFlags.Instance | BindingFlags.Public)
+ .Where(p => !objectTypeProps.Contains(p.Name) && p.CustomAttributes.All(a => a.AttributeType != typeof(JsonIgnoreAttribute)));
+
+ // Get serializable property names
+ var jsonNameFields = notIgnoreProps.Select(prop =>
+ {
+ string jsonFieldName = null;
+ var jsonPropertyAttribute = prop.CustomAttributes.FirstOrDefault(a => a.AttributeType == typeof(JsonPropertyAttribute));
+ if (jsonPropertyAttribute != null)
+ {
+ // Take the name of the json element from the attribute constructor
+ int constructorArgumentsCount = jsonPropertyAttribute.ConstructorArguments.Count;
+ if (constructorArgumentsCount > 0)
+ {
+ var argument = jsonPropertyAttribute.ConstructorArguments.First();
+ if (argument.ArgumentType == typeof(string) && !string.IsNullOrEmpty(argument.Value as string))
+ {
+ jsonFieldName = (string)argument.Value;
+ }
+ }
+ }
+
+ // Otherwise, take the name of the property
+ if (string.IsNullOrEmpty(jsonFieldName))
+ {
+ jsonFieldName = prop.Name;
+ }
+
+ return jsonFieldName;
+ });
+
+ var jKnownTypeKeys = new HashSet(jsonNameFields);
+
+ // By intersecting the sets of names we determine the most suitable inheritor
+ int count = jObjectKeys.Intersect(jKnownTypeKeys).Count();
+
+ if (count == jKnownTypeKeys.Count)
+ {
+ mostSuitableType = knownType;
+ break;
+ }
+
+ if (count > countOfMaxMatchingProperties)
+ {
+ countOfMaxMatchingProperties = count;
+ mostSuitableType = knownType;
+ }
+ }
+
+ if (mostSuitableType != null)
+ {
+ object target = Activator.CreateInstance(mostSuitableType);
+
+ using (JsonReader jObjectReader = CopyReaderForObject(reader, jObject))
+ {
+ serializer.Populate(jObjectReader, target);
+ }
+
+ return Activator.CreateInstance(objectType, target);
+ }
+
+ throw new SerializationException($"Could not deserialize {objectType}, no suitable type found.");
+ }
+
+ public override bool CanConvert(Type objectType)
+ {
+ return objectType.FullName.StartsWith("AnyOfTypes.AnyOf`");
+ }
+
+ private HashSet GetKeys(JObject obj)
+ {
+ return new HashSet(((IEnumerable>)obj).Select(k => k.Key));
+ }
+
+ private static JsonReader CopyReaderForObject(JsonReader reader, JObject jObject)
+ {
+ var jObjectReader = jObject.CreateReader();
+ jObjectReader.CloseInput = reader.CloseInput;
+ jObjectReader.Culture = reader.Culture;
+ jObjectReader.DateFormatString = reader.DateFormatString;
+ jObjectReader.DateParseHandling = reader.DateParseHandling;
+ jObjectReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
+ jObjectReader.FloatParseHandling = reader.FloatParseHandling;
+ jObjectReader.MaxDepth = reader.MaxDepth;
+ jObjectReader.SupportMultipleContent = reader.SupportMultipleContent;
+ return jObjectReader;
+ }
+
+ private static T GetPropertyValue(object value, string name)
+ {
+ return (T)GetPropertyValue(value, name);
+ }
+
+ private static object GetPropertyValue(object value, string name)
+ {
+ return value.GetType().GetProperty(name).GetValue(value);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AnyOf.Newtonsoft.Json/Compatiblity/LinqExtensions.cs b/src/AnyOf.Newtonsoft.Json/Compatiblity/LinqExtensions.cs
new file mode 100644
index 0000000..96cba4f
--- /dev/null
+++ b/src/AnyOf.Newtonsoft.Json/Compatiblity/LinqExtensions.cs
@@ -0,0 +1,14 @@
+#if !NETSTANDARD2_1_OR_GREATER
+using System.Collections.Generic;
+
+namespace System.Linq
+{
+ internal static class LinqExtensions
+ {
+ public static HashSet ToHashSet(this IEnumerable source, IEqualityComparer comparer = null)
+ {
+ return new HashSet(source, comparer);
+ }
+ }
+}
+#endif
\ No newline at end of file