Avoid infinite recursive loop with looped or self referencing object structures.

This commit is contained in:
2017-11-15 16:07:21 +01:00
parent 096267cebc
commit 5bf8b85416

View File

@@ -25,30 +25,36 @@ namespace VAR.Json
public JsonWriter(int indentChars) public JsonWriter(int indentChars)
{ {
this._indent = true; _indent = true;
this._indentChars = indentChars; _indentChars = indentChars;
this._useTabForIndent = false; _useTabForIndent = false;
} }
public JsonWriter(bool useTabForIndent) public JsonWriter(bool useTabForIndent)
{ {
this._indent = true; _indent = true;
this._useTabForIndent = useTabForIndent; _useTabForIndent = useTabForIndent;
} }
#endregion Creator #endregion Creator
#region Private methods #region Private methods
private bool IsValue(Object obj) private bool IsValue(object obj)
{ {
if (obj == null) if (obj == null)
{ {
return true; return true;
} }
if ((obj is float) || (obj is double) || if (
(obj is System.Int16) || (obj is System.Int32) || (obj is System.Int64) (obj is float) ||
|| (obj is String) || (obj is Boolean)) (obj is double) ||
(obj is short) ||
(obj is int) ||
(obj is long) ||
(obj is string) ||
(obj is bool) ||
false)
{ {
return true; return true;
} }
@@ -95,28 +101,33 @@ namespace VAR.Json
sbOutput.Append('"'); sbOutput.Append('"');
} }
private void WriteValue(StringBuilder sbOutput, Object obj, int level, bool useReflection) private void WriteValue(StringBuilder sbOutput, object obj, List<object> parentLevels, bool useReflection)
{ {
if (obj == null || obj is DBNull) if (obj == null || obj is DBNull)
{ {
// NULL // NULL
sbOutput.Append("null"); sbOutput.Append("null");
} }
else if ((obj is float) || (obj is double) || else if (
(obj is System.Int16) || (obj is System.Int32) || (obj is System.Int64)) (obj is float) ||
(obj is double) ||
(obj is short) ||
(obj is int) ||
(obj is long) ||
false)
{ {
// Numbers // Numbers
sbOutput.Append(obj.ToString()); sbOutput.Append(obj.ToString());
} }
else if (obj is String) else if (obj is string)
{ {
// Strings // Strings
WriteString(sbOutput, (String)obj); WriteString(sbOutput, (string)obj);
} }
else if (obj is Boolean) else if (obj is bool)
{ {
// Booleans // Booleans
sbOutput.Append(((Boolean)obj) ? "true" : "false"); sbOutput.Append(((bool)obj) ? "true" : "false");
} }
else if (obj is DateTime) else if (obj is DateTime)
{ {
@@ -128,19 +139,19 @@ namespace VAR.Json
else if (obj is IDictionary) else if (obj is IDictionary)
{ {
// Objects // Objects
WriteObject(sbOutput, obj, level); WriteObject(sbOutput, obj, parentLevels);
} }
else if (obj is IEnumerable) else if (obj is IEnumerable)
{ {
// Array/List // Array/List
WriteList(sbOutput, obj, level); WriteList(sbOutput, obj, parentLevels);
} }
else else
{ {
if (useReflection) if (useReflection)
{ {
// Reflected object // Reflected object
WriteReflectedObject(sbOutput, obj, level); WriteReflectedObject(sbOutput, obj, parentLevels);
} }
else else
{ {
@@ -149,7 +160,7 @@ namespace VAR.Json
} }
} }
private void WriteList(StringBuilder sbOutput, Object obj, int level) private void WriteList(StringBuilder sbOutput, object obj, List<object> parentLevels)
{ {
IEnumerable list = (IEnumerable)obj; IEnumerable list = (IEnumerable)obj;
int n = 0; int n = 0;
@@ -177,7 +188,7 @@ namespace VAR.Json
sbOutput.Append("[ "); sbOutput.Append("[ ");
if (!isLeaf || n > _indentThresold) if (!isLeaf || n > _indentThresold)
{ {
WriteIndent(sbOutput, level + 1); WriteIndent(sbOutput, parentLevels.Count + 1);
} }
foreach (object childObj in list) foreach (object childObj in list)
{ {
@@ -186,20 +197,22 @@ namespace VAR.Json
sbOutput.Append(", "); sbOutput.Append(", ");
if (!isLeaf || n > _indentThresold) if (!isLeaf || n > _indentThresold)
{ {
WriteIndent(sbOutput, level + 1); WriteIndent(sbOutput, parentLevels.Count + 1);
} }
} }
first = false; first = false;
WriteValue(sbOutput, childObj, level + 1, true); parentLevels.Add(obj);
WriteValue(sbOutput, childObj, parentLevels, true);
parentLevels.Remove(obj);
} }
if (!isLeaf || n > _indentThresold) if (!isLeaf || n > _indentThresold)
{ {
WriteIndent(sbOutput, level); WriteIndent(sbOutput, parentLevels.Count);
} }
sbOutput.Append(" ]"); sbOutput.Append(" ]");
} }
private void WriteObject(StringBuilder sbOutput, Object obj, int level) private void WriteObject(StringBuilder sbOutput, object obj, List<object> parentLevels)
{ {
IDictionary map = (IDictionary)obj; IDictionary map = (IDictionary)obj;
int n = map.Count; int n = map.Count;
@@ -227,7 +240,7 @@ namespace VAR.Json
sbOutput.Append("{ "); sbOutput.Append("{ ");
if (!isLeaf || n > _indentThresold) if (!isLeaf || n > _indentThresold)
{ {
WriteIndent(sbOutput, level + 1); WriteIndent(sbOutput, parentLevels.Count + 1);
} }
foreach (object key in map.Keys) foreach (object key in map.Keys)
{ {
@@ -237,32 +250,33 @@ namespace VAR.Json
sbOutput.Append(", "); sbOutput.Append(", ");
if (!isLeaf || n > _indentThresold) if (!isLeaf || n > _indentThresold)
{ {
WriteIndent(sbOutput, level + 1); WriteIndent(sbOutput, parentLevels.Count + 1);
} }
} }
first = false; first = false;
WriteString(sbOutput, Convert.ToString(key)); WriteString(sbOutput, Convert.ToString(key));
sbOutput.Append(": "); sbOutput.Append(": ");
WriteValue(sbOutput, value, level + 1, true); parentLevels.Add(obj);
WriteValue(sbOutput, value, parentLevels, true);
parentLevels.Remove(obj);
} }
if (!isLeaf || n > _indentThresold) if (!isLeaf || n > _indentThresold)
{ {
WriteIndent(sbOutput, level); WriteIndent(sbOutput, parentLevels.Count);
} }
sbOutput.Append(" }"); sbOutput.Append(" }");
} }
private void WriteReflectedObject(StringBuilder sbOutput, Object obj, int level) private void WriteReflectedObject(StringBuilder sbOutput, object obj, List<object> parentLevels)
{ {
Type type = obj.GetType(); Type type = obj.GetType();
PropertyInfo[] rawProperties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); PropertyInfo[] rawProperties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
List<PropertyInfo> properties = new List<PropertyInfo>(); List<PropertyInfo> properties = new List<PropertyInfo>();
foreach (PropertyInfo property in rawProperties) foreach (PropertyInfo property in rawProperties)
{ {
if (property.CanRead) if (property.CanRead == false) { continue; }
{
properties.Add(property); properties.Add(property);
}
} }
int n = properties.Count; int n = properties.Count;
@@ -290,7 +304,7 @@ namespace VAR.Json
sbOutput.Append("{ "); sbOutput.Append("{ ");
if (!isLeaf || n > _indentThresold) if (!isLeaf || n > _indentThresold)
{ {
WriteIndent(sbOutput, level + 1); WriteIndent(sbOutput, parentLevels.Count + 1);
} }
foreach (PropertyInfo property in properties) foreach (PropertyInfo property in properties)
{ {
@@ -306,17 +320,26 @@ namespace VAR.Json
sbOutput.Append(", "); sbOutput.Append(", ");
if (!isLeaf || n > _indentThresold) if (!isLeaf || n > _indentThresold)
{ {
WriteIndent(sbOutput, level + 1); WriteIndent(sbOutput, parentLevels.Count + 1);
} }
} }
first = false; first = false;
WriteString(sbOutput, property.Name); WriteString(sbOutput, property.Name);
sbOutput.Append(": "); sbOutput.Append(": ");
WriteValue(sbOutput, value, level + 1, false); parentLevels.Add(obj);
if (value != obj && parentLevels.Contains(value) == false)
{
WriteValue(sbOutput, value, parentLevels, false);
}
else
{
WriteValue(sbOutput, null, parentLevels, false);
}
parentLevels.Remove(obj);
} }
if (!isLeaf || n > _indentThresold) if (!isLeaf || n > _indentThresold)
{ {
WriteIndent(sbOutput, level); WriteIndent(sbOutput, parentLevels.Count);
} }
sbOutput.Append(" }"); sbOutput.Append(" }");
} }
@@ -325,10 +348,10 @@ namespace VAR.Json
#region Public methods #region Public methods
public String Write(Object obj) public string Write(object obj)
{ {
StringBuilder sbOutput = new StringBuilder(); StringBuilder sbOutput = new StringBuilder();
WriteValue(sbOutput, obj, 0, true); WriteValue(sbOutput, obj, new List<object>(), true);
return sbOutput.ToString(); return sbOutput.ToString();
} }