Free cookie consent management tool by TermsFeed Policy Generator

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

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

Reuse serializer instances for different types and provide better error information. (#603)

File size: 6.9 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 Deserializer {
12
13    class Midwife {
14
15      public int? Id { get; private set; }
16      public bool MetaMode { get; set; }
17      public object Obj { get; private set; }
18
19      private List<Tag> metaInfo;
20      private List<Tag> customValues;
21      private Type type;
22      private ICompositeSerializer compositeSerializer;
23
24      public Midwife(object value) {
25        this.Obj = value;
26      }
27
28      public Midwife(Type type, ICompositeSerializer compositeSerializer, int? id) {
29        this.type = type;
30        this.compositeSerializer = compositeSerializer;
31        this.Id = id;
32        MetaMode = false;
33        metaInfo = new List<Tag>();
34        customValues = new List<Tag>();
35      }
36
37      public void CreateInstance() {
38        if (Obj != null)
39          throw new PersistenceException("object already instantiated");
40        Obj = compositeSerializer.CreateInstance(type, metaInfo);
41      }
42
43      public void AddValue(string name, object value) {
44        if (MetaMode) {
45          metaInfo.Add(new Tag(name, value));
46        } else {
47          customValues.Add(new Tag(name, value));
48        }
49      }
50
51      public void Populate() {
52        compositeSerializer.Populate(Obj, customValues, type);
53      }
54    }
55
56    private readonly Dictionary<int, object> id2obj;
57    private readonly Dictionary<Type, object> serializerMapping;
58    private readonly Stack<Midwife> parentStack;
59    private readonly Dictionary<int, Type> typeIds;
60
61    public Deserializer(
62      IEnumerable<TypeMapping> typeCache) {
63      id2obj = new Dictionary<int, object>();
64      parentStack = new Stack<Midwife>();
65      typeIds = new Dictionary<int, Type>();
66      serializerMapping = CreateSerializers(typeCache);
67    }
68
69    private Dictionary<Type, object> CreateSerializers(IEnumerable<TypeMapping> typeCache) {
70      Dictionary<Type, object> serializerInstances = new Dictionary<Type, object>();
71      try {
72        var map = new Dictionary<Type, object>();
73        foreach (var typeMapping in typeCache) {
74          Type type = TypeLoader.Load(typeMapping.TypeName);
75          typeIds.Add(typeMapping.Id, type);
76          Type serializerType = TypeLoader.Load(typeMapping.Serializer);
77          object serializer;
78          if (serializerInstances.ContainsKey(serializerType))
79            serializer = serializerInstances[serializerType];
80          else
81            serializer = Activator.CreateInstance(serializerType, true);
82          map.Add(type, serializer);
83        }
84        return map;
85      } catch (PersistenceException) {
86        throw;
87      } catch (Exception e) {
88        throw new PersistenceException(
89          "The serialization type cache could not be loaded.\r\n" +
90          "This usualy happens when you are missing an Assembly or Plugin.", e);
91      }
92    }
93
94
95    public object Deserialize(IEnumerable<ISerializationToken> tokens) {
96      foreach (ISerializationToken token in tokens) {
97        Type t = token.GetType();
98        if (t == typeof(BeginToken)) {
99          CompositeStartHandler((BeginToken)token);
100        } else if (t == typeof(EndToken)) {
101          CompositeEndHandler((EndToken)token);
102        } else if (t == typeof(PrimitiveToken)) {
103          PrimitiveHandler((PrimitiveToken)token);
104        } else if (t == typeof(ReferenceToken)) {
105          ReferenceHandler((ReferenceToken)token);
106        } else if (t == typeof(NullReferenceToken)) {
107          NullHandler((NullReferenceToken)token);
108        } else if (t == typeof(MetaInfoBeginToken)) {
109          MetaInfoBegin((MetaInfoBeginToken)token);
110        } else if (t == typeof(MetaInfoEndToken)) {
111          MetaInfoEnd((MetaInfoEndToken)token);
112        } else {
113          throw new PersistenceException("invalid token type");
114        }
115      }
116      return parentStack.Pop().Obj;
117    }
118
119    private void CompositeStartHandler(BeginToken token) {
120      Type type = typeIds[(int)token.TypeId];
121      try {
122        parentStack.Push(new Midwife(type, (ICompositeSerializer)serializerMapping[type], token.Id));
123      } catch (Exception e) {
124        if (e is InvalidCastException || e is KeyNotFoundException) {
125          throw new PersistenceException(String.Format(
126            "Invalid composite serializer configuration for type \"{0}\".",
127            type.AssemblyQualifiedName), e);
128        } else {
129          throw new PersistenceException(String.Format(
130            "Unexpected exception while trying to compose object of type \"{0}\".",
131            type.AssemblyQualifiedName), e);
132        }
133      }
134    }
135
136    private void CompositeEndHandler(EndToken token) {
137      Type type = typeIds[(int)token.TypeId];
138      Midwife midwife = parentStack.Pop();
139      if (midwife.Obj == null)
140        CreateInstance(midwife);
141      midwife.Populate();
142      SetValue(token.Name, midwife.Obj);
143    }
144
145    private void PrimitiveHandler(PrimitiveToken token) {
146      Type type = typeIds[(int)token.TypeId];
147      try {
148        object value = ((IPrimitiveSerializer)serializerMapping[type]).Parse(token.SerialData);
149        if (token.Id != null)
150          id2obj[(int)token.Id] = value;
151        SetValue(token.Name, value);
152      } catch (Exception e) {
153        if (e is InvalidCastException || e is KeyNotFoundException) {
154          throw new PersistenceException(String.Format(
155            "Invalid primitive serializer configuration for type \"{0}\".",
156            type.AssemblyQualifiedName), e);
157        } else {
158          throw new PersistenceException(String.Format(
159            "Unexpected exception while trying to parse object of type \"{0}\".",
160            type.AssemblyQualifiedName), e);
161        }
162      }
163    }
164
165    private void ReferenceHandler(ReferenceToken token) {
166      object referredObject = id2obj[token.Id];
167      SetValue(token.Name, referredObject);
168    }
169
170    private void NullHandler(NullReferenceToken token) {
171      SetValue(token.Name, null);
172    }
173
174    private void MetaInfoBegin(MetaInfoBeginToken token) {
175      parentStack.Peek().MetaMode = true;
176    }
177
178    private void MetaInfoEnd(MetaInfoEndToken token) {
179      Midwife m = parentStack.Peek();
180      m.MetaMode = false;
181      CreateInstance(m);
182    }
183
184    private void CreateInstance(Midwife m) {
185      m.CreateInstance();
186      if (m.Id != null)
187        id2obj.Add((int)m.Id, m.Obj);
188    }
189
190    private void SetValue(string name, object value) {
191      if (parentStack.Count == 0) {
192        parentStack.Push(new Midwife(value));
193      } else {
194        Midwife m = parentStack.Peek();
195        if (m.MetaMode == false && m.Obj == null)
196          CreateInstance(m);
197        m.AddValue(name, value);
198      }
199    }
200  }
201}
Note: See TracBrowser for help on using the repository browser.