[1454] | 1 | using System.Collections.Generic;
|
---|
| 2 | using System;
|
---|
| 3 | using HeuristicLab.Persistence.Interfaces;
|
---|
[1556] | 4 | using HeuristicLab.Persistence.Core.Tokens;
|
---|
[1454] | 5 |
|
---|
[1567] | 6 | namespace HeuristicLab.Persistence.Core {
|
---|
[1454] | 7 |
|
---|
[1567] | 8 | public class Deserializer {
|
---|
[1454] | 9 |
|
---|
[1567] | 10 | class Midwife {
|
---|
[1566] | 11 |
|
---|
[1567] | 12 | public int? Id { get; private set; }
|
---|
| 13 | public bool MetaMode { get; set; }
|
---|
| 14 | public object Obj { get; private set; }
|
---|
[1454] | 15 |
|
---|
[1567] | 16 | private List<Tag> metaInfo;
|
---|
| 17 | private List<Tag> customValues;
|
---|
| 18 | private Type type;
|
---|
| 19 | private IDecomposer decomposer;
|
---|
[1553] | 20 |
|
---|
[1567] | 21 | public Midwife(object value) {
|
---|
| 22 | this.Obj = value;
|
---|
| 23 | }
|
---|
[1566] | 24 |
|
---|
[1567] | 25 | public Midwife(Type type, IDecomposer decomposer, int? id) {
|
---|
| 26 | this.type = type;
|
---|
| 27 | this.decomposer = decomposer;
|
---|
| 28 | this.Id = id;
|
---|
| 29 | MetaMode = false;
|
---|
| 30 | metaInfo = new List<Tag>();
|
---|
| 31 | customValues = new List<Tag>();
|
---|
| 32 | }
|
---|
[1454] | 33 |
|
---|
[1567] | 34 | public void CreateInstance() {
|
---|
| 35 | if (Obj != null)
|
---|
| 36 | throw new ApplicationException("object already instantiated");
|
---|
| 37 | Obj = decomposer.CreateInstance(type, metaInfo);
|
---|
| 38 | }
|
---|
[1454] | 39 |
|
---|
[1567] | 40 | public void AddValue(string name, object value) {
|
---|
| 41 | if (MetaMode) {
|
---|
| 42 | metaInfo.Add(new Tag(name, value));
|
---|
| 43 | } else {
|
---|
| 44 | customValues.Add(new Tag(name, value));
|
---|
| 45 | }
|
---|
[1553] | 46 | }
|
---|
[1454] | 47 |
|
---|
[1567] | 48 | public void Populate() {
|
---|
| 49 | decomposer.Populate(Obj, customValues, type);
|
---|
| 50 | }
|
---|
[1553] | 51 | }
|
---|
[1454] | 52 |
|
---|
| 53 | private readonly Dictionary<int, object> id2obj;
|
---|
[1553] | 54 | private readonly Dictionary<Type, object> serializerMapping;
|
---|
[1566] | 55 | private readonly Stack<Midwife> parentStack;
|
---|
[1553] | 56 | private readonly Dictionary<int, Type> typeIds;
|
---|
[1454] | 57 |
|
---|
[1542] | 58 | public Deserializer(
|
---|
[1553] | 59 | IEnumerable<TypeMapping> typeCache) {
|
---|
[1454] | 60 | id2obj = new Dictionary<int, object>();
|
---|
[1553] | 61 | parentStack = new Stack<Midwife>();
|
---|
[1454] | 62 | typeIds = new Dictionary<int, Type>();
|
---|
[1542] | 63 | serializerMapping = CreateSerializers(typeCache);
|
---|
[1454] | 64 | }
|
---|
| 65 |
|
---|
[1542] | 66 | private Dictionary<Type, object> CreateSerializers(IEnumerable<TypeMapping> typeCache) {
|
---|
[1454] | 67 | var map = new Dictionary<Type, object>();
|
---|
| 68 | foreach (var typeMapping in typeCache) {
|
---|
[1494] | 69 | Type type = Type.GetType(typeMapping.TypeName, true);
|
---|
[1454] | 70 | typeIds.Add(typeMapping.Id, type);
|
---|
| 71 | if (typeMapping.Serializer != null) {
|
---|
| 72 | Type serializerType = Type.GetType(typeMapping.Serializer);
|
---|
| 73 | map.Add(type, Activator.CreateInstance(serializerType, true));
|
---|
| 74 | }
|
---|
| 75 | }
|
---|
| 76 | return map;
|
---|
| 77 | }
|
---|
| 78 |
|
---|
[1566] | 79 | public object Deserialize(IEnumerable<ISerializationToken> tokens) {
|
---|
[1454] | 80 | foreach (ISerializationToken token in tokens) {
|
---|
| 81 | Type t = token.GetType();
|
---|
[1566] | 82 | if (t == typeof(BeginToken)) {
|
---|
[1454] | 83 | CompositeStartHandler((BeginToken)token);
|
---|
[1566] | 84 | } else if (t == typeof(EndToken)) {
|
---|
| 85 | CompositeEndHandler((EndToken)token);
|
---|
| 86 | } else if (t == typeof(PrimitiveToken)) {
|
---|
| 87 | PrimitiveHandler((PrimitiveToken)token);
|
---|
| 88 | } else if (t == typeof(ReferenceToken)) {
|
---|
| 89 | ReferenceHandler((ReferenceToken)token);
|
---|
[1454] | 90 | } else if (t == typeof(NullReferenceToken)) {
|
---|
| 91 | NullHandler((NullReferenceToken)token);
|
---|
[1553] | 92 | } else if (t == typeof(MetaInfoBeginToken)) {
|
---|
| 93 | MetaInfoBegin((MetaInfoBeginToken)token);
|
---|
| 94 | } else if (t == typeof(MetaInfoEndToken)) {
|
---|
| 95 | MetaInfoEnd((MetaInfoEndToken)token);
|
---|
[1454] | 96 | } else {
|
---|
| 97 | throw new ApplicationException("invalid token type");
|
---|
| 98 | }
|
---|
| 99 | }
|
---|
| 100 | return parentStack.Pop().Obj;
|
---|
| 101 | }
|
---|
| 102 |
|
---|
[1553] | 103 | private void CompositeStartHandler(BeginToken token) {
|
---|
[1454] | 104 | Type type = typeIds[(int)token.TypeId];
|
---|
| 105 | IDecomposer decomposer = null;
|
---|
[1566] | 106 | if (serializerMapping.ContainsKey(type))
|
---|
[1553] | 107 | decomposer = serializerMapping[type] as IDecomposer;
|
---|
[1454] | 108 | if (decomposer == null)
|
---|
| 109 | throw new ApplicationException(String.Format(
|
---|
| 110 | "No suitable method for deserialization of type \"{0}\" found.",
|
---|
| 111 | type.VersionInvariantName()));
|
---|
[1553] | 112 | parentStack.Push(new Midwife(type, decomposer, token.Id));
|
---|
[1454] | 113 | }
|
---|
| 114 |
|
---|
[1553] | 115 | private void CompositeEndHandler(EndToken token) {
|
---|
[1454] | 116 | Type type = typeIds[(int)token.TypeId];
|
---|
[1553] | 117 | Midwife midwife = parentStack.Pop();
|
---|
| 118 | midwife.Populate();
|
---|
| 119 | SetValue(token.Name, midwife.Obj);
|
---|
[1454] | 120 | }
|
---|
| 121 |
|
---|
[1553] | 122 | private void PrimitiveHandler(PrimitiveToken token) {
|
---|
[1454] | 123 | Type type = typeIds[(int)token.TypeId];
|
---|
[1566] | 124 | object value = ((IFormatter)serializerMapping[type]).Parse(token.SerialData);
|
---|
| 125 | if (token.Id != null)
|
---|
[1454] | 126 | id2obj[(int)token.Id] = value;
|
---|
| 127 | SetValue(token.Name, value);
|
---|
| 128 | }
|
---|
| 129 |
|
---|
[1553] | 130 | private void ReferenceHandler(ReferenceToken token) {
|
---|
[1454] | 131 | object referredObject = id2obj[token.Id];
|
---|
[1553] | 132 | SetValue(token.Name, referredObject);
|
---|
[1454] | 133 | }
|
---|
| 134 |
|
---|
[1553] | 135 | private void NullHandler(NullReferenceToken token) {
|
---|
[1454] | 136 | SetValue(token.Name, null);
|
---|
[1553] | 137 | }
|
---|
[1454] | 138 |
|
---|
[1553] | 139 | private void MetaInfoBegin(MetaInfoBeginToken token) {
|
---|
| 140 | parentStack.Peek().MetaMode = true;
|
---|
| 141 | }
|
---|
| 142 |
|
---|
| 143 | private void MetaInfoEnd(MetaInfoEndToken token) {
|
---|
[1566] | 144 | Midwife m = parentStack.Peek();
|
---|
[1553] | 145 | m.MetaMode = false;
|
---|
| 146 | CreateInstance(m);
|
---|
| 147 | }
|
---|
| 148 |
|
---|
| 149 | private void CreateInstance(Midwife m) {
|
---|
| 150 | m.CreateInstance();
|
---|
| 151 | if (m.Id != null)
|
---|
[1566] | 152 | id2obj.Add((int)m.Id, m.Obj);
|
---|
[1553] | 153 | }
|
---|
| 154 |
|
---|
[1454] | 155 | private void SetValue(string name, object value) {
|
---|
[1566] | 156 | if (parentStack.Count == 0) {
|
---|
[1553] | 157 | parentStack.Push(new Midwife(value));
|
---|
| 158 | } else {
|
---|
| 159 | Midwife m = parentStack.Peek();
|
---|
| 160 | if (m.MetaMode == false && m.Obj == null)
|
---|
| 161 | CreateInstance(m);
|
---|
[1566] | 162 | m.AddValue(name, value);
|
---|
[1454] | 163 | }
|
---|
| 164 | }
|
---|
| 165 | }
|
---|
| 166 | } |
---|