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