|
|
Comments and Discussions
|
|
 |

|
I have fixed this issue in v2.0.11.
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|
|

|
Thanks!
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|
|

|
When checking for the presence of attributes, you'll want to use IsDefined, rather than GetCustomAttributes.
MSDN[^]
It is about 4x times faster than using GetCustomAttributes.
|
|
|
|

|
Thanks Andrew!
Although fastJSON only does this once per type but still anything that goes faster is good
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|

|
See below as well... a few more suggestions.
|
|
|
|

|
Take the following with a grain of salt, I'm looking over the code fairly quickly, so I might miss obvious things.
-SafeDictionary - Why have an internal class contain locks, especially on an instance level? I'd imagine that serializing/deserializing a string should not run into multi-threaded issues. Furthermore, you're breaking a standard expectation for .NET (static members are thread safe, while instance members are not). I think it would be safe enough to just use regular Dictionaries and rely on the user of your class to handle the locking properly. Otherwise, performance suffers for those not using in a multi-threaded way.
-Formatter.AppendIndent - Since you're just appending four spaces, you might want to use StringBuilder.Append(char, int) and just multiply count by 4. It'd likely be faster.
-JSON.ToObject - You have several calls to GetGenericTypeDefinition. You may want to cache that result off rather than calling it again and again.
-JSON.CreateMyProp - You may want to look at this[^]. You could do an initial test to see if the type is Nullable, get the underlying type and then reduce the number of checks that you have (ex. type.GetGenericArguments()[0]).
-myPropInfo - You spend time trying to find out what type something is. Why not instead of capturing that into a bool, capture a delegate to do something with it? It would reduce the amount of code you have and allow you to not pay the penalty of going over all the different types again. You could also use a factory pattern to create a concrete type (from an abstract base that defines the functionality) that handles it for the specific case. Either way would work.
|
|
|
|

|
I guess: SafeDictionary has locks because it is used by the JsonRegistry which is static. Therefore, multiple threads can access the dictionary at runtime. Since the dictionary is created and populated on demand (new type to parse etc), it should be thread-safe.
I have tried to replace SafeDictionary with the ConcurrentDictionary but this decreases portability a lot. In fact I believe that the JsonRegistry should not be static. Changing parameters can too easily lead to unexpected output:
1. Set IncludeReadOnly= false, serialize
2. Set IncludeReadOnly= true, serialize=> fails, since it uses the cache which was populated based on the previous definition (1).
Aron
|
|
|
|

|
Hi Andrew,
in my private version of FastJson I tried to implement your proposal in replacing the myPropInfo with a dictionary lookup. The outcome was devastating. The performance dropped about more than 200% in the given benchmark.
Interesting however is, that a combination if-else block (as-is) with a dictionary brings a significant bonus when exotic types are used.
You can check that version at: http://www.innotags.de/download/Apolyton.FastJSON.zip[^]
|
|
|
|

|
Interesting.
I wasn't recommending a dictionary for that portion, but rather to capture an action to perform instead of a set of multiple flags to determine what to do later.
|
|
|
|

|
If any one can make fastJSON faster I am all ears
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|

|
Hi Mehdi,
nice work! I run though into a problem, when I tried to deserialize a JSON into a polymporphic objects. My object model is similar to city => list<zoo> => list<animals>
Since I don't know what animals are within a zoo, I just have a type animal for each zoo. The problem is now, that only animals of type animal are created and not dogs, cats, etc.
Now, I would like to solve this problem through a custom type animal, in which I can check the supplied json for the necessary properties for each animal (dog barks, cat miaus, etc.)
The issue is now, that the current implementation (2.0.9) passes only a string to the custom deserializer and throws an error, if the custom type consist of multiple properties or additional object. I was now wondering if this could be changed to the passed parameter from string to a dictionary or full json object.
thanks for your feedback,
Chris
|
|
|
|

|
Thanks Chris!
"Custom Types" is intended for RECT, COLOR, ... etc. not for classes. fastJSON will automatically handle nested types for you if you have enabled the extensions (and given the dog inherits from animal).
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|

