move to from olive to mcs
[mono.git] / mcs / class / System.ServiceModel.Web / System.Runtime.Serialization.Json / TypeMap.cs
1 //
2 // TypeMap.cs
3 //
4 // Author:
5 //      Atsushi Enomoto  <atsushi@ximian.com>
6 //
7 // Copyright (C) 2008 Novell, Inc (http://www.novell.com)
8 //
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:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
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.
27 //
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Collections.ObjectModel;
32 using System.Globalization;
33 using System.IO;
34 using System.Reflection;
35 using System.Text;
36 using System.Xml;
37
38 namespace System.Runtime.Serialization.Json
39 {
40         class TypeMap
41         {
42                 static bool IsInvalidNCName (string name)
43                 {
44                         if (name == null || name.Length == 0)
45                                 return true;
46                         try {
47                                 XmlConvert.VerifyNCName (name);
48                         } catch (XmlException) {
49                                 return true;
50                         }
51                         return false;
52                 }
53
54                 public static TypeMap CreateTypeMap (Type type)
55                 {
56                         object [] atts = type.GetCustomAttributes (typeof (DataContractAttribute), true);
57                         if (atts.Length == 1)
58                                 return CreateTypeMap (type, (DataContractAttribute) atts [0]);
59
60                         atts = type.GetCustomAttributes (typeof (SerializableAttribute), false);
61                         if (atts.Length == 1)
62                                 return CreateTypeMap (type, null);
63
64                         return null;
65                 }
66
67                 static TypeMap CreateTypeMap (Type type, DataContractAttribute dca)
68                 {
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));
71
72                         List<TypeMapMember> members = new List<TypeMapMember> ();
73
74                         foreach (FieldInfo fi in type.GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
75                                 if (dca != null) {
76                                         object [] atts = fi.GetCustomAttributes (typeof (DataMemberAttribute), true);
77                                         if (atts.Length == 0)
78                                                 continue;
79                                         DataMemberAttribute dma = (DataMemberAttribute) atts [0];
80                                         members.Add (new TypeMapField (fi, dma));
81                                 } else {
82                                         if (fi.GetCustomAttributes (typeof (NonSerializedAttribute), false).Length > 0)
83                                                 continue;
84                                         members.Add (new TypeMapField (fi, null));
85                                 }
86                         }
87
88                         if (dca != null) {
89                                 foreach (PropertyInfo pi in type.GetProperties (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
90                                         if (pi.GetIndexParameters ().Length > 0)
91                                                 continue;
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);
95                                         if (atts.Length == 0)
96                                                 continue;
97                                         DataMemberAttribute dma = (DataMemberAttribute) atts [0];
98                                         members.Add (new TypeMapProperty (pi, dma));
99                                 }
100                         }
101
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 ());
104                 }
105
106                 Type type;
107                 string element;
108                 TypeMapMember [] members;
109
110                 public TypeMap (Type type, string element, TypeMapMember [] orderedMembers)
111                 {
112                         this.type = type;
113                         this.element = element;
114                         this.members = orderedMembers;
115                 }
116
117                 public void Serialize (JsonSerializationWriter outputter, object graph)
118                 {
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 ();
125                         }
126                 }
127
128                 public object Deserialize (JsonSerializationReader jsr)
129                 {
130                         XmlReader reader = jsr.Reader;
131
132                         object ret = Activator.CreateInstance (type, true);
133                         Dictionary<TypeMapMember,bool> filled = new Dictionary<TypeMapMember,bool> ();
134
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));
144                                                 filled [mm] = true;
145                                                 consumed = true;
146                                                 break;
147                                         }
148                                 }
149                                 if (!consumed)
150                                         reader.Skip ();
151                         }
152                         reader.ReadEndElement ();
153                         return ret;
154                 }
155         }
156
157         abstract class TypeMapMember
158         {
159                 MemberInfo mi;
160                 DataMemberAttribute dma;
161
162                 protected TypeMapMember (MemberInfo mi, DataMemberAttribute dma)
163                 {
164                         this.mi = mi;
165                         this.dma = dma;
166                 }
167
168                 public string Name {
169                         get { return dma == null ? mi.Name : dma.Name ?? mi.Name; }
170                 }
171
172                 // FIXME: Fill 3.5 member in s.r.serialization.
173 //              public bool EmitDefaultValue {
174 //                      get { return dma != null && dma.EmitDefaultValue; }
175 //              }
176
177                 public bool IsRequired {
178                         get { return dma != null && dma.IsRequired; }
179                 }
180
181                 public int Order {
182                         get { return dma != null ? dma.Order : -1; }
183                 }
184
185                 public abstract Type Type { get; }
186
187                 public abstract object GetMemberOf (object owner);
188
189                 public abstract void SetMemberValue (object owner, object value);
190         }
191
192         class TypeMapField : TypeMapMember
193         {
194                 FieldInfo field;
195
196                 public TypeMapField (FieldInfo fi, DataMemberAttribute dma)
197                         : base (fi, dma)
198                 {
199                         this.field = fi;
200                 }
201
202                 public override Type Type {
203                         get { return field.FieldType; }
204                 }
205
206                 public override object GetMemberOf (object owner)
207                 {
208                         return field.GetValue (owner);
209                 }
210
211                 public override void SetMemberValue (object owner, object value)
212                 {
213                         field.SetValue (owner, value);
214                 }
215         }
216
217         class TypeMapProperty : TypeMapMember
218         {
219                 PropertyInfo property;
220
221                 public TypeMapProperty (PropertyInfo pi, DataMemberAttribute dma)
222                         : base (pi, dma)
223                 {
224                         this.property = pi;
225                 }
226
227                 public override Type Type {
228                         get { return property.PropertyType; }
229                 }
230
231                 public override object GetMemberOf (object owner)
232                 {
233                         return property.GetValue (owner, null);
234                 }
235
236                 public override void SetMemberValue (object owner, object value)
237                 {
238                         property.SetValue (owner, value, null);
239                 }
240         }
241 }