Skip to content
Merged
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
92 changes: 57 additions & 35 deletions Source/Schema.NET/ValuesJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace Schema.NET
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
Expand Down Expand Up @@ -63,6 +64,8 @@ public override object ReadJson(
var value = reader.Value;

var token = JToken.Load(reader);
var count = token.Children().Count();

#pragma warning disable CA1062 // Validate arguments of public methods
if (mainType.GenericTypeArguments.Length == 1)
#pragma warning restore CA1062 // Validate arguments of public methods
Expand All @@ -82,14 +85,29 @@ public override object ReadJson(
{
if (tokenType == JsonToken.StartArray)
{
var total = 0;
var items = new List<object>();
foreach (var type in mainType.GenericTypeArguments)
for (var i = mainType.GenericTypeArguments.Length - 1; i >= 0; i--)
{
var type = mainType.GenericTypeArguments[i];
var unwrappedType = type.GetUnderlyingTypeFromNullable();
var args = ReadJsonArray(token, unwrappedType);
var genericType = typeof(OneOrMany<>).MakeGenericType(type);
var item = (IValues)Activator.CreateInstance(genericType, args);
items.Add(item);
// only read as many items as there are tokens left
var args = ReadJsonArray(token, unwrappedType, count - total);

if (args != null && args.Count > 0)
{
var genericType = typeof(OneOrMany<>).MakeGenericType(type);
var item = (IValues)Activator.CreateInstance(genericType, args);
items.Add(item);

total += args.Count;

if (total >= count)
{
// if we have deserialized enough items as there are tokens, break
break;
}
}
}

argument = items;
Expand All @@ -99,11 +117,10 @@ public override object ReadJson(
for (var i = mainType.GenericTypeArguments.Length - 1; i >= 0; i--)
{
var type = mainType.GenericTypeArguments[i];
object args = null;

try
{
args = ParseTokenArguments(token, tokenType, type, value);
var args = ParseTokenArguments(token, tokenType, type, value);

if (args != null)
{
Expand Down Expand Up @@ -209,7 +226,7 @@ private static object ParseTokenArguments(JToken token, JsonToken tokenType, Typ
{
const string SCHEMA_ORG = "http://schema.org/";
const int SCHEMA_ORG_LENGTH = 18; // equivalent to "http://schema.org/".Length
object args = null;
object args;
var unwrappedType = type.GetUnderlyingTypeFromNullable();
if (unwrappedType.GetTypeInfo().IsEnum)
{
Expand Down Expand Up @@ -434,53 +451,58 @@ private static Type ToClass(Type type)
return type;
}

private static object ReadJsonArray(JToken token, Type type)
private static IList ReadJsonArray(JToken token, Type type, int? count = null)
{
var classType = ToClass(type);
var listType = typeof(List<>).MakeGenericType(classType);
var listType = typeof(List<>).MakeGenericType(type); // always read into list of interfaces
var list = Activator.CreateInstance(listType);
var i = 0;

if (count == null)
{
// if maximum item count not assigned, set to count of child tokens
count = token.Children().Count();
}

foreach (var childToken in token.Children())
{
var typeName = GetTypeNameFromToken(childToken);
if (string.IsNullOrEmpty(typeName))
{
var item = childToken.ToObject(classType);
listType
.GetRuntimeMethod(nameof(List<object>.Add), new[] { classType })
.Invoke(list, new object[] { item });
var child = childToken.ToObject(classType);
var method = listType.GetRuntimeMethod(nameof(List<object>.Add), new[] { classType });

if (method != null)
{
method.Invoke(list, new object[] { child });

i++;
}
}
else
{
var builtType = Type.GetType($"{NamespacePrefix}{typeName}");
if (builtType != null && GetTypeHierarchy(builtType).Any(x => x == classType))
if (builtType != null && type.GetTypeInfo().IsAssignableFrom(builtType.GetTypeInfo()))
{
var child = (Thing)childToken.ToObject(builtType);
listType
.GetRuntimeMethod(nameof(List<object>.Add), new[] { classType })
.Invoke(list, new object[] { child });
var method = listType.GetRuntimeMethod(nameof(List<object>.Add), new[] { classType });

if (method != null)
{
method.Invoke(list, new object[] { child });

i++;
}
}
}
}

return list;
}

private static IEnumerable<Type> GetTypeHierarchy(Type type)
{
if (type == null)
{
yield break;
if (i == count)
{
break;
}
}

yield return type;

var baseType = type.GetTypeInfo().BaseType;
while (baseType != null)
{
yield return baseType;
baseType = baseType.GetTypeInfo().BaseType;
}
return (IList)list;
}

private static string GetTypeNameFromToken(JToken token)
Expand Down
2 changes: 1 addition & 1 deletion Source/Schema.NET/core/ItemList.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Schema.NET
namespace Schema.NET
{
using System;
using System.Runtime.Serialization;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Schema.NET
namespace Schema.NET
{
using System;
using System.Runtime.Serialization;
Expand Down
5 changes: 4 additions & 1 deletion Source/Schema.NET/core/enumerations/ActionStatusType.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
namespace Schema.NET
namespace Schema.NET
{
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

/// <summary>
/// The status of an Action.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum ActionStatusType
{
/// <summary>
Expand Down
5 changes: 4 additions & 1 deletion Source/Schema.NET/core/enumerations/BedType.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
namespace Schema.NET
namespace Schema.NET
{
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

/// <summary>
/// A type of bed. This is used for indicating the bed or beds available in an accommodation.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum BedType
{
}
Expand Down
5 changes: 4 additions & 1 deletion Source/Schema.NET/core/enumerations/BoardingPolicyType.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
namespace Schema.NET
namespace Schema.NET
{
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

/// <summary>
/// A type of boarding policy used by an airline.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum BoardingPolicyType
{
/// <summary>
Expand Down
5 changes: 4 additions & 1 deletion Source/Schema.NET/core/enumerations/BookFormatType.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
namespace Schema.NET
namespace Schema.NET
{
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

/// <summary>
/// The publication format of the book.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum BookFormatType
{
/// <summary>
Expand Down
5 changes: 4 additions & 1 deletion Source/Schema.NET/core/enumerations/BusinessEntityType.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
namespace Schema.NET
namespace Schema.NET
{
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

/// <summary>
/// A business entity type is a conceptual entity representing the legal form, the size, the main line of business, the position in the value chain, or any combination thereof, of an organization or business person.&lt;br/&gt;&lt;br/&gt;
Expand All @@ -12,6 +14,7 @@
/// &lt;li&gt;http://purl.org/goodrelations/v1#Reseller&lt;/li&gt;
/// &lt;/ul&gt;
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum BusinessEntityType
{
}
Expand Down
5 changes: 4 additions & 1 deletion Source/Schema.NET/core/enumerations/BusinessFunction.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
namespace Schema.NET
namespace Schema.NET
{
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

/// <summary>
/// The business function specifies the type of activity or access (i.e., the bundle of rights) offered by the organization or business person through the offer. Typical are sell, rental or lease, maintenance or repair, manufacture / produce, recycle / dispose, engineering / construction, or installation. Proprietary specifications of access rights are also instances of this class.&lt;br/&gt;&lt;br/&gt;
Expand All @@ -16,6 +18,7 @@
/// &lt;li&gt;http://purl.org/goodrelations/v1#Buy&lt;/li&gt;
/// &lt;/ul&gt;
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum BusinessFunction
{
}
Expand Down
5 changes: 4 additions & 1 deletion Source/Schema.NET/core/enumerations/ContactPointOption.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
namespace Schema.NET
namespace Schema.NET
{
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

/// <summary>
/// Enumerated options related to a ContactPoint.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum ContactPointOption
{
/// <summary>
Expand Down
5 changes: 4 additions & 1 deletion Source/Schema.NET/core/enumerations/CreditCard.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
namespace Schema.NET
namespace Schema.NET
{
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

/// <summary>
/// A card payment method of a particular brand or name. Used to mark up a particular payment method and/or the financial product/service that supplies the card account.&lt;br/&gt;&lt;br/&gt;
Expand All @@ -14,6 +16,7 @@
/// &lt;li&gt;http://purl.org/goodrelations/v1#VISA&lt;/li&gt;
/// &lt;/ul&gt;
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum CreditCard
{
}
Expand Down
5 changes: 4 additions & 1 deletion Source/Schema.NET/core/enumerations/DayOfWeek.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
namespace Schema.NET
namespace Schema.NET
{
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

/// <summary>
/// The day of the week, e.g. used to specify to which day the opening hours of an OpeningHoursSpecification refer.&lt;br/&gt;&lt;br/&gt;
/// Originally, URLs from &lt;a href="http://purl.org/goodrelations/v1"&gt;GoodRelations&lt;/a&gt; were used (for &lt;a class="localLink" href="http://schema.org/Monday"&gt;Monday&lt;/a&gt;, &lt;a class="localLink" href="http://schema.org/Tuesday"&gt;Tuesday&lt;/a&gt;, &lt;a class="localLink" href="http://schema.org/Wednesday"&gt;Wednesday&lt;/a&gt;, &lt;a class="localLink" href="http://schema.org/Thursday"&gt;Thursday&lt;/a&gt;, &lt;a class="localLink" href="http://schema.org/Friday"&gt;Friday&lt;/a&gt;, &lt;a class="localLink" href="http://schema.org/Saturday"&gt;Saturday&lt;/a&gt;, &lt;a class="localLink" href="http://schema.org/Sunday"&gt;Sunday&lt;/a&gt; plus a special entry for &lt;a class="localLink" href="http://schema.org/PublicHolidays"&gt;PublicHolidays&lt;/a&gt;); these have now been integrated directly into schema.org.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum DayOfWeek
{
/// <summary>
Expand Down
5 changes: 4 additions & 1 deletion Source/Schema.NET/core/enumerations/DeliveryMethod.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
namespace Schema.NET
namespace Schema.NET
{
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

/// <summary>
/// A delivery method is a standardized procedure for transferring the product or service to the destination of fulfillment chosen by the customer. Delivery methods are characterized by the means of transportation used, and by the organization or group that is the contracting party for the sending organization or person.&lt;br/&gt;&lt;br/&gt;
Expand All @@ -16,6 +18,7 @@
/// &lt;li&gt;http://purl.org/goodrelations/v1#UPS&lt;/li&gt;
/// &lt;/ul&gt;
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum DeliveryMethod
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
namespace Schema.NET
namespace Schema.NET
{
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

/// <summary>
/// A type of permission which can be granted for accessing a digital document.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum DigitalDocumentPermissionType
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
namespace Schema.NET
namespace Schema.NET
{
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

/// <summary>
/// A value indicating which roadwheels will receive torque.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum DriveWheelConfigurationValue
{
/// <summary>
Expand Down
5 changes: 4 additions & 1 deletion Source/Schema.NET/core/enumerations/DrugClass.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
namespace Schema.NET
namespace Schema.NET
{
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

/// <summary>
/// A class of medical drugs, e.g., statins. Classes can represent general pharmacological class, common mechanisms of action, common physiological effects, etc.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum DrugClass
{
}
Expand Down
5 changes: 4 additions & 1 deletion Source/Schema.NET/core/enumerations/DrugCost.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
namespace Schema.NET
namespace Schema.NET
{
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

/// <summary>
/// The cost per unit of a medical drug. Note that this type is not meant to represent the price in an offer of a drug for sale; see the Offer type for that. This type will typically be used to tag wholesale or average retail cost of a drug, or maximum reimbursable cost. Costs of medical drugs vary widely depending on how and where they are paid for, so while this type captures some of the variables, costs should be used with caution by consumers of this schema's markup.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum DrugCost
{
}
Expand Down
Loading