#region License Information
/* HeuristicLab
* Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
namespace HeuristicLab.Persistence {
[Transformer("78556C88-0FEE-4602-95C7-A469B2DDB468", 100)]
internal sealed class StorableClassBoxTransformer : BoxTransformer {
public override bool CanTransformType(Type type) {
return StorableTypeAttribute.IsStorableType(type) && !type.IsValueType && !type.IsEnum || // don't transform structs or enums
type.BaseType != null && CanTransformType(type.BaseType);
}
protected override void Populate(Box.Builder box, object value, Mapper mapper) {
var b = StorableClassBox.CreateBuilder();
var type = value.GetType();
var typeInfo = Mapper.StaticCache.GetTypeInfo(type);
var emptyArgs = new object[0];
foreach (var hook in typeInfo.BeforeSerializationHooks) {
hook.Invoke(value, emptyArgs);
}
var components = new Dictionary();
foreach (var componentInfo in typeInfo.Fields) {
var field = (FieldInfo)componentInfo.MemberInfo;
var component = mapper.GetBoxId(field.GetValue(value));
components.Add(mapper.GetStringId(componentInfo.Name), component);
}
foreach (var componentInfo in typeInfo.Properties.Where(x => x.Readable)) {
var property = (PropertyInfo)componentInfo.MemberInfo;
var component = mapper.GetBoxId(property.GetValue(value, null));
components.Add(mapper.GetStringId(componentInfo.Name), component);
}
b.AddRangeKeyIds(components.Keys);
b.AddRangeValueIds(components.Values);
box.SetExtension(StorableClassBox.StorableClass, b.Build());
}
protected override object Extract(Box box, Type type, Mapper mapper) {
return mapper.CreateInstance(type);
}
public override void FillFromBox(object obj, Box box, Mapper mapper) {
var data = box.GetExtension(StorableClassBox.StorableClass);
var type = obj.GetType();
var typeInfo = Mapper.StaticCache.GetTypeInfo(type);
var typeBox = mapper.GetBox(box.TypeId).GetExtension(TypeBox.Type);
var version = typeBox.HasVersion ? typeBox.Version : 1;
var components = new Dictionary();
for (int i = 0; i < data.KeyIdsList.Count; i++) {
components.Add(data.KeyIdsList[i], data.ValueIdsList[i]);
}
var conversionMethods =
type.GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
.Where(StorableConversionAttribute.IsStorableConversionMethod)
.Where(mi => StorableConversionAttribute.GetVersion(mi) >= version)
.OrderBy(StorableConversionAttribute.GetVersion);
// put all objects into dictionary for optional conversion
var dict = new Dictionary();
foreach (var component in components) {
dict.Add(mapper.GetString(component.Key), mapper.GetObject(component.Value));
}
// TODO: check that all entries in the dictionary can be mapped to a field or property
foreach (var convMeth in conversionMethods) {
dict = (Dictionary)convMeth.Invoke(null, new object[] { dict });
}
foreach (var componentInfo in typeInfo.Fields) {
var field = (FieldInfo)componentInfo.MemberInfo;
object val = null;
bool found = dict.TryGetValue(componentInfo.Name, out val);
if (found)
field.SetValue(obj, val);
else if (componentInfo.StorableAttribute.DefaultValue != null)
field.SetValue(obj, componentInfo.StorableAttribute.DefaultValue);
}
foreach (var componentInfo in typeInfo.Properties.Where(x => x.Writeable)) {
var property = (PropertyInfo)componentInfo.MemberInfo;
object val = null;
bool found = dict.TryGetValue(componentInfo.Name, out val);
if (found)
property.SetValue(obj, val, null);
else if (componentInfo.StorableAttribute.DefaultValue != null)
property.SetValue(obj, componentInfo.StorableAttribute.DefaultValue, null);
}
var emptyArgs = new object[0];
foreach (var hook in typeInfo.AfterDeserializationHooks) {
hook.Invoke(obj, emptyArgs);
}
}
}
}