Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Persistence/3.3/Core/DeSerializer.cs @ 1795

Last change on this file since 1795 was 1795, checked in by epitzer, 15 years ago

Also make sure major and minor version match (not only newer) + better tests. (#613)

File size: 7.6 KB
Line 
1using System.Collections.Generic;
2using System;
3using HeuristicLab.Persistence.Interfaces;
4using HeuristicLab.Persistence.Core.Tokens;
5using HeuristicLab.Persistence.Auxiliary;
6using HeuristicLab.Tracing;
7using System.Reflection;
8
9namespace HeuristicLab.Persistence.Core {
10
11  public class TypeLoader {
12
13    public static Type Load(string typeNameString) {
14      Type type;
15      try {
16        type = Type.GetType(typeNameString, true);
17      } catch (Exception) {
18        Logger.Warn(String.Format(
19          "Cannot load type \"{0}\", falling back to partial name", typeNameString));
20        try {
21          TypeName typeName = TypeNameParser.Parse(typeNameString);
22          Assembly a = Assembly.LoadWithPartialName(typeName.AssemblyName);
23          type = a.GetType(typeName.ToString(false, false), true);
24        } catch (Exception) {
25          throw new PersistenceException(String.Format(
26            "Could not load type \"{0}\"",
27            typeNameString));
28        }
29        try {
30          TypeName requestedTypeName = TypeNameParser.Parse(typeNameString);
31          TypeName loadedTypeName = TypeNameParser.Parse(type.AssemblyQualifiedName);
32          if (!requestedTypeName.IsCompatible(loadedTypeName))
33            throw new PersistenceException(String.Format(
34              "Serialized type is incompatible with available type: serialized: {0}, loaded: {1}",
35              typeNameString,
36              type.AssemblyQualifiedName));
37          if (requestedTypeName.IsNewerThan(loadedTypeName))
38            throw new PersistenceException(String.Format(
39              "Serialized type is newer than available type: serialized: {0}, loaded: {1}",
40              typeNameString,
41              type.AssemblyQualifiedName));
42        } catch (PersistenceException) {
43          throw;
44        } catch (Exception e) {
45          Logger.Warn(String.Format(
46            "Could not perform version check requested type was {0} while loaded type is {1}:",
47            typeNameString,
48            type.AssemblyQualifiedName),
49            e);
50        }
51      }
52      return type;
53    }
54
55  }
56
57  public class Deserializer {
58
59    class Midwife {
60
61      public int? Id { get; private set; }
62      public bool MetaMode { get; set; }
63      public object Obj { get; private set; }
64
65      private List<Tag> metaInfo;
66      private List<Tag> customValues;
67      private Type type;
68      private IDecomposer decomposer;
69
70      public Midwife(object value) {
71        this.Obj = value;
72      }
73
74      public Midwife(Type type, IDecomposer decomposer, int? id) {
75        this.type = type;
76        this.decomposer = decomposer;
77        this.Id = id;
78        MetaMode = false;
79        metaInfo = new List<Tag>();
80        customValues = new List<Tag>();
81      }
82
83      public void CreateInstance() {
84        if (Obj != null)
85          throw new PersistenceException("object already instantiated");
86        Obj = decomposer.CreateInstance(type, metaInfo);
87      }
88
89      public void AddValue(string name, object value) {
90        if (MetaMode) {
91          metaInfo.Add(new Tag(name, value));
92        } else {
93          customValues.Add(new Tag(name, value));
94        }
95      }
96
97      public void Populate() {
98        decomposer.Populate(Obj, customValues, type);
99      }
100    }
101
102    private readonly Dictionary<int, object> id2obj;
103    private readonly Dictionary<Type, object> serializerMapping;
104    private readonly Stack<Midwife> parentStack;
105    private readonly Dictionary<int, Type> typeIds;
106
107    public Deserializer(
108      IEnumerable<TypeMapping> typeCache) {
109      id2obj = new Dictionary<int, object>();
110      parentStack = new Stack<Midwife>();
111      typeIds = new Dictionary<int, Type>();
112      serializerMapping = CreateSerializers(typeCache);
113    }
114
115    private Dictionary<Type, object> CreateSerializers(IEnumerable<TypeMapping> typeCache) {
116      try {
117        var map = new Dictionary<Type, object>();
118        foreach (var typeMapping in typeCache) {
119          Type type = TypeLoader.Load(typeMapping.TypeName);
120          typeIds.Add(typeMapping.Id, type);
121          Type serializerType = TypeLoader.Load(typeMapping.Serializer);
122          map.Add(type, Activator.CreateInstance(serializerType, true));
123        }
124        return map;
125      } catch (PersistenceException) {
126        throw;
127      } catch (Exception e) {
128        throw new PersistenceException(
129          "The serialization type cache could not be loaded.\r\n" +
130          "This usualy happens when you are missing an Assembly/Plugin.", e);
131      }
132    }
133
134
135    public object Deserialize(IEnumerable<ISerializationToken> tokens) {
136      foreach (ISerializationToken token in tokens) {
137        Type t = token.GetType();
138        if (t == typeof(BeginToken)) {
139          CompositeStartHandler((BeginToken)token);
140        } else if (t == typeof(EndToken)) {
141          CompositeEndHandler((EndToken)token);
142        } else if (t == typeof(PrimitiveToken)) {
143          PrimitiveHandler((PrimitiveToken)token);
144        } else if (t == typeof(ReferenceToken)) {
145          ReferenceHandler((ReferenceToken)token);
146        } else if (t == typeof(NullReferenceToken)) {
147          NullHandler((NullReferenceToken)token);
148        } else if (t == typeof(MetaInfoBeginToken)) {
149          MetaInfoBegin((MetaInfoBeginToken)token);
150        } else if (t == typeof(MetaInfoEndToken)) {
151          MetaInfoEnd((MetaInfoEndToken)token);
152        } else {
153          throw new PersistenceException("invalid token type");
154        }
155      }
156      return parentStack.Pop().Obj;
157    }
158
159    private void CompositeStartHandler(BeginToken token) {
160      Type type = typeIds[(int)token.TypeId];
161      IDecomposer decomposer = null;
162      if (serializerMapping.ContainsKey(type))
163        decomposer = serializerMapping[type] as IDecomposer;
164      if (decomposer == null)
165        throw new PersistenceException(String.Format(
166          "No suitable method for deserialization of type \"{0}\" found.",
167          type.VersionInvariantName()));
168      parentStack.Push(new Midwife(type, decomposer, token.Id));
169    }
170
171    private void CompositeEndHandler(EndToken token) {
172      Type type = typeIds[(int)token.TypeId];
173      Midwife midwife = parentStack.Pop();
174      if (midwife.Obj == null)
175        CreateInstance(midwife);
176      midwife.Populate();
177      SetValue(token.Name, midwife.Obj);
178    }
179
180    private void PrimitiveHandler(PrimitiveToken token) {
181      Type type = typeIds[(int)token.TypeId];
182      object value = ((IFormatter)serializerMapping[type]).Parse(token.SerialData);
183      if (token.Id != null)
184        id2obj[(int)token.Id] = value;
185      SetValue(token.Name, value);
186    }
187
188    private void ReferenceHandler(ReferenceToken token) {
189      object referredObject = id2obj[token.Id];
190      SetValue(token.Name, referredObject);
191    }
192
193    private void NullHandler(NullReferenceToken token) {
194      SetValue(token.Name, null);
195    }
196
197    private void MetaInfoBegin(MetaInfoBeginToken token) {
198      parentStack.Peek().MetaMode = true;
199    }
200
201    private void MetaInfoEnd(MetaInfoEndToken token) {
202      Midwife m = parentStack.Peek();
203      m.MetaMode = false;
204      CreateInstance(m);
205    }
206
207    private void CreateInstance(Midwife m) {
208      m.CreateInstance();
209      if (m.Id != null)
210        id2obj.Add((int)m.Id, m.Obj);
211    }
212
213    private void SetValue(string name, object value) {
214      if (parentStack.Count == 0) {
215        parentStack.Push(new Midwife(value));
216      } else {
217        Midwife m = parentStack.Peek();
218        if (m.MetaMode == false && m.Obj == null)
219          CreateInstance(m);
220        m.AddValue(name, value);
221      }
222    }
223  }
224}
Note: See TracBrowser for help on using the repository browser.