Guest User

Untitled

a guest
Dec 10th, 2018
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.79 KB | None | 0 0
  1. public abstract class ReferenceHandlingCustomCreationConverter<T> : JsonConverter where T : class
  2. {
  3. const string refProperty = "$ref";
  4. const string idProperty = "$id";
  5.  
  6. public override bool CanConvert(Type objectType)
  7. {
  8. return typeof(T).IsAssignableFrom(objectType);
  9. }
  10.  
  11. protected virtual T Create(Type objectType, T existingValue, JsonSerializer serializer, JObject obj)
  12. {
  13. return existingValue ?? (T)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
  14. }
  15.  
  16. protected abstract void Populate(JObject obj, T value, JsonSerializer serializer);
  17.  
  18. protected abstract void WriteProperties(JsonWriter writer, T value, JsonSerializer serializer, JsonObjectContract contract);
  19.  
  20. public override sealed object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
  21. {
  22. var contract = serializer.ContractResolver.ResolveContract(objectType);
  23. if (!(contract is JsonObjectContract))
  24. {
  25. throw new JsonSerializationException(string.Format("Invalid non-object contract type {0}", contract));
  26. }
  27. if (!(existingValue == null || existingValue is T))
  28. {
  29. throw new JsonSerializationException(string.Format("Converter cannot read JSON with the specified existing value. {0} is required.", typeof(T)));
  30. }
  31.  
  32. if (reader.MoveToContent().TokenType == JsonToken.Null)
  33. return null;
  34. var obj = JObject.Load(reader);
  35.  
  36. var refId = (string)obj[refProperty].RemoveFromLowestPossibleParent();
  37. var objId = (string)obj[idProperty].RemoveFromLowestPossibleParent();
  38. if (refId != null)
  39. {
  40. var reference = serializer.ReferenceResolver.ResolveReference(serializer, refId);
  41. if (reference != null)
  42. return reference;
  43. }
  44.  
  45. var value = Create(objectType, (T)existingValue, serializer, obj);
  46.  
  47. if (objId != null)
  48. {
  49. // Add the empty array into the reference table BEFORE poppulating it, to handle recursive references.
  50. serializer.ReferenceResolver.AddReference(serializer, objId, value);
  51. }
  52.  
  53. Populate(obj, value, serializer);
  54.  
  55. return value;
  56. }
  57.  
  58. public override sealed void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
  59. {
  60. var contract = serializer.ContractResolver.ResolveContract(value.GetType());
  61. if (!(contract is JsonObjectContract))
  62. {
  63. throw new JsonSerializationException(string.Format("Invalid non-object contract type {0}", contract));
  64. }
  65. if (!(value is T))
  66. {
  67. throw new JsonSerializationException(string.Format("Converter cannot read JSON with the specified existing value. {0} is required.", typeof(T)));
  68. }
  69.  
  70. writer.WriteStartObject();
  71.  
  72. if (serializer.ReferenceResolver.IsReferenced(serializer, value))
  73. {
  74. writer.WritePropertyName(refProperty);
  75. writer.WriteValue(serializer.ReferenceResolver.GetReference(serializer, value));
  76. }
  77. else
  78. {
  79. writer.WritePropertyName(idProperty);
  80. writer.WriteValue(serializer.ReferenceResolver.GetReference(serializer, value));
  81.  
  82. WriteProperties(writer, (T)value, serializer, (JsonObjectContract)contract);
  83. }
  84.  
  85. writer.WriteEndObject();
  86. }
  87. }
  88.  
  89. public static partial class JsonExtensions
  90. {
  91. public static JsonReader MoveToContent(this JsonReader reader)
  92. {
  93. if (reader.TokenType == JsonToken.None)
  94. reader.Read();
  95. while (reader.TokenType == JsonToken.Comment && reader.Read())
  96. ;
  97. return reader;
  98. }
  99.  
  100. public static JToken RemoveFromLowestPossibleParent(this JToken node)
  101. {
  102. if (node == null)
  103. return null;
  104. var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault();
  105. if (contained != null)
  106. contained.Remove();
  107. // Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should
  108. if (node.Parent is JProperty)
  109. ((JProperty)node.Parent).Value = null;
  110. return node;
  111. }
  112. }
  113.  
  114. protected abstract void Populate(JObject obj, T value, JsonSerializer serializer);
  115.  
  116. protected abstract void WriteProperties(JsonWriter writer, T value, JsonSerializer serializer, JsonObjectContract contract);
  117.  
  118. public class DefaultReferenceHandlingCustomCreationConverter<T> : ReferenceHandlingCustomCreationConverter<T> where T : class
  119. {
  120. protected override void Populate(JObject obj, T value, JsonSerializer serializer)
  121. {
  122. using (var reader = obj.CreateReader())
  123. serializer.Populate(reader, value);
  124. }
  125.  
  126. protected override void WriteProperties(JsonWriter writer, T value, JsonSerializer serializer, JsonObjectContract contract)
  127. {
  128. foreach (var property in contract.Properties.Where(p => p.Writable && !p.Ignored))
  129. {
  130. // TODO: handle JsonProperty attributes including
  131. // property.Converter, property.IsReference, property.ItemConverter, property.ItemReferenceLoopHandling,
  132. // property.ItemReferenceLoopHandling, property.ObjectCreationHandling, property.ReferenceLoopHandling, property.Required
  133. var itemValue = property.ValueProvider.GetValue(value);
  134. writer.WritePropertyName(property.PropertyName);
  135. serializer.Serialize(writer, itemValue);
  136. }
  137. }
  138. }
  139.  
  140. var settings = new JsonSerializerSettings
  141. {
  142. Converters = { new DefaultReferenceHandlingCustomCreationConverter<RootObject>() },
  143. ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
  144. };
  145. var json = JsonConvert.SerializeObject(parent, Formatting.Indented, settings);
Add Comment
Please, Sign In to add comment