Extracted JsonNameTable for JsonTextReader (#1703)
This commit is contained in:
committed by
James Newton-King
parent
ebadeaf8e5
commit
2d5eba5599
@@ -174,11 +174,11 @@ namespace Newtonsoft.Json.Tests
|
||||
reader.Read();
|
||||
|
||||
JsonTextReader jsonTextReader = (JsonTextReader)reader;
|
||||
Assert.IsNotNull(jsonTextReader.NameTable);
|
||||
Assert.IsNotNull(jsonTextReader.PropertyNameTable);
|
||||
|
||||
string s = serializer.Deserialize<string>(reader);
|
||||
Assert.AreEqual("hi", s);
|
||||
Assert.IsNotNull(jsonTextReader.NameTable);
|
||||
Assert.IsNotNull(jsonTextReader.PropertyNameTable);
|
||||
|
||||
NameTableTestClass o = new NameTableTestClass
|
||||
{
|
||||
@@ -200,16 +200,40 @@ namespace Newtonsoft.Json.Tests
|
||||
StringReader sr = new StringReader("{'property':'hi'}");
|
||||
JsonTextReader jsonTextReader = new JsonTextReader(sr);
|
||||
|
||||
Assert.IsNull(jsonTextReader.NameTable);
|
||||
Assert.IsNull(jsonTextReader.PropertyNameTable);
|
||||
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
serializer.Converters.Add(new NameTableTestClassConverter());
|
||||
NameTableTestClass o = serializer.Deserialize<NameTableTestClass>(jsonTextReader);
|
||||
|
||||
Assert.IsNull(jsonTextReader.NameTable);
|
||||
Assert.IsNull(jsonTextReader.PropertyNameTable);
|
||||
Assert.AreEqual("hi", o.Value);
|
||||
}
|
||||
|
||||
public class CustonNameTable : JsonNameTable
|
||||
{
|
||||
public override string Get(char[] key, int start, int length)
|
||||
{
|
||||
return "_" + new string(key, start, length);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CustonNameTableTest()
|
||||
{
|
||||
StringReader sr = new StringReader("{'property':'hi'}");
|
||||
JsonTextReader jsonTextReader = new JsonTextReader(sr);
|
||||
|
||||
Assert.IsNull(jsonTextReader.PropertyNameTable);
|
||||
var nameTable = jsonTextReader.PropertyNameTable = new CustonNameTable();
|
||||
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
Dictionary<string, string> o = serializer.Deserialize<Dictionary<string, string>>(jsonTextReader);
|
||||
Assert.AreEqual("hi", o["_property"]);
|
||||
|
||||
Assert.AreEqual(nameTable, jsonTextReader.PropertyNameTable);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DefaultSettings_Example()
|
||||
{
|
||||
|
||||
+22
-5
@@ -25,9 +25,12 @@
|
||||
|
||||
using System;
|
||||
|
||||
namespace Newtonsoft.Json.Utilities
|
||||
namespace Newtonsoft.Json
|
||||
{
|
||||
internal class PropertyNameTable
|
||||
/// <summary>
|
||||
/// The default JSON name table implementation.
|
||||
/// </summary>
|
||||
public class DefaultJsonNameTable : JsonNameTable
|
||||
{
|
||||
// used to defeat hashtable DoS attack where someone passes in lots of strings that hash to the same hash code
|
||||
private static readonly int HashCodeRandomizer;
|
||||
@@ -36,17 +39,26 @@ namespace Newtonsoft.Json.Utilities
|
||||
private Entry[] _entries;
|
||||
private int _mask = 31;
|
||||
|
||||
static PropertyNameTable()
|
||||
static DefaultJsonNameTable()
|
||||
{
|
||||
HashCodeRandomizer = Environment.TickCount;
|
||||
}
|
||||
|
||||
public PropertyNameTable()
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DefaultJsonNameTable"/> class.
|
||||
/// </summary>
|
||||
public DefaultJsonNameTable()
|
||||
{
|
||||
_entries = new Entry[_mask + 1];
|
||||
}
|
||||
|
||||
public string Get(char[] key, int start, int length)
|
||||
/// <summary>
|
||||
/// Gets the string containing the same characters as the specified range of characters in the given array.
|
||||
/// </summary>
|
||||
/// <param name="key">The character array containing the name to find.</param>
|
||||
/// <param name="start">The zero-based index into the array specifying the first character of the name.</param>
|
||||
/// <param name="length">The number of characters in the name.</param>
|
||||
public override string Get(char[] key, int start, int length)
|
||||
{
|
||||
if (length == 0)
|
||||
{
|
||||
@@ -74,6 +86,11 @@ namespace Newtonsoft.Json.Utilities
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified string into name table.
|
||||
/// </summary>
|
||||
/// <param name="key">The string to add.</param>
|
||||
/// <remarks>This method is not thread-safe.</remarks>
|
||||
public string Add(string key)
|
||||
{
|
||||
if (key == null)
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Newtonsoft.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for a table of atomized string objects.
|
||||
/// </summary>
|
||||
public abstract class JsonNameTable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the string containing the same characters as the specified range of characters in the given array.
|
||||
/// </summary>
|
||||
/// <param name="key">The character array containing the name to find.</param>
|
||||
/// <param name="start">The zero-based index into the array specifying the first character of the name.</param>
|
||||
/// <param name="length">The number of characters in the name.</param>
|
||||
public abstract string Get(char[] key, int start, int length);
|
||||
}
|
||||
}
|
||||
@@ -974,9 +974,9 @@ namespace Newtonsoft.Json
|
||||
|
||||
if (reader is JsonTextReader textReader)
|
||||
{
|
||||
if (_contractResolver is DefaultContractResolver resolver)
|
||||
if (textReader.PropertyNameTable == null && _contractResolver is DefaultContractResolver resolver)
|
||||
{
|
||||
textReader.NameTable = resolver.GetNameTable();
|
||||
textReader.PropertyNameTable = resolver.GetNameTable();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1009,9 +1009,10 @@ namespace Newtonsoft.Json
|
||||
reader.DateFormatString = previousDateFormatString;
|
||||
}
|
||||
|
||||
if (reader is JsonTextReader textReader)
|
||||
if (reader is JsonTextReader textReader && textReader.PropertyNameTable != null &&
|
||||
_contractResolver is DefaultContractResolver resolver && textReader.PropertyNameTable == resolver.GetNameTable())
|
||||
{
|
||||
textReader.NameTable = null;
|
||||
textReader.PropertyNameTable = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -979,9 +979,9 @@ namespace Newtonsoft.Json
|
||||
|
||||
string propertyName;
|
||||
|
||||
if (NameTable != null)
|
||||
if (PropertyNameTable != null)
|
||||
{
|
||||
propertyName = NameTable.Get(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length)
|
||||
propertyName = PropertyNameTable.Get(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length)
|
||||
// no match in name table
|
||||
?? _stringReference.ToString();
|
||||
}
|
||||
|
||||
@@ -74,7 +74,6 @@ namespace Newtonsoft.Json
|
||||
private StringBuffer _stringBuffer;
|
||||
private StringReference _stringReference;
|
||||
private IArrayPool<char> _arrayPool;
|
||||
internal PropertyNameTable NameTable;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JsonTextReader"/> class with the specified <see cref="TextReader"/>.
|
||||
@@ -105,6 +104,11 @@ namespace Newtonsoft.Json
|
||||
internal int CharPos => _charPos;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the reader's property name table.
|
||||
/// </summary>
|
||||
public JsonNameTable PropertyNameTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the reader's character buffer pool.
|
||||
/// </summary>
|
||||
@@ -1563,9 +1567,9 @@ namespace Newtonsoft.Json
|
||||
|
||||
string propertyName;
|
||||
|
||||
if (NameTable != null)
|
||||
if (PropertyNameTable != null)
|
||||
{
|
||||
propertyName = NameTable.Get(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length);
|
||||
propertyName = PropertyNameTable.Get(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length);
|
||||
|
||||
// no match in name table
|
||||
if (propertyName == null)
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
public class CamelCasePropertyNamesContractResolver : DefaultContractResolver
|
||||
{
|
||||
private static readonly object TypeContractCacheLock = new object();
|
||||
private static readonly PropertyNameTable NameTable = new PropertyNameTable();
|
||||
private static readonly DefaultJsonNameTable NameTable = new DefaultJsonNameTable();
|
||||
private static Dictionary<ResolverContractKey, JsonContract> _contractCache;
|
||||
|
||||
/// <summary>
|
||||
@@ -119,7 +119,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
return contract;
|
||||
}
|
||||
|
||||
internal override PropertyNameTable GetNameTable()
|
||||
internal override DefaultJsonNameTable GetNameTable()
|
||||
{
|
||||
return NameTable;
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
new RegexConverter()
|
||||
};
|
||||
|
||||
private readonly PropertyNameTable _nameTable = new PropertyNameTable();
|
||||
private readonly DefaultJsonNameTable _nameTable = new DefaultJsonNameTable();
|
||||
|
||||
private readonly ThreadSafeStore<Type, JsonContract> _contractCache;
|
||||
|
||||
@@ -1334,7 +1334,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
throw new JsonSerializationException("Null collection of serializable members returned.");
|
||||
}
|
||||
|
||||
PropertyNameTable nameTable = GetNameTable();
|
||||
DefaultJsonNameTable nameTable = GetNameTable();
|
||||
|
||||
JsonPropertyCollection properties = new JsonPropertyCollection(type);
|
||||
|
||||
@@ -1358,7 +1358,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
return orderedProperties;
|
||||
}
|
||||
|
||||
internal virtual PropertyNameTable GetNameTable()
|
||||
internal virtual DefaultJsonNameTable GetNameTable()
|
||||
{
|
||||
return _nameTable;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user