static Hashtable nameCache;
static Hashtable primitiveTypes;
static Hashtable primitiveArrayTypes;
+ static Hashtable nullableTypes;
#if TARGET_JVM
- const string AppDomainCacheName = "System.Xml.Serialization.TypeTranslator.AppDomainCache";
- static Hashtable AppDomainCache {
- get {
- Hashtable res = (Hashtable)AppDomain.CurrentDomain.GetData(AppDomainCacheName);
-
- if(res == null) {
- lock(AppDomainCacheName) {
- res = (Hashtable)AppDomain.CurrentDomain.GetData(AppDomainCacheName);
- if (res == null) {
- res = new Hashtable();
- AppDomain.CurrentDomain.SetData(AppDomainCacheName, res);
- }
+ static readonly object AppDomain_TypeTranslatorCacheLock = new object ();
+ const string AppDomain_nameCacheName = "System.Xml.Serialization.TypeTranslator.nameCache";
+ const string AppDomain_nullableTypesName = "System.Xml.Serialization.TypeTranslator.nullableTypes";
+
+ static Hashtable AppDomain_nameCache {
+ get { return GetAppDomainCache (AppDomain_nameCacheName); }
+ }
+
+ static Hashtable AppDomain_nullableTypes {
+ get { return GetAppDomainCache (AppDomain_nullableTypesName); }
+ }
+
+ static Hashtable GetAppDomainCache(string name) {
+ Hashtable res = (Hashtable) AppDomain.CurrentDomain.GetData (name);
+
+ if (res == null) {
+ lock (AppDomain_TypeTranslatorCacheLock) {
+ res = (Hashtable) AppDomain.CurrentDomain.GetData (name);
+ if (res == null) {
+ res = Hashtable.Synchronized (new Hashtable ());
+ AppDomain.CurrentDomain.SetData (name, res);
}
}
-
- return res;
}
+
+ return res;
}
#endif
static TypeTranslator ()
{
nameCache = new Hashtable ();
- primitiveArrayTypes = new Hashtable ();
+ primitiveArrayTypes = Hashtable.Synchronized (new Hashtable ());
+#if !TARGET_JVM
+ nameCache = Hashtable.Synchronized (nameCache);
+#endif
// XSD Types with direct map to CLR types
nameCache.Add (typeof (bool), new TypeData (typeof (bool), "boolean", true));
nameCache.Add (typeof (decimal), new TypeData (typeof (decimal), "decimal", true));
nameCache.Add (typeof (XmlQualifiedName), new TypeData (typeof (XmlQualifiedName), "QName", true));
nameCache.Add (typeof (string), new TypeData (typeof (string), "string", true));
+#if !MOONLIGHT
XmlSchemaPatternFacet guidFacet = new XmlSchemaPatternFacet();
guidFacet.Value = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}";
nameCache.Add (typeof (Guid), new TypeData (typeof (Guid), "guid", true, (TypeData)nameCache[typeof (string)], guidFacet));
+#endif
nameCache.Add (typeof (byte), new TypeData (typeof (byte), "unsignedByte", true));
nameCache.Add (typeof (sbyte), new TypeData (typeof (sbyte), "byte", true));
nameCache.Add (typeof (char), new TypeData (typeof (char), "char", true, (TypeData)nameCache[typeof (ushort)], null));
nameCache.Add (typeof (object), new TypeData (typeof (object), "anyType", false));
nameCache.Add (typeof (byte[]), new TypeData (typeof (byte[]), "base64Binary", true));
+#if !MOONLIGHT
nameCache.Add (typeof (XmlNode), new TypeData (typeof (XmlNode), "XmlNode", false));
nameCache.Add (typeof (XmlElement), new TypeData (typeof (XmlElement), "XmlElement", false));
- nameCache.Add (typeof (TimeSpan), new TypeData (typeof (TimeSpan), "duration", true));
+#endif
primitiveTypes = new Hashtable();
ICollection types = nameCache.Values;
primitiveTypes.Add ("normalizedString", new TypeData (typeof (string), "normalizedString", true));
primitiveTypes.Add ("anyURI", new TypeData (typeof (string), "anyURI", true));
primitiveTypes.Add ("base64", new TypeData (typeof (byte[]), "base64", true));
+ primitiveTypes.Add ("duration", new TypeData (typeof (string), "duration", true));
+
+#if NET_2_0
+ nullableTypes = Hashtable.Synchronized(new Hashtable ());
+ foreach (DictionaryEntry de in primitiveTypes) {
+ TypeData td = (TypeData) de.Value;
+ TypeData ntd = new TypeData (td.Type, td.XmlType, true);
+ ntd.IsNullable = true;
+ nullableTypes.Add (de.Key, ntd);
+ }
+#endif
}
public static TypeData GetTypeData (Type type)
return GetTypeData (type, null);
}
- public static TypeData GetTypeData (Type type, string xmlDataType)
+ public static TypeData GetTypeData (Type runtimeType, string xmlDataType, bool underlyingEnumType = false)
{
+ if (underlyingEnumType && runtimeType.IsEnum)
+ runtimeType = Enum.GetUnderlyingType (runtimeType);
+
+ Type type = runtimeType;
+ bool nullableOverride = false;
+#if NET_2_0
+ // Nullable<T> is serialized as T
+ if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>)) {
+ nullableOverride = true;
+ type = type.GetGenericArguments () [0];
+ }
+
+
if ((xmlDataType != null) && (xmlDataType.Length != 0)) {
// If the type is an array, xmlDataType specifies the type for the array elements,
// not for the whole array. The exception is base64Binary, since it is a byte[],
// that's why the following check is needed.
TypeData at = GetPrimitiveTypeData (xmlDataType);
if (type.IsArray && type != at.Type) {
- lock (primitiveArrayTypes) {
TypeData tt = (TypeData) primitiveArrayTypes [xmlDataType];
if (tt != null)
return tt;
}
else
throw new InvalidOperationException ("Cannot convert values of type '" + type.GetElementType () + "' to '" + xmlDataType + "'");
+ }
+ if (nullableOverride){
+ TypeData tt = (TypeData) nullableTypes [at.XmlType];
+ if (tt == null){
+ tt = new TypeData (type, at.XmlType, false);
+ tt.IsNullable = true;
+ nullableTypes [at.XmlType] = tt;
}
+ return tt;
}
return at;
}
- lock (nameCache) {
- TypeData typeData = nameCache[type] as TypeData;
+ if (nullableOverride){
+ TypeData pt = GetTypeData (type); // beware this recursive call btw ...
+ if (pt != null) {
+ TypeData tt = (TypeData) nullableTypes [pt.XmlType];
+#if TARGET_JVM
+ if (tt == null)
+ tt = (TypeData) AppDomain_nullableTypes [pt.XmlType];
+#endif
+ if (tt == null) {
+ tt = new TypeData (type, pt.XmlType, false);
+ tt.IsNullable = true;
+#if TARGET_JVM
+ AppDomain_nullableTypes [pt.XmlType] = tt;
+#else
+ nullableTypes [pt.XmlType] = tt;
+#endif
+ }
+ return tt;
+ }
+ }
+#endif
+
+ TypeData typeData = nameCache[runtimeType] as TypeData;
if (typeData != null) return typeData;
#if TARGET_JVM
- Hashtable dynamicCache = AppDomainCache;
- typeData = dynamicCache[type] as TypeData;
+ Hashtable dynamicCache = AppDomain_nameCache;
+ typeData = dynamicCache[runtimeType] as TypeData;
if (typeData != null) return typeData;
#endif
-
+
string name;
if (type.IsArray) {
string sufix = GetTypeData (type.GetElementType ()).XmlType;
name = GetArrayName (sufix);
}
+#if NET_2_0
+ else if (type.IsGenericType && !type.IsGenericTypeDefinition) {
+ name = XmlConvert.EncodeLocalName (type.Name.Substring (0, type.Name.IndexOf ('`'))) + "Of";
+ foreach (Type garg in type.GetGenericArguments ())
+ name += garg.IsArray || garg.IsGenericType ?
+ GetTypeData (garg).XmlType :
+ CodeIdentifier.MakePascal (XmlConvert.EncodeLocalName (garg.Name));
+ }
+#endif
else
name = XmlConvert.EncodeLocalName (type.Name);
typeData = new TypeData (type, name, false);
+ if (nullableOverride)
+ typeData.IsNullable = true;
#if TARGET_JVM
- dynamicCache[type] = typeData;
+ dynamicCache[runtimeType] = typeData;
#else
- nameCache[type] = typeData;
+ nameCache[runtimeType] = typeData;
#endif
return typeData;
- }
}
public static bool IsPrimitive (Type type)
public static TypeData GetPrimitiveTypeData (string typeName)
{
- TypeData td = (TypeData) primitiveTypes[typeName];
+ return GetPrimitiveTypeData (typeName, false);
+ }
+
+ public static TypeData GetPrimitiveTypeData (string typeName, bool nullable)
+ {
+ TypeData td = (TypeData) primitiveTypes [typeName];
+ if (td != null && !td.Type.IsValueType)
+ return td;
+ // for 1.x profile, 'nullableTypes' is null
+ Hashtable table = nullable && nullableTypes != null ? nullableTypes : primitiveTypes;
+ td = (TypeData) table [typeName];
if (td == null) throw new NotSupportedException ("Data type '" + typeName + "' not supported");
return td;
}
if (primType.SchemaType == SchemaTypes.Primitive)
{
- TypeData newPrim = GetTypeData (primType.Type);
+ TypeData newPrim = GetTypeData (primType.Type, null);
if (newPrim != primType) return newPrim;
}
return primType;