|
hi Mehdi,
thanks for the quick response. The Problem is that those nested types defined as follow in JSON:
A point:
{ "geometry" :
{ "x" : 2781859.5718259001,
"y" : 5104563.3898882624
}
A polygon:
{ "geometry":
{ "rings":
[
[
[123.445, 23.456],
[33.123, 23.4345,
[33.125, 23.4345,
[123.2342, 23.4345]
],
[
[123.445, 23.456],
[33.123, 23.4345,
[33.125, 23.4345,
[123.2342, 23.4345]
]
]
}
}
(PS: I know, this is not best way to do this, but it was given to me as such and can not be changed )
I would need now to create a GeometryPoint and GeometryPolygon object, which belongs to a dataset which has a property Geometry (which can be point or polygon).
==> Dataset.Geometry could be of type GeometryPoint or GeometryPolygon (and both inherite from the base type Geometry)
I believe, that for this purpose I would need a custom type with needs to be able to parse the appropriate JSON substrings, yet those substrings need to be passes as Dictionary. Therefore my question regarding the passed type.
Unless, there's another approache to this problem?
thanks for your help,
Chris
|
|
|
|

|
Ah! the data does not have the $type extensions...
Try the Parse() method instead, it will give you a dictionary and list of object collections.
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|

|
Hi Mehdi,
We are planning to use your work in our company. In that scope, I have done some major code review. For now, I can offer you two different packages, if you are interested: a small one and a big one.
The first is primarily focusing on the public API applies primarily minor code review changes. This should definitely a value to the community. Performance characterisics should not have been changed.
The second package is an intense review, in brief details:
- Harmonizing with .NET naming conventions
- Applying good principles like separation of concerns (with perf. in mind).
- Improving exception reporting
- Increasing flexibility of the framework: Property opt-in, Property opt-out. This should increase performance in real-life use cases.
- Small performance drop 1-3% (custo types always available)
- Unit test driven: all native serilization/ deserialization is tested (46+ Tests)
- 5+ Bug fixes
- Improved debugging capabilities
In the near future, I will have to make the basic funcionality again available under Silverlight 5. Which critical feature was removed by Microsoft?
Best Regards,
Aron
|
|
|
|

|
Thanks Aron!
Anything which doesn't break usage is most welcome (I would like to change somethings but it would break running code for people). Post your changes to me or you can fork the code for yourself and publish that way.
As for SL5, the code that doesn't exist is (in Reflection.cs):
...
DynamicMethod dynamicSet = new DynamicMethod("_", typeof(object), arguments, type, true);
...
I'm a bit put off by MS in this regard so I haven't put any time into creating a workaround for it.
[as a side note fastJSON works as is in MonoDroid, and I will publish soon ]
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|

|
Sorry Mehdi for the late response,
but I am quite busy during the week. For now, I don't want to post a public alternative. Therefore, I have uploaded the packages to a different server.
The first package was about code understanding and improving without changing or breaking stuff.
http://www.innotags.de/download/fastJSON.zip[^]
The second package is about bringing value to the code, improving and hardening it.
Performance:
===============================================
I have run additional performance tests on that package and I am not perfectly happy:
- I lost 10% during serialization. Maybe you could have a quick look, if there is an obvious mistake.
- Deserialization is equal, sometimes faster but not significally.
Abstract from the readme.txt
===============================================
The changes are basing on FastJSON 2.0.9
- All native non-exotic members are unit tested in serialization/ deserialization
- 'Json' class is tested with the complex class used for unit testing.
- NOT COVERED BY TESTS YET:
- JsonParameter interpretations
- $type support
- I had to change the namespace to something in order to be able to compare with FastJson 2.0.9
- The benchmark console app has also been adjusted slightly.
NEW FEATURES
===============================================
- Property Opt-in, Opt-out: See JsonParameter.SerializationPolicy. To be combined with DataMemberAttribute. I have choosen this attribute over Serializable attribute since the last is coming from System.Xml, DataMember from Runtime.Serialization. Performance hit first time the type is used.
- Added support DataMember.Name which allows to declaratively abstract the json field name from the property name which increases robustness of the resulting json protocol. It will also easy the case-insensitive implementation a lot I think. Performance hit first time the type is used.
- Added support for IgnoreDataMember. Useful for Opt-out scenarios. Performance hit first time the type is used.
- Added support for encoding, see JsonParameters.Encoding. Performance hit depending on the encoding used (no hit, if default encoding is used).
FIXED ISSUES
===============================================
- Benchmark: Using StopWatch instead of DateTime which is recommended to measure ellapsed time.
- JsonSerializer: DateTime to Utc is now respecting the kind of the datetime (JsonSerializer_DateTimeUtc)
- JsonSerializer: List of bytes was not properly serialized (see JsonSerializer_ByteEnumeration)
- JsonPropertyInfo.CanWrite (formerly named MyPropInfo) was always false for fields (should be always true).
- JsonPropertyInfo.Filled was never false. Returned by Reflection, which always sets it to true. Don't see the use of the variable. Removed.
- JsonPropertyInfo.GenericTypes was always null except for dictionaries with the name "Dictionary".
PENDING ISSUES
===============================================
- Benchmark mistake in BinaryFormatter: as you mention fastJSON based on streams is a lot slower. The BinaryFormatter consumes streams so it cannot directly be compared to FastJson. The use cases are different: in case of an http request for instance, the input value is 'stream' and not 'string'. In order to compare performance, the Json Benchmarks should also have the input value 'stream' and not string. The time to convert the input value have to be paid anyway -and it should be part of the FastJson Benchmark which is not the case.
- JsonDeserializer deserialization of byte[] is still failing, see Json_ByteEnumerationClass
- JsonRegistry is not threadsafe: changing ShowReadOnlyProperty has potential to corrupt running (de-)serializations. Should be removed. Unit tests reveal that the issue exists also in a single thread.
- There is a bug in the $type extension. It has a risk of return the wrong type. One can see it when exotic benchmark is run which will report an InvalidCastException.
Best Regards,
Aron
|
|
|
|

|
dynamic employee = new ExpandoObject();
employee.Name = "John Smith";
employee.Age = 33;
var manager = new ExpandoObject() as IDictionary<string, object>;
manager.Add("Name", "Allison Brown");
manager.Add("Age", 42);
Console.WriteLine(((string)fastJSON.JSON.Instance.ToJSON(employee)));
Console.WriteLine(fastJSON.JSON.Instance.ToJSON(manager));
Console.WriteLine(((string)ServiceStack.Text.JsonSerializer.SerializeToString(employee)));
Console.WriteLine(ServiceStack.Text.JsonSerializer.SerializeToString(manager));
Output:
{"$types":{"System.Dynamic.ExpandoObject, System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089":"1"},"$type":"1"}
{"$types":{"System.Dynamic.ExpandoObject, System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089":"1"},"$type":"1"}
["[Name, John Smith]","[Age, 33]"]
{"Name":"Allison Brown","Age":42}
|
|
|
|

|
Thanks Alexandre!
I have had a couple of requests for "dynamic" support.
PRO's:
- a better coding experience
- you don't need to create the containing class (less coding)
CON's:
- requires .net4+
- a bit slow
Having said that I may add it as a better Parse() method for .net 4+ compilations.
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|

|
I have a anoying problem.
I am getting this error now. It has been working before in other projects but not in my recent.
This is a test code that is thowing the error:
Public Class fastJSONBuggTestC
Public Settings As New SettingsC
Public Class SettingsC
Public Version As Integer = 1
Public RegistrationKey As String = "unknown"
End Class
Public Sub New()
Dim testSettings As New SettingsC()
Dim param As New fastJSON.JSONParameters()
param.IgnoreCaseOnDeserialize = True
param.SerializeNullValues = True
param.UseExtensions = True
param.UseFastGuid = True
param.UseOptimizedDatasetSchema = True
param.UseUTCDateTime = True
param.UsingGlobalTypes = True
Dim jsonString As String = fastJSON.JSON.Instance.ToJSON(Settings, param)
Settings = fastJSON.JSON.Instance.ToObject(jsonString)
End Sub
End Class
It is this row:
Settings = fastJSON.JSON.Instance.ToObject(jsonString)
that is throwing the error "Cannot determine type", anyone now why this is hapening now and not before?
Thanks!
Robin Andersson
|
|
|
|

|
Can you send me the JSON string generated?
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|

|
Extremely through and highly optimized
|
|
|
|

|
A couple of examples:
One:
["foo0",{"foo1":"C:\\!bar1","foo2":"C:\\bar2"}]
[
"foo0",
{
"foo1" : "C:\\!bar1",
"foo2" : "C:\\bar2"}]
Two:
[{"foo":"'[0]"}]
[
{
"foo" : "'[
0
]"}]
|
|
|
|

|
Hi,
great work and I'd really appreciate it if you try to update the NuGet package regularly. So everyone can update to the latest version easyly.
Thanks a lot
|
|
|
|

|
I will try
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|

|
Thanks. 5-stars
|
|
|
|

|
like:
var arr2 = new[]{
new { Text = "M", Value = true},
new { Text = "F", Value = false }
};
var ttt = fastJSON.JSON.Instance.ToJSON(arr2, new fastJSON.JSONParameters() { UseExtensions = false });
the result is : "[{},{}]"
|
|
|
|

|
Actually it will serialize but *not* deserialize anonymous types, just set the EnableAnonymousTypes = true parameter.
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|

|
Hello,
I run the console test and it appears that deserialization of dataset is not working.
Was it working in a previous version?
Tkanks a lot.
|
|
|
|

|
What error are you getting?
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|

|
Thans for your answer.
The error is "Cannot determine type"
The code who provide error is:
ds = CreateDataset();
string text = fastJSON.JSON.Instance.ToJSON(ds);
DataSet ds2 = (DataSet)fastJSON.JSON.Instance.ToObject(text);
If the dataset is a property of an object, it's working.
But if the Dataset is the object it doens't work.
|
|
|
|

|
Root level deserialize of a dataset is not supported at the moment. The code will work fine if the dataset was in an object.
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|

|
I have added root level DataSet and DataTable support and will post shortly.
var ds = CreateDataset();
var s = fastJSON.JSON.Instance.ToJSON(ds);
var o = fastJSON.JSON.Instance.ToObject<DataSet>(s);
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|

|
For example i have code in c#:
public class TestB
{
public int b = 3;
public string c = "AA";
public TestB() { }
};
public class TestA
{
public int a = 0;
public TestB tb = new TestB();
public TestA() { }
};
void method()
{
WebRequest webRequest = WebRequest.Create("http://localhost/");
webRequest.ContentType = "application/json";
webRequest.Method = "POST";
TestA ta = new TestA();
string a = JSON.Instance.ToJSON(ta);
byte[] bytes = Encoding.UTF8.GetBytes(a);
Stream os = null;
webRequest.ContentLength = bytes.Length; os = webRequest.GetRequestStream();
os.Write(bytes, 0, bytes.Length);
if (os != null)
{
os.Close();
}
WebResponse webResponse = webRequest.GetResponse();
StreamReader sr = new StreamReader(webResponse.GetResponseStream());
string s = sr.ReadToEnd();
TestB tb = JSON.Instance.ToObject<TestB>(s);
}
and i have a server in php v. 5.3 to response this:
$data = file_get_contents("php://input");
$obj = json_decode($data);
$ret = json_encode($obj->tb);
$len = strlen($ret);
header("Content-length: $len");
echo $ret;
return;
So in the class is return inner value of class TestB (tb). Send is ok, it sends $types, and $type. But in return it send me:
{"$type":"2","b":3,"c":"AA"}
Doesn't send information about types ($types), and in your code the value of globaltypes
is empty because the return information is $types and code will have exception on line:
if (globaltypes.TryGetValue((string)tn, out tname))
tn = tname;
|
|
|
|

|
Hi, I have a exception while parsing a json string which contains numbers formatted as:
Points": [
{
"X": 0.1097,
"Y": 0,
"Z": 4.16366160299608e-18 // <- bug here
}
]
To fix it, in JSONParser.cs (line 308, function ParseNumber()) , replace:
return decimal.Parse(s,NumberFormatInfo.InvariantInfo);
with:
return Double.Parse(s,NumberFormatInfo.InvariantInfo);
Thanks.
Alex.
|
|
|
|

|
Unfortunately the GermanNumbers test fails with this.
I will try to find a work around.
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|

|
Fixed now in v2.0.8.
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|

|
Thanks !
I'll test it now.
|
|
|
|

|
First of all, thanks for sharing that little useful library! I just wonder why doesn't it support deserialization of arrays (admittedly, you can use List, but still)? The necessary code changes seem to be trivial.
Regards,
Andrew
|
|
|
|

|
Thanks Andrew!
The following works fine:
public class arrayclass
{
public int[] ints { get; set; }
public string[] strs;
}
[Test]
public static void ArrayTest()
{
arrayclass a = new arrayclass();
a.ints = new int[] { 3, 1, 4 };
a.strs = new string[] {"a","b","c"};
var s = fastJSON.JSON.Instance.ToJSON(a);
var o = fastJSON.JSON.Instance.ToObject(s);
}
I have added it to the unit tests.
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|
|

|
Good tips
|
|
|
|

|
¿It is possible to deserialize immutable classes?
If i have a class like this:
class Immutable
{
public Immutable( long id )
{
this.Id = id;
}
public long Id { get; private set; }
}
with JsonNet i must add a attribute to them and an empty constructor and leave the class like this:
class Immutable
{
[JsonConstructor]
private Immutable() : this(0) { }
public Immutable( long id )
{
this.Id = id;
}
[JsonProperty]
public long Id { get; private set; }
}
Thanks
Iker eL_FRuTeRo
|
|
|
|

|
You don't need any attributes with fastJSON, but a default constructor is required.
You can get the json output for readonly properties by setting the ShowReadOnlyProperties = true in JSONParameters.
Obviously when deserializing the readonly properties will be ignored and not set.
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|

|
In a immutable object, all its properties are readonly as they are immutable.
can i deserialie them without adding a public setter?
Thank you very much
Iker eL_FRuTeRo
|
|
|
|

|
Unfortunately not since the deserializer is using the Set method defined on the class and if it is private then it will fail.
Obviously the designer of the class made the decision to make properties private, so it is unsafe to assume anything about the internal structure of the class when reflecting at the level of fastJSON.
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|

|
I am trying to serialize and deserialize a variable of type System.Type. Is that possible? If yes, what am I doing wrong?
System.Type type = typeof(string);
var jsonText = JSON.Instance.ToJSON(type);
var newType = JSON.Instance.ToObject(jsonText) as Type;
I get the following exception:
System.Exception : Failed to fast create instance for type 'System.RuntimeType' from assemebly 'System.RuntimeType, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
----> System.ArgumentNullException : Value cannot be null.
Parameter name: con
at fastJSON.JSON.FastCreateInstance(Type objtype) in JSON.cs: line 164
at fastJSON.JSON.ParseDictionary(Dictionary`2 d, Dictionary`2 globaltypes, Type type) in JSON.cs: line 471
at fastJSON.JSON.ToObject(String json, Type type) in JSON.cs: line 82
at fastJSON.JSON.ToObject(String json) in JSON.cs: line 75
(I also posted this on CodePlex: [^]. I am not sure where the official forum is.)
|
|
|
|

|
Serializers are generally meant to process "data" types not "meta" types, so unfortunately you can't work with Type as an input.
I prefer this forum than Codeplex as provides a better interface and is easier to work with.
Its the man, not the machine - Chuck Yeager
If at first you don't succeed... get a better publicist
If the final destination is death, then we should enjoy every second of the journey.
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
|
Smallest, fastest polymorphic JSON serializer (with Silverlight4 and MonoDroid support)
| Type | Article |
| Licence | CPOL |
| First Posted | 19 Feb 2011 |
| Views | 1,554,530 |
| Downloads | 25,736 |
| Bookmarked | 462 times |
|
|