Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Persistence/3.3/Core/Serializer.cs @ 2106

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

Collect all exceptions during serialization and continue as far as possible. Throw a collected exception in th end. (#678)

File size: 7.3 KB
Line 
1using System.Collections.Generic;
2using System.Collections;
3using System;
4using System.Linq;
5using HeuristicLab.Persistence.Auxiliary;
6using HeuristicLab.Persistence.Interfaces;
7using HeuristicLab.Persistence.Core.Tokens;
8using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
9using System.Text;
10using System.Reflection;
11using System.IO;
12
13namespace HeuristicLab.Persistence.Core {
14
15  public class Serializer : IEnumerable<ISerializationToken> {
16
17    class ReferenceEqualityComparer : IEqualityComparer<object> {
18
19      public new bool Equals(object a, object b) {
20        return Object.ReferenceEquals(a, b);
21      }
22
23      public int GetHashCode(object obj) {
24        if (obj == null)
25          return 0;
26        return obj.GetHashCode();
27      }
28
29    }
30
31    private readonly object obj;
32    private readonly string rootName;
33    private readonly Dictionary<object, int> obj2id;
34    private readonly Dictionary<Type, int> typeCache;
35    private readonly Configuration configuration;
36    private readonly bool isTestRun;
37    private readonly List<Exception> exceptions;
38
39    public List<TypeMapping> TypeCache {
40      get {
41        BuildTypeCache();
42        return externalTypeCache;
43      }
44    }
45
46    public List<string> RequiredFiles {
47      get {
48        BuildTypeCache();
49        return requiredFiles;
50      }
51    }
52
53    private List<TypeMapping> externalTypeCache;
54    private List<string> requiredFiles;
55    private void BuildTypeCache() {     
56      externalTypeCache = new List<TypeMapping>();
57      Dictionary<Assembly, bool> assemblies = new Dictionary<Assembly, bool>();
58      foreach (var pair in typeCache) {
59        string serializer = null;
60        IPrimitiveSerializer f = configuration.GetPrimitiveSerializer(pair.Key);
61        if (f != null) {
62          serializer = f.GetType().AssemblyQualifiedName;
63          assemblies[f.GetType().Assembly] = true;
64        } else {
65          ICompositeSerializer d = configuration.GetCompositeSerializer(pair.Key);
66          serializer = d.GetType().AssemblyQualifiedName;
67          assemblies[d.GetType().Assembly] = true;
68        }
69        externalTypeCache.Add(new TypeMapping(pair.Value, pair.Key.AssemblyQualifiedName, serializer));
70        assemblies[pair.Key.Assembly] = true;
71      }
72      Dictionary<string, bool> files = new Dictionary<string, bool>();
73      foreach (Assembly a in assemblies.Keys) {
74        files[a.CodeBase] = true;
75      }
76      requiredFiles = new List<string>(files.Keys);
77    }
78
79    public Serializer(object obj, Configuration configuration) :
80      this(obj, configuration, "ROOT") { }
81
82    public Serializer(object obj, Configuration configuration, string rootName)
83      : this(obj, configuration, rootName, false) { }
84
85    public Serializer(object obj, Configuration configuration, string rootName, bool isTestRun) {
86   
87      this.obj = obj;
88      this.rootName = rootName;
89      this.configuration = configuration;
90      obj2id = new Dictionary<object, int>(new ReferenceEqualityComparer()) { { new object(), 0 } };
91      typeCache = new Dictionary<Type, int>();
92      this.isTestRun = isTestRun;
93      this.exceptions = new List<Exception>();
94    }
95
96    IEnumerator IEnumerable.GetEnumerator() {
97      return GetEnumerator();
98    }
99
100    public IEnumerator<ISerializationToken> GetEnumerator() {
101      var enumerator = Serialize(new DataMemberAccessor(rootName, null, () => obj, null));
102      if (isTestRun) {
103        return AddExceptionCompiler(enumerator);
104      } else {
105        return enumerator;
106      }
107    }
108
109    public IEnumerator<ISerializationToken> AddExceptionCompiler(IEnumerator<ISerializationToken> enumerator) {
110      while (enumerator.MoveNext())
111        yield return enumerator.Current;
112      if (exceptions.Count == 1)
113        throw exceptions[0];
114      if (exceptions.Count > 1)
115        throw new PersistenceException("Multiple exceptions during serialization", exceptions);
116    }
117
118    private IEnumerator<ISerializationToken> Serialize(DataMemberAccessor accessor) {
119      object value = accessor.Get();
120      if (value == null)
121        return NullReferenceEnumerator(accessor.Name);
122      Type type = value.GetType();
123      if (obj2id.ContainsKey(value))
124        return ReferenceEnumerator(accessor.Name, obj2id[value]);
125      if (!typeCache.ContainsKey(type))
126        typeCache.Add(type, typeCache.Count);
127      int typeId = typeCache[type];
128      int? id = null;
129      if (!type.IsValueType) {
130        id = obj2id.Count;
131        obj2id.Add(value, (int)id);
132      }
133      try {
134        IPrimitiveSerializer primitiveSerializer = configuration.GetPrimitiveSerializer(type);
135        if (primitiveSerializer != null)
136          return PrimitiveEnumerator(accessor.Name, typeId, primitiveSerializer.Format(value), id);
137        ICompositeSerializer compositeSerializer = configuration.GetCompositeSerializer(type);
138        if (compositeSerializer != null)
139          return CompositeEnumerator(accessor.Name, compositeSerializer.Decompose(value), id, typeId, compositeSerializer.CreateMetaInfo(value));
140        throw new PersistenceException(
141            String.Format(
142            "No suitable method for serializing values of type \"{0}\" found\r\n" +
143            "primitive serializers:\r\n{1}\r\n" +
144            "composite serializers:\r\n{2}",
145            value.GetType().VersionInvariantName(),
146            string.Join("\r\n", configuration.PrimitiveSerializers.Select(f => f.GetType().VersionInvariantName()).ToArray()),
147            string.Join("\r\n", configuration.CompositeSerializers.Select(d => d.GetType().VersionInvariantName()).ToArray())
148            ));
149      } catch (Exception x) {
150        if (isTestRun) {
151          exceptions.Add(x);
152          return new List<ISerializationToken>().GetEnumerator();
153        } else {
154          throw x;
155        }
156      }
157    }
158
159    private IEnumerator<ISerializationToken> NullReferenceEnumerator(string name) {
160      yield return new NullReferenceToken(name);
161    }
162
163    private IEnumerator<ISerializationToken> ReferenceEnumerator(string name, int id) {
164      yield return new ReferenceToken(name, id);
165    }
166
167    private IEnumerator<ISerializationToken> PrimitiveEnumerator(string name,
168        int typeId, ISerialData serializedValue, int? id) {
169      yield return new PrimitiveToken(name, typeId, id, serializedValue);
170    }
171
172    private IEnumerator<ISerializationToken> CompositeEnumerator(
173        string name, IEnumerable<Tag> tags, int? id, int typeId, IEnumerable<Tag> metaInfo) {
174      yield return new BeginToken(name, typeId, id);
175      bool first = true;
176      foreach (var tag in metaInfo) {
177        IEnumerator<ISerializationToken> metaIt = Serialize(new DataMemberAccessor(tag.Value, tag.Name));
178        while (metaIt.MoveNext()) {
179          if (first) {
180            yield return new MetaInfoBeginToken();
181            first = false;
182          }
183          yield return metaIt.Current;
184        }
185      }
186      if (!first) {
187        yield return new MetaInfoEndToken();
188      }
189      foreach (var tag in tags) {
190        IEnumerator<ISerializationToken> it = Serialize(new DataMemberAccessor(tag.Value, tag.Name));
191        while (it.MoveNext())
192          yield return it.Current;
193      }
194      yield return new EndToken(name, typeId, id);
195    }
196
197  }
198
199
200}
Note: See TracBrowser for help on using the repository browser.