Skip to content

Commit

Permalink
[bcl] Implement KnownTypes for DataContractJsonSerializer. Fixes #230…
Browse files Browse the repository at this point in the history
…58 and polymorphism support.

Also discarded old __type hint behavior in JsonSerializationReader that potentially allowed any loaded type to be instantiated.
  • Loading branch information
alexischr committed Oct 7, 2014
1 parent fbea921 commit 71e152a
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,17 @@ public DataContractJsonSerializer (Type type, XmlDictionaryString rootName, IEnu
throw new ArgumentOutOfRangeException ("maxItemsInObjectGraph");

this.type = type;
known_types = new ReadOnlyCollection<Type> (knownTypes != null ? knownTypes.ToArray () : Type.EmptyTypes);

var knownTypesFromAttributes = new List<Type> ();

foreach (var attr in type.GetCustomAttributes (typeof(KnownTypeAttribute)))
knownTypesFromAttributes.Add ((attr as KnownTypeAttribute).Type);

if (knownTypes != null)
knownTypesFromAttributes.AddRange (knownTypes);

known_types = new ReadOnlyCollection<Type> (knownTypesFromAttributes);

root = rootName;
max_items = maxItemsInObjectGraph;
ignore_extension = ignoreExtensionDataObject;
Expand Down Expand Up @@ -134,8 +144,6 @@ public IDataContractSurrogate DataContractSurrogate {
public bool IgnoreExtensionDataObject {
get { return ignore_extension; }
}

[MonoTODO]
public ReadOnlyCollection<Type> KnownTypes {
get { return known_types; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,18 @@ public object ReadObject (Type type, object instance)
if (ct != null) {
return DeserializeGenericCollection (type, ct, instance);
} else {
TypeMap map = GetTypeMap (type);
return map.Deserialize (this, instance);
string typeHint = reader.GetAttribute ("__type");
if (typeHint != null) {
// this might be a derived & known type. We allow it when it's both.
Type exactType = GetRuntimeType (typeHint, type);
if (exactType == null)
throw SerializationError (String.Format ("Cannot load type '{0}'", typeHint));
TypeMap map = GetTypeMap (exactType);
return map.Deserialize (this, instance);
} else { // no type hint
TypeMap map = GetTypeMap (type);
return map.Deserialize (this, instance);
}
}
}
else
Expand All @@ -198,24 +208,22 @@ object ReadValueType (Type type, bool nullable)
}


Type GetRuntimeType (string name)
Type GetRuntimeType (string name, Type baseType)
{
name = ToRuntimeTypeName (name);
string properName = ToRuntimeTypeName (name);

if (baseType != null && baseType.FullName.Equals (properName))
return baseType;

if (serializer.KnownTypes != null)
foreach (Type t in serializer.KnownTypes)
if (t.FullName == name)
if (t.FullName.Equals (properName))
return t;
var ret = root_type.Assembly.GetType (name, false) ?? Type.GetType (name, false);
if (ret != null)
return ret;

// We probably have to iterate all the existing
// assemblies that are loaded in current domain.
foreach (var ass in AppDomain.CurrentDomain.GetAssemblies ()) {
ret = ass.GetType (name, false);
if (ret != null)
return ret;
}
if (baseType != null)
foreach (var attr in baseType.GetCustomAttributes (typeof(KnownTypeAttribute)))
if ((attr as KnownTypeAttribute).Type.FullName.Equals (properName))
return (attr as KnownTypeAttribute).Type;

return null;
}
Expand All @@ -230,7 +238,7 @@ object ReadInstanceDrivenObject ()
case "object":
string runtimeType = reader.GetAttribute ("__type");
if (runtimeType != null) {
Type t = GetRuntimeType (runtimeType);
Type t = GetRuntimeType (runtimeType, null);
if (t == null)
throw SerializationError (String.Format ("Cannot load type '{0}'", runtimeType));
return ReadObject (t);
Expand Down

2 comments on commit 71e152a

@akoeplinger
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexischr This breaks the net_2_0 build:

System.Runtime.Serialization.Json/DataContractJsonSerializer.cs(90,30): error CS1502: The best overloaded method match for `System.Reflection.MemberInfo.GetCustomAttributes(bool)' has some invalid arguments
System.Runtime.Serialization.Json/DataContractJsonSerializer.cs(90,51): error CS1503: Argument `#1' cannot convert `System.Type' expression to type `bool'
System.Runtime.Serialization.Json/JsonSerializationReader.cs(224,35): error CS1502: The best overloaded method match for `System.Reflection.MemberInfo.GetCustomAttributes(bool)' has some invalid arguments
System.Runtime.Serialization.Json/JsonSerializationReader.cs(224,56): error CS1503: Argument `#1' cannot convert `System.Type' expression to type `bool'

@alexischr
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@akoeplinger Fixed in e92af12, thanks!

Please sign in to comment.