Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.Persistence/3.3/Core/Deserializer.cs @ 16571

Last change on this file since 16571 was 16565, checked in by gkronber, 6 years ago

#2520: merged changes from PersistenceOverhaul branch (r16451:16564) into trunk

File size: 9.2 KB
RevLine 
[3743]1#region License Information
2/* HeuristicLab
[16565]3 * Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[3743]4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
[4068]22using System;
[3743]23using System.Collections.Generic;
[16565]24using HEAL.Attic;
[4068]25using HeuristicLab.Persistence.Auxiliary;
26using HeuristicLab.Persistence.Core.Tokens;
[1454]27using HeuristicLab.Persistence.Interfaces;
28
[1574]29namespace HeuristicLab.Persistence.Core {
[1454]30
[3004]31  /// <summary>
32  /// Core hub for deserialization. Reads the serialization token stream,
33  /// instantiates objects and fills in values.
34  /// </summary>
[1574]35  public class Deserializer {
[1454]36
[3004]37    /// <summary>
38    /// Helps in delivering the class instance and acts as proxy while
39    /// the object cannot yet be instantiate.
40    /// </summary>
41    private class Midwife {
[1566]42
[1567]43      public int? Id { get; private set; }
44      public bool MetaMode { get; set; }
45      public object Obj { get; private set; }
[1454]46
[1567]47      private List<Tag> metaInfo;
48      private List<Tag> customValues;
49      private Type type;
[1823]50      private ICompositeSerializer compositeSerializer;
[1553]51
[1567]52      public Midwife(object value) {
53        this.Obj = value;
54      }
[1566]55
[1823]56      public Midwife(Type type, ICompositeSerializer compositeSerializer, int? id) {
[1567]57        this.type = type;
[1823]58        this.compositeSerializer = compositeSerializer;
[1567]59        this.Id = id;
60        MetaMode = false;
61        metaInfo = new List<Tag>();
62        customValues = new List<Tag>();
63      }
[1454]64
[1567]65      public void CreateInstance() {
66        if (Obj != null)
[1625]67          throw new PersistenceException("object already instantiated");
[1823]68        Obj = compositeSerializer.CreateInstance(type, metaInfo);
[1567]69      }
[1454]70
[1567]71      public void AddValue(string name, object value) {
72        if (MetaMode) {
73          metaInfo.Add(new Tag(name, value));
74        } else {
75          customValues.Add(new Tag(name, value));
76        }
[1553]77      }
[1454]78
[1567]79      public void Populate() {
[1823]80        compositeSerializer.Populate(Obj, customValues, type);
[1567]81      }
[1553]82    }
[4068]83
[1454]84    private readonly Dictionary<int, object> id2obj;
[1553]85    private readonly Dictionary<Type, object> serializerMapping;
[1566]86    private readonly Stack<Midwife> parentStack;
[1553]87    private readonly Dictionary<int, Type> typeIds;
[4175]88    private Dictionary<Type, object> serializerInstances;
[1454]89
[3004]90    /// <summary>
91    /// Instantiates a new deserializer with the given type cache,
92    /// that contains information about the serializers to use
93    /// for every type and their type ids.
[3016]94    /// </summary>
95    /// <param name="typeCache">The type cache.</param>
[1542]96    public Deserializer(
[1553]97      IEnumerable<TypeMapping> typeCache) {
[1454]98      id2obj = new Dictionary<int, object>();
[1553]99      parentStack = new Stack<Midwife>();
[1454]100      typeIds = new Dictionary<int, Type>();
[3005]101      serializerMapping = new Dictionary<Type, object>();
[4175]102      serializerInstances = new Dictionary<Type, object>();
[3005]103      foreach (var typeMapping in typeCache) {
104        AddTypeInfo(typeMapping);
105      }
[1454]106    }
107
[3016]108    /// <summary>
109    /// Adds additionaly type information.
110    /// </summary>
111    /// <param name="typeMapping">The new type mapping.</param>
[3005]112    public void AddTypeInfo(TypeMapping typeMapping) {
113      if (typeIds.ContainsKey(typeMapping.Id))
114        return;
[1625]115      try {
[3005]116        Type type = TypeLoader.Load(typeMapping.TypeName);
117        typeIds.Add(typeMapping.Id, type);
118        Type serializerType = TypeLoader.Load(typeMapping.Serializer);
119        object serializer;
[4175]120        if (serializerInstances.ContainsKey(serializerType)) {
[3005]121          serializer = serializerInstances[serializerType];
[4175]122        } else {
[3005]123          serializer = Activator.CreateInstance(serializerType, true);
[4175]124          serializerInstances.Add(serializerType, serializer);
125        }
[3005]126        serializerMapping.Add(type, serializer);
[4175]127      } catch (PersistenceException) {
[1779]128        throw;
[4175]129      } catch (Exception e) {
[3005]130        throw new PersistenceException(string.Format(
131          "Could not add type info for {0} ({1})",
132          typeMapping.TypeName, typeMapping.Serializer), e);
[1703]133      }
[1454]134    }
135
[3004]136    /// <summary>
137    /// Process the token stream and deserialize an instantate a new object graph.
[3016]138    /// </summary>
139    /// <param name="tokens">The tokens.</param>
140    /// <returns>A fresh object filled with fresh data.</returns>
[1566]141    public object Deserialize(IEnumerable<ISerializationToken> tokens) {
[1454]142      foreach (ISerializationToken token in tokens) {
143        Type t = token.GetType();
[1566]144        if (t == typeof(BeginToken)) {
[1454]145          CompositeStartHandler((BeginToken)token);
[1566]146        } else if (t == typeof(EndToken)) {
147          CompositeEndHandler((EndToken)token);
148        } else if (t == typeof(PrimitiveToken)) {
149          PrimitiveHandler((PrimitiveToken)token);
150        } else if (t == typeof(ReferenceToken)) {
151          ReferenceHandler((ReferenceToken)token);
[1454]152        } else if (t == typeof(NullReferenceToken)) {
153          NullHandler((NullReferenceToken)token);
[1553]154        } else if (t == typeof(MetaInfoBeginToken)) {
155          MetaInfoBegin((MetaInfoBeginToken)token);
156        } else if (t == typeof(MetaInfoEndToken)) {
157          MetaInfoEnd((MetaInfoEndToken)token);
[3005]158        } else if (t == typeof(TypeToken)) {
159          Type((TypeToken)token);
[1454]160        } else {
[1625]161          throw new PersistenceException("invalid token type");
[1454]162        }
163      }
164      return parentStack.Pop().Obj;
165    }
166
[2873]167    private void InstantiateParent() {
168      if (parentStack.Count == 0)
169        return;
170      Midwife m = parentStack.Peek();
171      if (!m.MetaMode && m.Obj == null)
172        CreateInstance(m);
173    }
174
[3005]175    private void Type(TypeToken token) {
176      AddTypeInfo(new TypeMapping(token.Id, token.TypeName, token.Serializer));
177    }
178
[1553]179    private void CompositeStartHandler(BeginToken token) {
[2873]180      InstantiateParent();
[1454]181      Type type = typeIds[(int)token.TypeId];
[1859]182      try {
183        parentStack.Push(new Midwife(type, (ICompositeSerializer)serializerMapping[type], token.Id));
[4175]184      } catch (Exception e) {
[1859]185        if (e is InvalidCastException || e is KeyNotFoundException) {
186          throw new PersistenceException(String.Format(
187            "Invalid composite serializer configuration for type \"{0}\".",
188            type.AssemblyQualifiedName), e);
189        } else {
190          throw new PersistenceException(String.Format(
191            "Unexpected exception while trying to compose object of type \"{0}\".",
192            type.AssemblyQualifiedName), e);
193        }
194      }
[1454]195    }
196
[1553]197    private void CompositeEndHandler(EndToken token) {
[1454]198      Type type = typeIds[(int)token.TypeId];
[1553]199      Midwife midwife = parentStack.Pop();
[1574]200      if (midwife.Obj == null)
201        CreateInstance(midwife);
[1553]202      midwife.Populate();
203      SetValue(token.Name, midwife.Obj);
[1454]204    }
205
[1553]206    private void PrimitiveHandler(PrimitiveToken token) {
[1454]207      Type type = typeIds[(int)token.TypeId];
[1859]208      try {
209        object value = ((IPrimitiveSerializer)serializerMapping[type]).Parse(token.SerialData);
210        if (token.Id != null)
211          id2obj[(int)token.Id] = value;
212        SetValue(token.Name, value);
[4175]213      } catch (Exception e) {
[1859]214        if (e is InvalidCastException || e is KeyNotFoundException) {
215          throw new PersistenceException(String.Format(
216            "Invalid primitive serializer configuration for type \"{0}\".",
217            type.AssemblyQualifiedName), e);
218        } else {
219          throw new PersistenceException(String.Format(
220            "Unexpected exception while trying to parse object of type \"{0}\".",
221            type.AssemblyQualifiedName), e);
222        }
223      }
[1454]224    }
225
[1553]226    private void ReferenceHandler(ReferenceToken token) {
[1454]227      object referredObject = id2obj[token.Id];
[1553]228      SetValue(token.Name, referredObject);
[1454]229    }
230
[1553]231    private void NullHandler(NullReferenceToken token) {
[1454]232      SetValue(token.Name, null);
[1553]233    }
[1454]234
[1553]235    private void MetaInfoBegin(MetaInfoBeginToken token) {
236      parentStack.Peek().MetaMode = true;
237    }
238
239    private void MetaInfoEnd(MetaInfoEndToken token) {
[1566]240      Midwife m = parentStack.Peek();
[1553]241      m.MetaMode = false;
242      CreateInstance(m);
243    }
244
245    private void CreateInstance(Midwife m) {
246      m.CreateInstance();
247      if (m.Id != null)
[1566]248        id2obj.Add((int)m.Id, m.Obj);
[1553]249    }
250
[1454]251    private void SetValue(string name, object value) {
[1566]252      if (parentStack.Count == 0) {
[1553]253        parentStack.Push(new Midwife(value));
254      } else {
255        Midwife m = parentStack.Peek();
[2873]256        if (m.MetaMode == false && m.Obj == null) {
[1553]257          CreateInstance(m);
[2873]258        }
[1566]259        m.AddValue(name, value);
[1454]260      }
261    }
262  }
263}
Note: See TracBrowser for help on using the repository browser.