Skip to content

Commit b726936

Browse files
committed
Add seperate static classes for default decoder and encoder
Add static classes for extensions
1 parent b4ab4a2 commit b726936

8 files changed

Lines changed: 372 additions & 272 deletions

File tree

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Reflection;
5+
6+
namespace Tiny {
7+
8+
using Decoder = Func<Type, object, object>;
9+
10+
public static class DefaultDecoder {
11+
12+
public static Decoder GenericDecoder() {
13+
return (type, jsonObj) => {
14+
object instance = Activator.CreateInstance(type, true);
15+
if (jsonObj is IDictionary) {
16+
foreach (DictionaryEntry item in (IDictionary)jsonObj) {
17+
string name = (string)item.Key;
18+
if (!JsonMapper.DecodeValue(instance, name, item.Value)) {
19+
Console.WriteLine("couldn't decode field \"" + name + "\" of " + type);
20+
}
21+
}
22+
} else {
23+
Console.WriteLine("unsupported json type: " + (jsonObj != null ? jsonObj.GetType().ToString() : "null"));
24+
}
25+
return instance;
26+
};
27+
}
28+
29+
public static Decoder DictionaryDecoder() {
30+
return (type, jsonObj) => {
31+
Console.WriteLine("Decode Dictionary");
32+
33+
// Dictionary
34+
if (jsonObj is IDictionary<string, object>) {
35+
Dictionary<string, object> jsonDict = (Dictionary<string, object>)jsonObj;
36+
if (type.GetGenericArguments().Length == 2) {
37+
IDictionary instance = null;
38+
Type keyType = type.GetGenericArguments()[0];
39+
Type genericType = type.GetGenericArguments()[1];
40+
bool nullable = genericType.IsNullable();
41+
if (type != typeof(IDictionary) && typeof(IDictionary).IsAssignableFrom(type)) {
42+
Console.WriteLine("Create Dictionary Instance");
43+
instance = Activator.CreateInstance(type, true) as IDictionary;
44+
} else {
45+
Console.WriteLine("Create Dictionary Instance for IDictionary interface");
46+
Type genericDictType = typeof(Dictionary<,>).MakeGenericType(keyType, genericType);
47+
instance = Activator.CreateInstance(genericDictType) as IDictionary;
48+
}
49+
foreach (KeyValuePair<string, object> item in jsonDict) {
50+
Console.WriteLine(item.Key + " = " + JsonMapper.DecodeValue(item.Value, genericType));
51+
object value = JsonMapper.DecodeValue(item.Value, genericType);
52+
object key = item.Key;
53+
if (keyType == typeof(int)) key = Int32.Parse(item.Key);
54+
if (value != null || nullable) instance.Add(key, value);
55+
}
56+
return instance;
57+
} else {
58+
Console.WriteLine("unexpected type arguemtns");
59+
}
60+
}
61+
// Dictionary (convert int to string key)
62+
if (jsonObj is IDictionary<int, object>) {
63+
Dictionary<string, object> jsonDict = new Dictionary<string, object>();
64+
foreach (KeyValuePair<int, object> keyValuePair in (Dictionary<int, object>)jsonObj) {
65+
jsonDict.Add(keyValuePair.Key.ToString(), keyValuePair.Value);
66+
}
67+
if (type.GetGenericArguments().Length == 2) {
68+
IDictionary instance = null;
69+
Type keyType = type.GetGenericArguments()[0];
70+
Type genericType = type.GetGenericArguments()[1];
71+
bool nullable = genericType.IsNullable();
72+
if (type != typeof(IDictionary) && typeof(IDictionary).IsAssignableFrom(type)) {
73+
instance = Activator.CreateInstance(type, true) as IDictionary;
74+
} else {
75+
Type genericDictType = typeof(Dictionary<,>).MakeGenericType(keyType, genericType);
76+
instance = Activator.CreateInstance(genericDictType) as IDictionary;
77+
}
78+
foreach (KeyValuePair<string, object> item in jsonDict) {
79+
Console.WriteLine(item.Key + " = " + JsonMapper.DecodeValue(item.Value, genericType));
80+
object value = JsonMapper.DecodeValue(item.Value, genericType);
81+
if (value != null || nullable) instance.Add(Convert.ToInt32(item.Key), value);
82+
}
83+
return instance;
84+
} else {
85+
Console.WriteLine("unexpected type arguemtns");
86+
}
87+
}
88+
Console.WriteLine("couldn't decode Dictionary: " + type);
89+
return null;
90+
};
91+
}
92+
93+
public static Decoder ArrayDecoder() {
94+
return (type, jsonObj) => {
95+
if (typeof(IEnumerable).IsAssignableFrom(type)) {
96+
if (jsonObj is IList) {
97+
IList jsonList = (IList)jsonObj;
98+
if (type.IsArray) {
99+
Type elementType = type.GetElementType();
100+
bool nullable = elementType.IsNullable();
101+
var array = Array.CreateInstance(elementType, jsonList.Count);
102+
for (int i = 0; i < jsonList.Count; i++) {
103+
object value = JsonMapper.DecodeValue(jsonList[i], elementType);
104+
if (value != null || nullable) array.SetValue(value, i);
105+
}
106+
return array;
107+
}
108+
}
109+
}
110+
111+
Console.WriteLine("Couldn't decode Array: " + type);
112+
return null;
113+
};
114+
}
115+
116+
public static Decoder ListDecoder() {
117+
return (type, jsonObj) => {
118+
if (type.HasGenericInterface(typeof(IList<>)) && type.GetGenericArguments().Length == 1) {
119+
Type genericType = type.GetGenericArguments()[0];
120+
if (jsonObj is IList) {
121+
IList jsonList = (IList)jsonObj;
122+
IList instance = null;
123+
bool nullable = genericType.IsNullable();
124+
if (type != typeof(IList) && typeof(IList).IsAssignableFrom(type)) {
125+
instance = Activator.CreateInstance(type, true) as IList;
126+
} else {
127+
Type genericListType = typeof(List<>).MakeGenericType(genericType);
128+
instance = Activator.CreateInstance(genericListType) as IList;
129+
}
130+
foreach (var item in jsonList) {
131+
object value = JsonMapper.DecodeValue(item, genericType);
132+
if (value != null || nullable) instance.Add(value);
133+
}
134+
return instance;
135+
}
136+
}
137+
Console.WriteLine("Couldn't decode List: " + type);
138+
return null;
139+
};
140+
}
141+
142+
public static Decoder CollectionDecoder() {
143+
return (type, jsonObj) => {
144+
if (type.HasGenericInterface(typeof(ICollection<>))) {
145+
Type genericType = type.GetGenericArguments()[0];
146+
if (jsonObj is IList) {
147+
IList jsonList = (IList)jsonObj;
148+
var listType = type.IsInstanceOfGenericType(typeof(HashSet<>)) ? typeof(HashSet<>) : typeof(List<>);
149+
var constructedListType = listType.MakeGenericType(genericType);
150+
var instance = Activator.CreateInstance(constructedListType, true);
151+
bool nullable = genericType.IsNullable();
152+
MethodInfo addMethodInfo = type.GetMethod("Add");
153+
if (addMethodInfo != null) {
154+
foreach (var item in jsonList) {
155+
object value = JsonMapper.DecodeValue(item, genericType);
156+
if (value != null || nullable) addMethodInfo.Invoke(instance, new object[] { value });
157+
}
158+
return instance;
159+
}
160+
}
161+
}
162+
Console.WriteLine("Couldn't decode Collection: " + type);
163+
return null;
164+
};
165+
}
166+
167+
public static Decoder EnumerableDecoder() {
168+
return (type, jsonObj) => {
169+
if (typeof(IEnumerable).IsAssignableFrom(type)) {
170+
// It could be an dictionary
171+
if (jsonObj is IDictionary) {
172+
// Decode a dictionary
173+
return DictionaryDecoder().Invoke(type, jsonObj);
174+
}
175+
176+
// Or it could be also be a list
177+
if (jsonObj is IList) {
178+
// Decode an array
179+
if (type.IsArray) {
180+
return ArrayDecoder().Invoke(type, jsonObj);
181+
}
182+
183+
// Decode a list
184+
if (type.HasGenericInterface(typeof(IList<>))) {
185+
return ListDecoder().Invoke(type, jsonObj);
186+
}
187+
188+
// Decode a collection
189+
if (type.HasGenericInterface(typeof(ICollection<>))) {
190+
return CollectionDecoder().Invoke(type, jsonObj);
191+
}
192+
}
193+
}
194+
195+
Console.WriteLine("Couldn't decode Enumerable: " + type);
196+
return null;
197+
};
198+
}
199+
}
200+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using System;
2+
using System.Collections;
3+
using System.Reflection;
4+
5+
namespace Tiny {
6+
7+
using Encoder = Action<object, JsonBuilder>;
8+
9+
public static class DefaultEncoder {
10+
11+
public static Encoder GenericEncoder() {
12+
return (obj, builder) => {
13+
builder.AppendBeginObject();
14+
Type type = obj.GetType();
15+
bool first = true;
16+
while (type != null) {
17+
foreach (FieldInfo field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)) {
18+
if (field.GetCustomAttributes(typeof(NonSerializedAttribute), true).Length == 0) {
19+
if (first) first = false; else builder.AppendSeperator();
20+
JsonMapper.EncodeNameValue(field.Name, field.GetValue(obj), builder);
21+
}
22+
}
23+
type = type.BaseType;
24+
}
25+
builder.AppendEndObject();
26+
};
27+
}
28+
29+
public static Encoder DictionaryEncoder() {
30+
return (obj, builder) => {
31+
builder.AppendBeginObject();
32+
bool first = true;
33+
IDictionary dict = (IDictionary)obj;
34+
foreach (var key in dict.Keys) {
35+
if (first) first = false; else builder.AppendSeperator();
36+
JsonMapper.EncodeNameValue(key.ToString(), dict[key], builder);
37+
}
38+
builder.AppendEndObject();
39+
};
40+
}
41+
42+
public static Encoder EnumerableEncoder() {
43+
return (obj, builder) => {
44+
builder.AppendBeginArray();
45+
bool first = true;
46+
foreach (var item in (IEnumerable)obj) {
47+
if (first) first = false; else builder.AppendSeperator();
48+
JsonMapper.EncodeValue(item, builder);
49+
}
50+
builder.AppendEndArray();
51+
};
52+
}
53+
54+
public static Encoder ZuluDateEncoder() {
55+
return (obj, builder) => {
56+
DateTime date = (DateTime)obj;
57+
string zulu = date.ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'");
58+
builder.AppendString(zulu);
59+
};
60+
}
61+
}
62+
}

