PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/src/ServiceStack.Text/JsConfig.cs

https://github.com/pauldbau/ServiceStack.Text
C# | 852 lines | 649 code | 84 blank | 119 comment | 97 complexity | 7c13674edf0de070dd999dcbac29a6cb MD5 | raw file
Possible License(s): BSD-3-Clause
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using ServiceStack.Text.Common;
  5. using ServiceStack.Text.Json;
  6. using ServiceStack.Text.Jsv;
  7. #if WINDOWS_PHONE
  8. using ServiceStack.Text.WP;
  9. #endif
  10. namespace ServiceStack.Text
  11. {
  12. public static class
  13. JsConfig
  14. {
  15. static JsConfig()
  16. {
  17. //In-built default serialization, to Deserialize Color struct do:
  18. //JsConfig<System.Drawing.Color>.SerializeFn = c => c.ToString().Replace("Color ", "").Replace("[", "").Replace("]", "");
  19. //JsConfig<System.Drawing.Color>.DeSerializeFn = System.Drawing.Color.FromName;
  20. Reset();
  21. }
  22. public static JsConfigScope BeginScope()
  23. {
  24. return new JsConfigScope();
  25. }
  26. [ThreadStatic]
  27. private static bool? tsConvertObjectTypesIntoStringDictionary;
  28. private static bool? sConvertObjectTypesIntoStringDictionary;
  29. public static bool ConvertObjectTypesIntoStringDictionary
  30. {
  31. get
  32. {
  33. return (JsConfigScope.Current != null ? JsConfigScope.Current.ConvertObjectTypesIntoStringDictionary: null)
  34. ?? tsConvertObjectTypesIntoStringDictionary
  35. ?? sConvertObjectTypesIntoStringDictionary
  36. ?? false;
  37. }
  38. set
  39. {
  40. tsConvertObjectTypesIntoStringDictionary = value;
  41. if (!sConvertObjectTypesIntoStringDictionary.HasValue) sConvertObjectTypesIntoStringDictionary = value;
  42. }
  43. }
  44. [ThreadStatic]
  45. private static bool? tsTryToParsePrimitiveTypeValues;
  46. private static bool? sTryToParsePrimitiveTypeValues;
  47. public static bool TryToParsePrimitiveTypeValues
  48. {
  49. get
  50. {
  51. return (JsConfigScope.Current != null ? JsConfigScope.Current.TryToParsePrimitiveTypeValues: null)
  52. ?? tsTryToParsePrimitiveTypeValues
  53. ?? sTryToParsePrimitiveTypeValues
  54. ?? false;
  55. }
  56. set
  57. {
  58. tsTryToParsePrimitiveTypeValues = value;
  59. if (!sTryToParsePrimitiveTypeValues.HasValue) sTryToParsePrimitiveTypeValues = value;
  60. }
  61. }
  62. [ThreadStatic]
  63. private static bool? tsIncludeNullValues;
  64. private static bool? sIncludeNullValues;
  65. public static bool IncludeNullValues
  66. {
  67. get
  68. {
  69. return (JsConfigScope.Current != null ? JsConfigScope.Current.IncludeNullValues: null)
  70. ?? tsIncludeNullValues
  71. ?? sIncludeNullValues
  72. ?? false;
  73. }
  74. set
  75. {
  76. tsIncludeNullValues = value;
  77. if (!sIncludeNullValues.HasValue) sIncludeNullValues = value;
  78. }
  79. }
  80. [ThreadStatic]
  81. private static bool? tsTreatEnumAsInteger;
  82. private static bool? sTreatEnumAsInteger;
  83. public static bool TreatEnumAsInteger
  84. {
  85. get
  86. {
  87. return (JsConfigScope.Current != null ? JsConfigScope.Current.TreatEnumAsInteger: null)
  88. ?? tsTreatEnumAsInteger
  89. ?? sTreatEnumAsInteger
  90. ?? false;
  91. }
  92. set
  93. {
  94. tsTreatEnumAsInteger = value;
  95. if (!sTreatEnumAsInteger.HasValue) sTreatEnumAsInteger = value;
  96. }
  97. }
  98. [ThreadStatic]
  99. private static bool? tsExcludeTypeInfo;
  100. private static bool? sExcludeTypeInfo;
  101. public static bool ExcludeTypeInfo
  102. {
  103. get
  104. {
  105. return (JsConfigScope.Current != null ? JsConfigScope.Current.ExcludeTypeInfo: null)
  106. ?? tsExcludeTypeInfo
  107. ?? sExcludeTypeInfo
  108. ?? false;
  109. }
  110. set
  111. {
  112. tsExcludeTypeInfo = value;
  113. if (!sExcludeTypeInfo.HasValue) sExcludeTypeInfo = value;
  114. }
  115. }
  116. [ThreadStatic]
  117. private static bool? tsForceTypeInfo;
  118. private static bool? sForceTypeInfo;
  119. public static bool IncludeTypeInfo
  120. {
  121. get
  122. {
  123. return (JsConfigScope.Current != null ? JsConfigScope.Current.IncludeTypeInfo: null)
  124. ?? tsForceTypeInfo
  125. ?? sForceTypeInfo
  126. ?? false;
  127. }
  128. set
  129. {
  130. if (!tsForceTypeInfo.HasValue) tsForceTypeInfo = value;
  131. if (!sForceTypeInfo.HasValue) sForceTypeInfo = value;
  132. }
  133. }
  134. [ThreadStatic]
  135. private static string tsTypeAttr;
  136. private static string sTypeAttr;
  137. public static string TypeAttr
  138. {
  139. get
  140. {
  141. return (JsConfigScope.Current != null ? JsConfigScope.Current.TypeAttr: null)
  142. ?? tsTypeAttr
  143. ?? sTypeAttr
  144. ?? JsWriter.TypeAttr;
  145. }
  146. set
  147. {
  148. tsTypeAttr = value;
  149. if (sTypeAttr == null) sTypeAttr = value;
  150. JsonTypeAttrInObject = JsonTypeSerializer.GetTypeAttrInObject(value);
  151. JsvTypeAttrInObject = JsvTypeSerializer.GetTypeAttrInObject(value);
  152. }
  153. }
  154. [ThreadStatic]
  155. private static string tsJsonTypeAttrInObject;
  156. private static string sJsonTypeAttrInObject;
  157. private static readonly string defaultJsonTypeAttrInObject = JsonTypeSerializer.GetTypeAttrInObject(TypeAttr);
  158. internal static string JsonTypeAttrInObject
  159. {
  160. get
  161. {
  162. return (JsConfigScope.Current != null ? JsConfigScope.Current.JsonTypeAttrInObject: null)
  163. ?? tsJsonTypeAttrInObject
  164. ?? sJsonTypeAttrInObject
  165. ?? defaultJsonTypeAttrInObject;
  166. }
  167. set
  168. {
  169. tsJsonTypeAttrInObject = value;
  170. if (sJsonTypeAttrInObject == null) sJsonTypeAttrInObject = value;
  171. }
  172. }
  173. [ThreadStatic]
  174. private static string tsJsvTypeAttrInObject;
  175. private static string sJsvTypeAttrInObject;
  176. private static readonly string defaultJsvTypeAttrInObject = JsvTypeSerializer.GetTypeAttrInObject(TypeAttr);
  177. internal static string JsvTypeAttrInObject
  178. {
  179. get
  180. {
  181. return (JsConfigScope.Current != null ? JsConfigScope.Current.JsvTypeAttrInObject: null)
  182. ?? tsJsvTypeAttrInObject
  183. ?? sJsvTypeAttrInObject
  184. ?? defaultJsvTypeAttrInObject;
  185. }
  186. set
  187. {
  188. tsJsvTypeAttrInObject = value;
  189. if (sJsvTypeAttrInObject == null) sJsvTypeAttrInObject = value;
  190. }
  191. }
  192. [ThreadStatic]
  193. private static Func<Type, string> tsTypeWriter;
  194. private static Func<Type, string> sTypeWriter;
  195. public static Func<Type, string> TypeWriter
  196. {
  197. get
  198. {
  199. return (JsConfigScope.Current != null ? JsConfigScope.Current.TypeWriter: null)
  200. ?? tsTypeWriter
  201. ?? sTypeWriter
  202. ?? AssemblyUtils.WriteType;
  203. }
  204. set
  205. {
  206. tsTypeWriter = value;
  207. if (sTypeWriter == null) sTypeWriter = value;
  208. }
  209. }
  210. [ThreadStatic]
  211. private static Func<string, Type> tsTypeFinder;
  212. private static Func<string, Type> sTypeFinder;
  213. public static Func<string, Type> TypeFinder
  214. {
  215. get
  216. {
  217. return (JsConfigScope.Current != null ? JsConfigScope.Current.TypeFinder: null)
  218. ?? tsTypeFinder
  219. ?? sTypeFinder
  220. ?? AssemblyUtils.FindType;
  221. }
  222. set
  223. {
  224. tsTypeFinder = value;
  225. if (sTypeFinder == null) sTypeFinder = value;
  226. }
  227. }
  228. [ThreadStatic]
  229. private static JsonDateHandler? tsDateHandler;
  230. private static JsonDateHandler? sDateHandler;
  231. public static JsonDateHandler DateHandler
  232. {
  233. get
  234. {
  235. return (JsConfigScope.Current != null ? JsConfigScope.Current.DateHandler: null)
  236. ?? tsDateHandler
  237. ?? sDateHandler
  238. ?? JsonDateHandler.TimestampOffset;
  239. }
  240. set
  241. {
  242. tsDateHandler = value;
  243. if (!sDateHandler.HasValue) sDateHandler = value;
  244. }
  245. }
  246. /// <summary>
  247. /// Sets which format to use when serializing TimeSpans
  248. /// </summary>
  249. public static JsonTimeSpanHandler TimeSpanHandler { get; set; }
  250. /// <summary>
  251. /// <see langword="true"/> if the <see cref="ITypeSerializer"/> is configured
  252. /// to take advantage of <see cref="CLSCompliantAttribute"/> specification,
  253. /// to support user-friendly serialized formats, ie emitting camelCasing for JSON
  254. /// and parsing member names and enum values in a case-insensitive manner.
  255. /// </summary>
  256. [ThreadStatic]
  257. private static bool? tsEmitCamelCaseNames;
  258. private static bool? sEmitCamelCaseNames;
  259. public static bool EmitCamelCaseNames
  260. {
  261. // obeying the use of ThreadStatic, but allowing for setting JsConfig once as is the normal case
  262. get
  263. {
  264. return (JsConfigScope.Current != null ? JsConfigScope.Current.EmitCamelCaseNames: null)
  265. ?? tsEmitCamelCaseNames
  266. ?? sEmitCamelCaseNames
  267. ?? false;
  268. }
  269. set
  270. {
  271. tsEmitCamelCaseNames = value;
  272. if (!sEmitCamelCaseNames.HasValue) sEmitCamelCaseNames = value;
  273. }
  274. }
  275. /// <summary>
  276. /// <see langword="true"/> if the <see cref="ITypeSerializer"/> is configured
  277. /// to support web-friendly serialized formats, ie emitting lowercase_underscore_casing for JSON
  278. /// </summary>
  279. [ThreadStatic]
  280. private static bool? tsEmitLowercaseUnderscoreNames;
  281. private static bool? sEmitLowercaseUnderscoreNames;
  282. public static bool EmitLowercaseUnderscoreNames
  283. {
  284. // obeying the use of ThreadStatic, but allowing for setting JsConfig once as is the normal case
  285. get
  286. {
  287. return (JsConfigScope.Current != null ? JsConfigScope.Current.EmitLowercaseUnderscoreNames: null)
  288. ?? tsEmitLowercaseUnderscoreNames
  289. ?? sEmitLowercaseUnderscoreNames
  290. ?? false;
  291. }
  292. set
  293. {
  294. tsEmitLowercaseUnderscoreNames = value;
  295. if (!sEmitLowercaseUnderscoreNames.HasValue) sEmitLowercaseUnderscoreNames = value;
  296. }
  297. }
  298. /// <summary>
  299. /// Define how property names are mapped during deserialization
  300. /// </summary>
  301. private static JsonPropertyConvention propertyConvention;
  302. public static JsonPropertyConvention PropertyConvention
  303. {
  304. get { return propertyConvention; }
  305. set
  306. {
  307. propertyConvention = value;
  308. switch (propertyConvention)
  309. {
  310. case JsonPropertyConvention.ExactMatch:
  311. DeserializeTypeRefJson.PropertyNameResolver = DeserializeTypeRefJson.DefaultPropertyNameResolver;
  312. break;
  313. case JsonPropertyConvention.Lenient:
  314. DeserializeTypeRefJson.PropertyNameResolver = DeserializeTypeRefJson.LenientPropertyNameResolver;
  315. break;
  316. }
  317. }
  318. }
  319. /// <summary>
  320. /// Gets or sets a value indicating if the framework should throw serialization exceptions
  321. /// or continue regardless of deserialization errors. If <see langword="true"/> the framework
  322. /// will throw; otherwise, it will parse as many fields as possible. The default is <see langword="false"/>.
  323. /// </summary>
  324. [ThreadStatic]
  325. private static bool? tsThrowOnDeserializationError;
  326. private static bool? sThrowOnDeserializationError;
  327. public static bool ThrowOnDeserializationError
  328. {
  329. // obeying the use of ThreadStatic, but allowing for setting JsConfig once as is the normal case
  330. get
  331. {
  332. return (JsConfigScope.Current != null ? JsConfigScope.Current.ThrowOnDeserializationError: null)
  333. ?? tsThrowOnDeserializationError
  334. ?? sThrowOnDeserializationError
  335. ?? false;
  336. }
  337. set
  338. {
  339. tsThrowOnDeserializationError = value;
  340. if (!sThrowOnDeserializationError.HasValue) sThrowOnDeserializationError = value;
  341. }
  342. }
  343. /// <summary>
  344. /// Gets or sets a value indicating if the framework should always convert <see cref="DateTime"/> to UTC format instead of local time.
  345. /// </summary>
  346. [ThreadStatic]
  347. private static bool? tsAlwaysUseUtc;
  348. private static bool? sAlwaysUseUtc;
  349. public static bool AlwaysUseUtc
  350. {
  351. // obeying the use of ThreadStatic, but allowing for setting JsConfig once as is the normal case
  352. get
  353. {
  354. return (JsConfigScope.Current != null ? JsConfigScope.Current.AlwaysUseUtc: null)
  355. ?? tsAlwaysUseUtc
  356. ?? sAlwaysUseUtc
  357. ?? false;
  358. }
  359. set
  360. {
  361. tsAlwaysUseUtc = value;
  362. if (!sAlwaysUseUtc.HasValue) sAlwaysUseUtc = value;
  363. }
  364. }
  365. internal static HashSet<Type> HasSerializeFn = new HashSet<Type>();
  366. internal static HashSet<Type> TreatValueAsRefTypes = new HashSet<Type>();
  367. [ThreadStatic]
  368. private static bool? tsPreferInterfaces;
  369. private static bool? sPreferInterfaces;
  370. /// <summary>
  371. /// If set to true, Interface types will be prefered over concrete types when serializing.
  372. /// </summary>
  373. public static bool PreferInterfaces
  374. {
  375. get
  376. {
  377. return (JsConfigScope.Current != null ? JsConfigScope.Current.PreferInterfaces: null)
  378. ?? tsPreferInterfaces
  379. ?? sPreferInterfaces
  380. ?? false;
  381. }
  382. set
  383. {
  384. tsPreferInterfaces = value;
  385. if (!sPreferInterfaces.HasValue) sPreferInterfaces = value;
  386. }
  387. }
  388. internal static bool TreatAsRefType(Type valueType)
  389. {
  390. return TreatValueAsRefTypes.Contains(valueType.IsGenericType ? valueType.GetGenericTypeDefinition() : valueType);
  391. }
  392. public static void Reset()
  393. {
  394. ModelFactory = ReflectionExtensions.GetConstructorMethodToCache;
  395. tsTryToParsePrimitiveTypeValues = sTryToParsePrimitiveTypeValues = null;
  396. tsConvertObjectTypesIntoStringDictionary = sConvertObjectTypesIntoStringDictionary = null;
  397. tsIncludeNullValues = sIncludeNullValues = null;
  398. tsExcludeTypeInfo = sExcludeTypeInfo = null;
  399. tsEmitCamelCaseNames = sEmitCamelCaseNames = null;
  400. tsEmitLowercaseUnderscoreNames = sEmitLowercaseUnderscoreNames = null;
  401. tsDateHandler = sDateHandler = null;
  402. tsPreferInterfaces = sPreferInterfaces = null;
  403. tsThrowOnDeserializationError = sThrowOnDeserializationError = null;
  404. tsTypeAttr = sTypeAttr = null;
  405. tsJsonTypeAttrInObject = sJsonTypeAttrInObject = null;
  406. tsJsvTypeAttrInObject = sJsvTypeAttrInObject = null;
  407. tsTypeWriter = sTypeWriter = null;
  408. tsTypeFinder = sTypeFinder = null;
  409. tsTreatEnumAsInteger = sTreatEnumAsInteger = null;
  410. tsAlwaysUseUtc = sAlwaysUseUtc = null;
  411. HasSerializeFn = new HashSet<Type>();
  412. TreatValueAsRefTypes = new HashSet<Type> { typeof(KeyValuePair<,>) };
  413. PropertyConvention = JsonPropertyConvention.ExactMatch;
  414. }
  415. #if MONOTOUCH
  416. /// <summary>
  417. /// Provide hint to MonoTouch AOT compiler to pre-compile generic classes for all your DTOs.
  418. /// Just needs to be called once in a static constructor.
  419. /// </summary>
  420. [MonoTouch.Foundation.Preserve]
  421. public static void InitForAot() {
  422. }
  423. [MonoTouch.Foundation.Preserve]
  424. public static void RegisterForAot()
  425. {
  426. RegisterTypeForAot<Poco>();
  427. RegisterElement<Poco, string>();
  428. RegisterElement<Poco, bool>();
  429. RegisterElement<Poco, char>();
  430. RegisterElement<Poco, byte>();
  431. RegisterElement<Poco, sbyte>();
  432. RegisterElement<Poco, short>();
  433. RegisterElement<Poco, ushort>();
  434. RegisterElement<Poco, int>();
  435. RegisterElement<Poco, uint>();
  436. RegisterElement<Poco, long>();
  437. RegisterElement<Poco, ulong>();
  438. RegisterElement<Poco, float>();
  439. RegisterElement<Poco, double>();
  440. RegisterElement<Poco, decimal>();
  441. RegisterElement<Poco, bool?>();
  442. RegisterElement<Poco, char?>();
  443. RegisterElement<Poco, byte?>();
  444. RegisterElement<Poco, sbyte?>();
  445. RegisterElement<Poco, short?>();
  446. RegisterElement<Poco, ushort?>();
  447. RegisterElement<Poco, int?>();
  448. RegisterElement<Poco, uint?>();
  449. RegisterElement<Poco, long?>();
  450. RegisterElement<Poco, ulong?>();
  451. RegisterElement<Poco, float?>();
  452. RegisterElement<Poco, double?>();
  453. RegisterElement<Poco, decimal?>();
  454. //RegisterElement<Poco, JsonValue>();
  455. RegisterTypeForAot<DayOfWeek>(); // used by DateTime
  456. // register built in structs
  457. RegisterTypeForAot<Guid>();
  458. RegisterTypeForAot<TimeSpan>();
  459. RegisterTypeForAot<DateTime>();
  460. RegisterTypeForAot<DateTime?>();
  461. RegisterTypeForAot<TimeSpan?>();
  462. RegisterTypeForAot<Guid?>();
  463. }
  464. [MonoTouch.Foundation.Preserve]
  465. public static void RegisterTypeForAot<T>()
  466. {
  467. AotConfig.RegisterSerializers<T>();
  468. }
  469. [MonoTouch.Foundation.Preserve]
  470. static void RegisterQueryStringWriter()
  471. {
  472. var i = 0;
  473. if (QueryStringWriter<Poco>.WriteFn() != null) i++;
  474. }
  475. [MonoTouch.Foundation.Preserve]
  476. internal static int RegisterElement<T, TElement>()
  477. {
  478. var i = 0;
  479. i += AotConfig.RegisterSerializers<TElement>();
  480. AotConfig.RegisterElement<T, TElement, JsonTypeSerializer>();
  481. AotConfig.RegisterElement<T, TElement, JsvTypeSerializer>();
  482. return i;
  483. }
  484. ///<summary>
  485. /// Class contains Ahead-of-Time (AOT) explicit class declarations which is used only to workaround "-aot-only" exceptions occured on device only.
  486. /// </summary>
  487. [MonoTouch.Foundation.Preserve(AllMembers=true)]
  488. internal class AotConfig
  489. {
  490. internal static JsReader<JsonTypeSerializer> jsonReader;
  491. internal static JsWriter<JsonTypeSerializer> jsonWriter;
  492. internal static JsReader<JsvTypeSerializer> jsvReader;
  493. internal static JsWriter<JsvTypeSerializer> jsvWriter;
  494. internal static JsonTypeSerializer jsonSerializer;
  495. internal static JsvTypeSerializer jsvSerializer;
  496. static AotConfig()
  497. {
  498. jsonSerializer = new JsonTypeSerializer();
  499. jsvSerializer = new JsvTypeSerializer();
  500. jsonReader = new JsReader<JsonTypeSerializer>();
  501. jsonWriter = new JsWriter<JsonTypeSerializer>();
  502. jsvReader = new JsReader<JsvTypeSerializer>();
  503. jsvWriter = new JsWriter<JsvTypeSerializer>();
  504. }
  505. internal static int RegisterSerializers<T>()
  506. {
  507. var i = 0;
  508. i += Register<T, JsonTypeSerializer>();
  509. if (jsonSerializer.GetParseFn<T>() != null) i++;
  510. if (jsonSerializer.GetWriteFn<T>() != null) i++;
  511. if (jsonReader.GetParseFn<T>() != null) i++;
  512. if (jsonWriter.GetWriteFn<T>() != null) i++;
  513. i += Register<T, JsvTypeSerializer>();
  514. if (jsvSerializer.GetParseFn<T>() != null) i++;
  515. if (jsvSerializer.GetWriteFn<T>() != null) i++;
  516. if (jsvReader.GetParseFn<T>() != null) i++;
  517. if (jsvWriter.GetWriteFn<T>() != null) i++;
  518. //RegisterCsvSerializer<T>();
  519. RegisterQueryStringWriter();
  520. return i;
  521. }
  522. internal static void RegisterCsvSerializer<T>()
  523. {
  524. CsvSerializer<T>.WriteFn();
  525. CsvSerializer<T>.WriteObject(null, null);
  526. CsvWriter<T>.Write(null, default(IEnumerable<T>));
  527. CsvWriter<T>.WriteRow(null, default(T));
  528. }
  529. public static ParseStringDelegate GetParseFn(Type type)
  530. {
  531. var parseFn = JsonTypeSerializer.Instance.GetParseFn(type);
  532. return parseFn;
  533. }
  534. internal static int Register<T, TSerializer>() where TSerializer : ITypeSerializer
  535. {
  536. var i = 0;
  537. if (JsonWriter<T>.WriteFn() != null) i++;
  538. if (JsonWriter.Instance.GetWriteFn<T>() != null) i++;
  539. if (JsonReader.Instance.GetParseFn<T>() != null) i++;
  540. if (JsonReader<T>.Parse(null) != null) i++;
  541. if (JsonReader<T>.GetParseFn() != null) i++;
  542. //if (JsWriter.GetTypeSerializer<JsonTypeSerializer>().GetWriteFn<T>() != null) i++;
  543. if (new List<T>() != null) i++;
  544. if (new T[0] != null) i++;
  545. JsConfig<T>.ExcludeTypeInfo = false;
  546. if (JsConfig<T>.OnDeserializedFn != null) i++;
  547. if (JsConfig<T>.HasDeserializeFn) i++;
  548. if (JsConfig<T>.SerializeFn != null) i++;
  549. if (JsConfig<T>.DeSerializeFn != null) i++;
  550. //JsConfig<T>.SerializeFn = arg => "";
  551. //JsConfig<T>.DeSerializeFn = arg => default(T);
  552. if (TypeConfig<T>.Properties != null) i++;
  553. /*
  554. if (WriteType<T, TSerializer>.Write != null) i++;
  555. if (WriteType<object, TSerializer>.Write != null) i++;
  556. if (DeserializeBuiltin<T>.Parse != null) i++;
  557. if (DeserializeArray<T[], TSerializer>.Parse != null) i++;
  558. DeserializeType<TSerializer>.ExtractType(null);
  559. DeserializeArrayWithElements<T, TSerializer>.ParseGenericArray(null, null);
  560. DeserializeCollection<TSerializer>.ParseCollection<T>(null, null, null);
  561. DeserializeListWithElements<T, TSerializer>.ParseGenericList(null, null, null);
  562. SpecializedQueueElements<T>.ConvertToQueue(null);
  563. SpecializedQueueElements<T>.ConvertToStack(null);
  564. */
  565. WriteListsOfElements<T, TSerializer>.WriteList(null, null);
  566. WriteListsOfElements<T, TSerializer>.WriteIList(null, null);
  567. WriteListsOfElements<T, TSerializer>.WriteEnumerable(null, null);
  568. WriteListsOfElements<T, TSerializer>.WriteListValueType(null, null);
  569. WriteListsOfElements<T, TSerializer>.WriteIListValueType(null, null);
  570. WriteListsOfElements<T, TSerializer>.WriteGenericArrayValueType(null, null);
  571. WriteListsOfElements<T, TSerializer>.WriteArray(null, null);
  572. TranslateListWithElements<T>.LateBoundTranslateToGenericICollection(null, null);
  573. TranslateListWithConvertibleElements<T, T>.LateBoundTranslateToGenericICollection(null, null);
  574. QueryStringWriter<T>.WriteObject(null, null);
  575. return i;
  576. }
  577. internal static void RegisterElement<T, TElement, TSerializer>() where TSerializer : ITypeSerializer
  578. {
  579. DeserializeDictionary<TSerializer>.ParseDictionary<T, TElement>(null, null, null, null);
  580. DeserializeDictionary<TSerializer>.ParseDictionary<TElement, T>(null, null, null, null);
  581. ToStringDictionaryMethods<T, TElement, TSerializer>.WriteIDictionary(null, null, null, null);
  582. ToStringDictionaryMethods<TElement, T, TSerializer>.WriteIDictionary(null, null, null, null);
  583. // Include List deserialisations from the Register<> method above. This solves issue where List<Guid> properties on responses deserialise to null.
  584. // No idea why this is happening because there is no visible exception raised. Suspect MonoTouch is swallowing an AOT exception somewhere.
  585. DeserializeArrayWithElements<TElement, TSerializer>.ParseGenericArray(null, null);
  586. DeserializeListWithElements<TElement, TSerializer>.ParseGenericList(null, null, null);
  587. // Cannot use the line below for some unknown reason - when trying to compile to run on device, mtouch bombs during native code compile.
  588. // Something about this line or its inner workings is offensive to mtouch. Luckily this was not needed for my List<Guide> issue.
  589. // DeserializeCollection<JsonTypeSerializer>.ParseCollection<TElement>(null, null, null);
  590. TranslateListWithElements<TElement>.LateBoundTranslateToGenericICollection(null, typeof(List<TElement>));
  591. TranslateListWithConvertibleElements<TElement, TElement>.LateBoundTranslateToGenericICollection(null, typeof(List<TElement>));
  592. }
  593. }
  594. #endif
  595. /// <summary>
  596. /// Set this to enable your own type construction provider.
  597. /// This is helpful for integration with IoC containers where you need to call the container constructor.
  598. /// Return null if you don't know how to construct the type and the parameterless constructor will be used.
  599. /// </summary>
  600. public static EmptyCtorFactoryDelegate ModelFactory { get; set; }
  601. }
  602. #if MONOTOUCH
  603. [MonoTouch.Foundation.Preserve(AllMembers=true)]
  604. internal class Poco
  605. {
  606. public string Dummy { get; set; }
  607. }
  608. #endif
  609. public class JsConfig<T>
  610. {
  611. /// <summary>
  612. /// Always emit type info for this type. Takes precedence over ExcludeTypeInfo
  613. /// </summary>
  614. public static bool IncludeTypeInfo = false;
  615. /// <summary>
  616. /// Never emit type info for this type
  617. /// </summary>
  618. public static bool ExcludeTypeInfo = false;
  619. /// <summary>
  620. /// <see langword="true"/> if the <see cref="ITypeSerializer"/> is configured
  621. /// to take advantage of <see cref="CLSCompliantAttribute"/> specification,
  622. /// to support user-friendly serialized formats, ie emitting camelCasing for JSON
  623. /// and parsing member names and enum values in a case-insensitive manner.
  624. /// </summary>
  625. public static bool EmitCamelCaseNames = false;
  626. /// <summary>
  627. /// Define custom serialization fn for BCL Structs
  628. /// </summary>
  629. private static Func<T, string> serializeFn;
  630. public static Func<T, string> SerializeFn
  631. {
  632. get { return serializeFn; }
  633. set
  634. {
  635. serializeFn = value;
  636. if (value != null)
  637. JsConfig.HasSerializeFn.Add(typeof(T));
  638. else
  639. JsConfig.HasSerializeFn.Remove(typeof(T));
  640. }
  641. }
  642. /// <summary>
  643. /// Opt-in flag to set some Value Types to be treated as a Ref Type
  644. /// </summary>
  645. public bool TreatValueAsRefTypes
  646. {
  647. get { return JsConfig.TreatValueAsRefTypes.Contains(typeof(T)); }
  648. set
  649. {
  650. if (value)
  651. JsConfig.TreatValueAsRefTypes.Add(typeof(T));
  652. else
  653. JsConfig.TreatValueAsRefTypes.Remove(typeof(T));
  654. }
  655. }
  656. /// <summary>
  657. /// Whether there is a fn (raw or otherwise)
  658. /// </summary>
  659. public static bool HasSerializeFn
  660. {
  661. get { return serializeFn != null || rawSerializeFn != null; }
  662. }
  663. /// <summary>
  664. /// Define custom raw serialization fn
  665. /// </summary>
  666. private static Func<T, string> rawSerializeFn;
  667. public static Func<T, string> RawSerializeFn
  668. {
  669. get { return rawSerializeFn; }
  670. set
  671. {
  672. rawSerializeFn = value;
  673. if (value != null)
  674. JsConfig.HasSerializeFn.Add(typeof(T));
  675. else
  676. JsConfig.HasSerializeFn.Remove(typeof(T));
  677. }
  678. }
  679. /// <summary>
  680. /// Define custom serialization hook
  681. /// </summary>
  682. private static Func<T, T> onSerializingFn;
  683. public static Func<T, T> OnSerializingFn
  684. {
  685. get { return onSerializingFn; }
  686. set { onSerializingFn = value; }
  687. }
  688. /// <summary>
  689. /// Define custom deserialization fn for BCL Structs
  690. /// </summary>
  691. public static Func<string, T> DeSerializeFn;
  692. /// <summary>
  693. /// Define custom raw deserialization fn for objects
  694. /// </summary>
  695. public static Func<string, T> RawDeserializeFn;
  696. public static bool HasDeserializeFn
  697. {
  698. get { return DeSerializeFn != null || RawDeserializeFn != null; }
  699. }
  700. private static Func<T, T> onDeserializedFn;
  701. public static Func<T, T> OnDeserializedFn
  702. {
  703. get { return onDeserializedFn; }
  704. set { onDeserializedFn = value; }
  705. }
  706. /// <summary>
  707. /// Exclude specific properties of this type from being serialized
  708. /// </summary>
  709. public static string[] ExcludePropertyNames;
  710. public static void WriteFn<TSerializer>(TextWriter writer, object obj)
  711. {
  712. if (RawSerializeFn != null)
  713. {
  714. writer.Write(RawSerializeFn((T)obj));
  715. }
  716. else
  717. {
  718. var serializer = JsWriter.GetTypeSerializer<TSerializer>();
  719. serializer.WriteString(writer, SerializeFn((T)obj));
  720. }
  721. }
  722. public static object ParseFn(string str)
  723. {
  724. return DeSerializeFn(str);
  725. }
  726. internal static object ParseFn(ITypeSerializer serializer, string str)
  727. {
  728. if (RawDeserializeFn != null)
  729. {
  730. return RawDeserializeFn(str);
  731. }
  732. else
  733. {
  734. return DeSerializeFn(serializer.UnescapeString(str));
  735. }
  736. }
  737. }
  738. public enum JsonPropertyConvention
  739. {
  740. /// <summary>
  741. /// The property names on target types must match property names in the JSON source
  742. /// </summary>
  743. ExactMatch,
  744. /// <summary>
  745. /// The property names on target types may not match the property names in the JSON source
  746. /// </summary>
  747. Lenient
  748. }
  749. public enum JsonDateHandler
  750. {
  751. TimestampOffset,
  752. DCJSCompatible,
  753. ISO8601
  754. }
  755. public enum JsonTimeSpanHandler
  756. {
  757. /// <summary>
  758. /// Uses the xsd format like PT15H10M20S
  759. /// </summary>
  760. DurationFormat,
  761. /// <summary>
  762. /// Uses the standard .net ToString method of the TimeSpan class
  763. /// </summary>
  764. StandardFormat
  765. }
  766. }