5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2008 Novell, Inc (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Collections.ObjectModel;
32 using System.Globalization;
34 using System.Reflection;
38 namespace System.Runtime.Serialization.Json
42 static bool IsInvalidNCName (string name)
44 if (name == null || name.Length == 0)
47 XmlConvert.VerifyNCName (name);
48 } catch (XmlException) {
54 public static TypeMap CreateTypeMap (Type type)
56 object [] atts = type.GetCustomAttributes (typeof (DataContractAttribute), true);
58 return CreateTypeMap (type, (DataContractAttribute) atts [0]);
60 atts = type.GetCustomAttributes (typeof (SerializableAttribute), false);
62 return CreateTypeMap (type, null);
67 static TypeMap CreateTypeMap (Type type, DataContractAttribute dca)
69 if (dca != null && dca.Name != null && IsInvalidNCName (dca.Name))
70 throw new InvalidDataContractException (String.Format ("DataContractAttribute for type '{0}' has an invalid name", type));
72 List<TypeMapMember> members = new List<TypeMapMember> ();
74 foreach (FieldInfo fi in type.GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
76 object [] atts = fi.GetCustomAttributes (typeof (DataMemberAttribute), true);
79 DataMemberAttribute dma = (DataMemberAttribute) atts [0];
80 members.Add (new TypeMapField (fi, dma));
82 if (fi.GetCustomAttributes (typeof (NonSerializedAttribute), false).Length > 0)
84 members.Add (new TypeMapField (fi, null));
89 foreach (PropertyInfo pi in type.GetProperties (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
90 if (pi.GetIndexParameters ().Length > 0)
92 if (!pi.CanRead || !pi.CanWrite)
93 throw new InvalidDataContractException (String.Format ("Property {0} must have both getter and setter", pi));
94 object [] atts = pi.GetCustomAttributes (typeof (DataMemberAttribute), true);
97 DataMemberAttribute dma = (DataMemberAttribute) atts [0];
98 members.Add (new TypeMapProperty (pi, dma));
102 members.Sort (delegate (TypeMapMember m1, TypeMapMember m2) { return m1.Order - m2.Order; });
103 return new TypeMap (type, dca == null ? null : dca.Name, members.ToArray ());
108 TypeMapMember [] members;
110 public TypeMap (Type type, string element, TypeMapMember [] orderedMembers)
113 this.element = element;
114 this.members = orderedMembers;
117 public void Serialize (JsonSerializationWriter outputter, object graph)
119 foreach (TypeMapMember member in members) {
120 object memberObj = member.GetMemberOf (graph);
121 // FIXME: consider EmitDefaultValue
122 outputter.Writer.WriteStartElement (member.Name);
123 outputter.WriteObjectContent (memberObj, false, false);
124 outputter.Writer.WriteEndElement ();
128 public object Deserialize (JsonSerializationReader jsr)
130 XmlReader reader = jsr.Reader;
132 object ret = Activator.CreateInstance (type, true);
133 Dictionary<TypeMapMember,bool> filled = new Dictionary<TypeMapMember,bool> ();
135 reader.ReadStartElement ();
136 for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
137 bool consumed = false;
138 for (int i = 0; i < members.Length; i++) {
139 TypeMapMember mm = members [i];
140 if (mm.Name == reader.LocalName && reader.NamespaceURI == String.Empty) {
141 if (filled.ContainsKey (mm))
142 throw new SerializationException (String.Format ("Object content '{0}' for '{1}' already appeared in the reader", reader.LocalName, type));
143 mm.SetMemberValue (ret, jsr.ReadObject (mm.Type));
152 reader.ReadEndElement ();
157 abstract class TypeMapMember
160 DataMemberAttribute dma;
162 protected TypeMapMember (MemberInfo mi, DataMemberAttribute dma)
169 get { return dma == null ? mi.Name : dma.Name ?? mi.Name; }
172 // FIXME: Fill 3.5 member in s.r.serialization.
173 // public bool EmitDefaultValue {
174 // get { return dma != null && dma.EmitDefaultValue; }
177 public bool IsRequired {
178 get { return dma != null && dma.IsRequired; }
182 get { return dma != null ? dma.Order : -1; }
185 public abstract Type Type { get; }
187 public abstract object GetMemberOf (object owner);
189 public abstract void SetMemberValue (object owner, object value);
192 class TypeMapField : TypeMapMember
196 public TypeMapField (FieldInfo fi, DataMemberAttribute dma)
202 public override Type Type {
203 get { return field.FieldType; }
206 public override object GetMemberOf (object owner)
208 return field.GetValue (owner);
211 public override void SetMemberValue (object owner, object value)
213 field.SetValue (owner, value);
217 class TypeMapProperty : TypeMapMember
219 PropertyInfo property;
221 public TypeMapProperty (PropertyInfo pi, DataMemberAttribute dma)
227 public override Type Type {
228 get { return property.PropertyType; }
231 public override object GetMemberOf (object owner)
233 return property.GetValue (owner, null);
236 public override void SetMemberValue (object owner, object value)
238 property.SetValue (owner, value, null);