Tiny-JSON/Tiny-JSON/Extensions.cs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using System;
2+
using System.Linq;
3+
4+
namespace Tiny {
5+
public static class TypeExtensions {
6+
public static bool IsInstanceOfGenericType(this Type type, Type genericType) {
7+
while (type != null) {
8+
if (type.IsGenericType && type.GetGenericTypeDefinition() == genericType) return true;
9+
type = type.BaseType;
10+
}
11+
return false;
12+
}
13+
14+
public static bool HasGenericInterface(this Type type, Type genericInterface) {
15+
if (genericInterface == null) throw new ArgumentNullException();
16+
var interfaceTest = new Predicate<Type>(i => i.IsGenericType && i.GetGenericTypeDefinition().IsAssignableFrom(genericInterface));
17+
return interfaceTest(type) || type.GetInterfaces().Any(i => interfaceTest(i));
18+
}
19+
}
20+
21+
public static class JsonExtensions {
22+
public static bool IsNullable(this Type type) {
23+
return Nullable.GetUnderlyingType(type) != null || !type.IsPrimitive;
24+
}
25+
26+
public static bool IsNumeric(this Type type) {
27+
if (type.IsEnum) return false;
28+
switch (Type.GetTypeCode(type)) {
29+
case TypeCode.Byte:
30+
case TypeCode.SByte:
31+
case TypeCode.UInt16:
32+
case TypeCode.UInt32:
33+
case TypeCode.UInt64:
34+
case TypeCode.Int16:
35+
case TypeCode.Int32:
36+
case TypeCode.Int64:
37+
case TypeCode.Decimal:
38+
case TypeCode.Double:
39+
case TypeCode.Single:
40+
return true;
41+
case TypeCode.Object:
42+
Type underlyingType = Nullable.GetUnderlyingType(type);
43+
return underlyingType != null && underlyingType.IsNumeric();
44+
default:
45+
return false;
46+
}
47+
}
48+
49+
public static bool IsFloatingPoint(this Type type) {
50+
if (type.IsEnum) return false;
51+
switch (Type.GetTypeCode(type)) {
52+
case TypeCode.Decimal:
53+
case TypeCode.Double:
54+
case TypeCode.Single:
55+
return true;
56+
case TypeCode.Object:
57+
Type underlyingType = Nullable.GetUnderlyingType(type);
58+
return underlyingType != null && underlyingType.IsFloatingPoint();
59+
default:
60+
return false;
61+
}
62+
}
63+
}
64+
65+
public static class StringBuilderExtensions {
66+
public static void Clear(this System.Text.StringBuilder sb) {
67+
sb.Length = 0;
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)