Free cookie consent management tool by TermsFeed Policy Generator

source: branches/Persistence Test/HeuristicLab.Persistence/3.3/Core/Serializer.cs @ 3962

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

allow empty MetaInfo or Tag list for composite serializers (#802)

File size: 7.4 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      this.obj = obj;
87      this.rootName = rootName;
88      this.configuration = configuration;
89      obj2id = new Dictionary<object, int>(new ReferenceEqualityComparer()) { { new object(), 0 } };
90      typeCache = new Dictionary<Type, int>();
91      this.isTestRun = isTestRun;
92      this.exceptions = new List<Exception>();
93    }
94
95    IEnumerator IEnumerable.GetEnumerator() {
96      return GetEnumerator();
97    }
98
99    public IEnumerator<ISerializationToken> GetEnumerator() {
100      var enumerator = Serialize(new DataMemberAccessor(rootName, null, () => obj, null));
101      if (isTestRun) {
102        return AddExceptionCompiler(enumerator);
103      } else {
104        return enumerator;
105      }
106    }
107
108    public IEnumerator<ISerializationToken> AddExceptionCompiler(IEnumerator<ISerializationToken> enumerator) {
109      while (enumerator.MoveNext())
110        yield return enumerator.Current;
111      if (exceptions.Count == 1)
112        throw exceptions[0];
113      if (exceptions.Count > 1)
114        throw new PersistenceException("Multiple exceptions during serialization", exceptions);
115    }
116
117    private IEnumerator<ISerializationToken> Serialize(DataMemberAccessor accessor) {
118      object value = accessor.Get();
119      if (value == null)
120        return NullReferenceEnumerator(accessor.Name);
121      Type type = value.GetType();
122      if (obj2id.ContainsKey(value))
123        return ReferenceEnumerator(accessor.Name, obj2id[value]);
124      if (!typeCache.ContainsKey(type))
125        typeCache.Add(type, typeCache.Count);
126      int typeId = typeCache[type];
127      int? id = null;
128      if (!type.IsValueType) {
129        id = obj2id.Count;
130        obj2id.Add(value, (int)id);
131      }
132      try {
133        IPrimitiveSerializer primitiveSerializer = configuration.GetPrimitiveSerializer(type);
134        if (primitiveSerializer != null)
135          return PrimitiveEnumerator(accessor.Name, typeId, primitiveSerializer.Format(value), id);
136        ICompositeSerializer compositeSerializer = configuration.GetCompositeSerializer(type);
137        if (compositeSerializer != null)
138          return CompositeEnumerator(accessor.Name, compositeSerializer.Decompose(value), id, typeId, compositeSerializer.CreateMetaInfo(value));
139        throw new PersistenceException(
140            String.Format(
141            "No suitable method for serializing values of type \"{0}\" found\r\n" +
142            "primitive serializers:\r\n{1}\r\n" +
143            "composite serializers:\r\n{2}",
144            value.GetType().VersionInvariantName(),
145            string.Join("\r\n", configuration.PrimitiveSerializers.Select(f => f.GetType().VersionInvariantName()).ToArray()),
146            string.Join("\r\n", configuration.CompositeSerializers.Select(d => d.GetType().VersionInvariantName()).ToArray())
147            ));
148      } catch (Exception x) {
149        if (isTestRun) {
150          exceptions.Add(x);
151          return new List<ISerializationToken>().GetEnumerator();
152        } else {
153          throw x;
154        }
155      }
156    }
157
158    private IEnumerator<ISerializationToken> NullReferenceEnumerator(string name) {
159      yield return new NullReferenceToken(name);
160    }
161
162    private IEnumerator<ISerializationToken> ReferenceEnumerator(string name, int id) {
163      yield return new ReferenceToken(name, id);
164    }
165
166    private IEnumerator<ISerializationToken> PrimitiveEnumerator(string name,
167        int typeId, ISerialData serializedValue, int? id) {
168      yield return new PrimitiveToken(name, typeId, id, serializedValue);
169    }
170
171    private IEnumerator<ISerializationToken> CompositeEnumerator(
172        string name, IEnumerable<Tag> tags, int? id, int typeId, IEnumerable<Tag> metaInfo) {
173      yield return new BeginToken(name, typeId, id);
174      bool first = true;
175      if (metaInfo != null) {
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      }
187      if (!first) {
188        yield return new MetaInfoEndToken();
189      }
190      if (tags != null) {
191        foreach (var tag in tags) {
192          IEnumerator<ISerializationToken> it = Serialize(new DataMemberAccessor(tag.Value, tag.Name));
193          while (it.MoveNext())
194            yield return it.Current;
195        }
196      }
197      yield return new EndToken(name, typeId, id);
198    }
199
200  }
201
202
203}
Note: See TracBrowser for help on using the repository browser.