Changeset 15034


Ignore:
Timestamp:
06/16/17 11:32:56 (10 days ago)
Author:
gkronber
Message:

#2520: improved conversions

Location:
branches/PersistenceReintegration
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • branches/PersistenceReintegration/HeuristicLab.Persistence/4.0/Core/StorableConversionAttribute.cs

    r14927 r15034  
    2626  [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
    2727  public sealed class StorableConversionAttribute : Attribute {
    28     public uint SrcVersion { get; set; }
     28    public Guid Guid { get; private set; }
     29    public uint SrcVersion { get; private set; }
    2930
    30     public StorableConversionAttribute(uint srcVersion) {
     31    public StorableConversionAttribute(string guid, uint srcVersion) {
     32      this.Guid = new Guid(guid);
    3133      this.SrcVersion = srcVersion;
    3234    }
     
    3537      return Attribute.IsDefined(mi, typeof(StorableConversionAttribute), false);
    3638    }
    37     public static StorableConversionAttribute GetTransformerAttribute(MethodInfo mi) {
     39
     40    public static StorableConversionAttribute GetStorableConversionAttribute(MethodInfo mi) {
    3841      return (StorableConversionAttribute)Attribute.GetCustomAttribute(mi, typeof(StorableConversionAttribute), false);
    3942    }
     43    public static Guid GetGuid(MethodInfo mi) {
     44      return GetStorableConversionAttribute(mi).Guid;
     45    }
    4046    public static uint GetVersion(MethodInfo mi) {
    41       return GetTransformerAttribute(mi).SrcVersion;
     47      return GetStorableConversionAttribute(mi).SrcVersion;
    4248    }
    4349  }
  • branches/PersistenceReintegration/HeuristicLab.Persistence/4.0/Core/StorableTypeAttribute.cs

    r14925 r15034  
    3737
    3838    public Guid Guid { get; private set; }
    39     public uint Version { get; set; }
     39    public uint Version { get; private set; }
    4040
    4141    /// <summary>
  • branches/PersistenceReintegration/HeuristicLab.Persistence/4.0/Core/TypeInfo.cs

    r15020 r15034  
    5959      if (StorableTypeAttribute != null) {
    6060        // check constructors (
    61         if (!type.IsValueType && !type.IsEnum && !type.IsInterface && 
     61        if (!type.IsValueType && !type.IsEnum && !type.IsInterface &&
    6262          GetStorableConstructor() == null && GetDefaultConstructor() == null)
    6363          throw new PersistenceException("No storable constructor or parameterless constructor found.");
    6464
    65           // traverse type hierarchy from base type to sub types
    66           Stack<Type> types = new Stack<Type>();
     65        // traverse type hierarchy from base type to sub types
     66        Stack<Type> types = new Stack<Type>();
    6767        while (type != null) {
    6868          types.Push(type);
     
    9595            foreach (var property in propertyInfos) {
    9696              var attrib = StorableAttribute.GetStorableAttribute(property);
    97               if (!attrib.AllowOneWay && (!property.CanRead || !property.CanWrite))
     97              if ((!property.CanRead || !property.CanWrite) && (attrib == null || !attrib.AllowOneWay))
    9898                throw new PersistenceException("Properties must be readable and writable or explicity enable one way serialization.");
    9999
  • branches/PersistenceReintegration/HeuristicLab.Persistence/4.0/Transformers/StorableClassTransformer.cs

    r14927 r15034  
    7272      var typeBox = mapper.GetBox(box.TypeId).GetExtension(TypeBox.Type);
    7373      var version = typeBox.HasVersion ? typeBox.Version : 1;
     74      var typeGuid = typeInfo.StorableTypeAttribute.Guid;
    7475
    7576      var components = new Dictionary<uint, uint>();
     
    7980
    8081      var conversionMethods =
    81         type.GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
     82        type.Assembly.GetTypes().SelectMany(t =>
     83          t.GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
    8284          .Where(StorableConversionAttribute.IsStorableConversionMethod)
    83           .Where(mi => StorableConversionAttribute.GetVersion(mi) >= version)
    84           .OrderBy(StorableConversionAttribute.GetVersion);
     85          .Where(mi => StorableConversionAttribute.GetGuid(mi) == typeGuid &&
     86                       StorableConversionAttribute.GetVersion(mi) >= version))
     87          .OrderBy(StorableConversionAttribute.GetVersion)
     88          .ToArray();
    8589
    86       // put all objects into dictionary for optional conversion
     90      // put all objects into dictionary for conversion
    8791      var dict = new Dictionary<string, object>();
    8892      foreach (var component in components) {
     
    9094      }
    9195
    92       // TODO: check that all entries in the dictionary can be mapped to a field or property
    9396      foreach (var convMeth in conversionMethods) {
     97        if (StorableConversionAttribute.GetVersion(convMeth) != version)
     98          throw new PersistenceException(string.Format("No conversion method defined for type {0} version {1}", typeGuid, version));
    9499        dict = (Dictionary<string, object>)convMeth.Invoke(null, new object[] { dict });
     100        version++;
     101      }
     102      if (version != typeInfo.StorableTypeAttribute.Version)
     103        throw new PersistenceException(string.Format("Missing one or more conversion methods for type {0} version {1}",
     104          typeGuid, typeInfo.StorableTypeAttribute.Version));
     105
     106      // set default values for all fields and properties
     107      foreach (var componentInfo in typeInfo.Fields) {
     108        var field = (FieldInfo)componentInfo.MemberInfo;
     109        if (componentInfo.StorableAttribute != null && componentInfo.StorableAttribute.DefaultValue != null)
     110          field.SetValue(obj, componentInfo.StorableAttribute.DefaultValue);
     111      }
     112      foreach (var componentInfo in typeInfo.Properties.Where(x => x.Writeable)) {
     113        var property = (PropertyInfo)componentInfo.MemberInfo;
     114        if (componentInfo.StorableAttribute != null && componentInfo.StorableAttribute.DefaultValue != null)
     115          property.SetValue(obj, componentInfo.StorableAttribute.DefaultValue, null);
    95116      }
    96117
    97       foreach (var componentInfo in typeInfo.Fields) {
    98         var field = (FieldInfo)componentInfo.MemberInfo;
    99         object val = null;
    100         bool found = dict.TryGetValue(componentInfo.Name, out val);
    101         if (found)
     118      // set all members as generated by conversion method chain
     119      foreach (var kvp in dict.ToArray()) {
     120        var key = kvp.Key;
     121        var val = kvp.Value;
     122        var fieldInfo = typeInfo.Fields.FirstOrDefault(fi => fi.Name == key);
     123        if (fieldInfo != null) {
     124          var field = (FieldInfo)fieldInfo.MemberInfo;
    102125          field.SetValue(obj, val);
    103         else if (componentInfo.StorableAttribute.DefaultValue != null)
    104           field.SetValue(obj, componentInfo.StorableAttribute.DefaultValue);
     126          dict.Remove(fieldInfo.Name);
     127          continue;
     128        }
     129        var propInfo = typeInfo.Properties.Where(x => x.Writeable).FirstOrDefault(pi => pi.Name == key);
     130        if (propInfo != null) {
     131          var prop = (PropertyInfo)propInfo.MemberInfo;
     132          prop.SetValue(obj, val, null);
     133          dict.Remove(propInfo.Name);
     134          continue;
     135        }
    105136      }
    106137
    107       foreach (var componentInfo in typeInfo.Properties.Where(x => x.Writeable)) {
    108         var property = (PropertyInfo)componentInfo.MemberInfo;
    109         object val = null;
    110         bool found = dict.TryGetValue(componentInfo.Name, out val);
    111         if (found)
    112           property.SetValue(obj, val, null);
    113         else if (componentInfo.StorableAttribute.DefaultValue != null)
    114           property.SetValue(obj, componentInfo.StorableAttribute.DefaultValue, null);
    115       }
     138      if (dict.Any())
     139        throw new PersistenceException(string.Format("Invalid conversion method. The following members are undefined in type {0} version {1}: {2}",
     140          typeGuid, typeInfo.StorableTypeAttribute.Version,
     141          string.Join(", ", dict.Keys)));
    116142
    117143      var emptyArgs = new object[0];
  • branches/PersistenceReintegration/HeuristicLab.Persistence/4.0/Transformers/Transformers.cs

    r15022 r15034  
    332332        return ((Type)mapper.GetObject(b.GetGenericTypeIds(0))).MakeArrayType();
    333333      } else {
     334       
    334335        return type;
    335336      }
  • branches/PersistenceReintegration/HeuristicLab.Tests/HeuristicLab.Persistence-3.3/UseCasesPersistenceNew.cs

    r15020 r15034  
    21662166    }
    21672167    [StorableType("00000000-0000-0000-0000-BADCAFFEE000", 2)] // for testing (version 2)
    2168     private partial class V2 : NewBaseType {
     2168    private class V2 : NewBaseType {
    21692169      [Storable]
    21702170      public int a;
     
    21862186    }
    21872187
    2188     // conversion part
    2189     private partial class V2 : NewBaseType {
    2190       [StorableConversion(srcVersion: 1)]
     2188    [StorableType("00000000-0000-0000-0000-BADCAFFEE200", 3)] // for testing (version 3)
     2189    private class V3 : NewBaseType {
     2190      [Storable]
     2191      public int a;
     2192
     2193      [Storable]
     2194      public int[] val;
     2195
     2196      [Storable]
     2197      public V3 mySelf;
     2198
     2199      [Storable]
     2200      public Tuple<int, int> tup;
     2201
     2202      [Storable]
     2203      public Point coords;
     2204    }
     2205
     2206    private static class Conversions {
     2207      [StorableConversion("D211A828-6440-4E72-A8C7-AA4F9B4FFA75", 1)]
    21912208      private static Dictionary<string, object> ConvertV1(Dictionary<string, object> values) {
    21922209        var newValues = new Dictionary<string, object>();
     
    22082225        return newValues;
    22092226      }
    2210     }
    2211 
    2212     [StorableType("00000000-0000-0000-0000-BADCAFFEE200", 3)] // for testing (version 3)
    2213     private partial class V3 : NewBaseType {
    2214       [Storable]
    2215       public int a;
    2216 
    2217       [Storable]
    2218       public int[] val;
    2219 
    2220       [Storable]
    2221       public V3 mySelf;
    2222 
    2223       [Storable]
    2224       public Tuple<int, int> tup;
    2225 
    2226       [Storable]
    2227       public Point coords;
    2228     }
    2229 
    2230     // conversion part
    2231     private partial class V3 {
    2232       [StorableConversion(srcVersion: 1)]
    2233       private static Dictionary<string, object> ConvertV1(Dictionary<string, object> values) {
    2234         var newValues = new Dictionary<string, object>();
    2235         var items = (ItemCollection<IItem>)values["OldBaseType.items"];
    2236         newValues["NewBaseType.items"] = items.Select(iv => new DoubleValue((double)(((dynamic)iv).Value))).ToArray();
    2237         newValues["V2.a"] = ((IntValue)values["V1.a"]).Value;
    2238         newValues["V2.val"] = ((ItemList<IntValue>)values["V1.vals"]).Select(iv => iv.Value).ToArray();
    2239 
    2240         newValues["V2.mySelf"] = values["V1.mySelf"]; // myself type will be mapped correctly
    2241 
    2242         var tup = (Tuple<int, int>)values["V1.tup"];
    2243         if (tup != null) {
    2244           newValues["V2.TupItem1"] = tup.Item1;
    2245           newValues["V2.TupItem2"] = tup.Item2;
    2246         }
    2247 
    2248         newValues["V2.coords"] = new Point((int)values["V1.x"], (int)values["V1.y"]);
    2249 
    2250         return newValues;
    2251       }
    2252 
    2253       [StorableConversion(srcVersion: 2)]
     2227
     2228      [StorableConversion("D211A828-6440-4E72-A8C7-AA4F9B4FFA75", 2)]
    22542229      private static Dictionary<string, object> ConvertV2(Dictionary<string, object> values) {
    22552230        var newValues = new Dictionary<string, object>();
     
    22862261      Mapper.StaticCache.DeregisterType(StorableTypeAttribute.GetStorableTypeAttribute(typeof(V1)).Guid);
    22872262      Mapper.StaticCache.DeregisterType(StorableTypeAttribute.GetStorableTypeAttribute(typeof(V2)).Guid);
    2288 
    2289       Mapper.StaticCache.RegisterType(StorableTypeAttribute.GetStorableTypeAttribute(typeof(V1)).Guid, typeof(V2));
    2290 
    2291       object o = serializer.Deserialize(tempFile);
    2292       var restored = (V2)o;
     2263      Mapper.StaticCache.DeregisterType(StorableTypeAttribute.GetStorableTypeAttribute(typeof(V3)).Guid);
     2264
     2265      Mapper.StaticCache.RegisterType(StorableTypeAttribute.GetStorableTypeAttribute(typeof(V1)).Guid, typeof(V3));
     2266      var pi = typeof(StorableTypeAttribute).GetProperty("Guid");
     2267      pi.SetValue(
     2268        Mapper.StaticCache.GetTypeInfo(typeof(V3)).StorableTypeAttribute,
     2269        StorableTypeAttribute.GetStorableTypeAttribute(typeof(V1)).Guid,
     2270        null);
     2271
     2272      object o = serializer.Deserialize(tempFile);
     2273      var restored = (V3)o;
    22932274      Assert.AreEqual(restored.a, old.a.Value);
    2294       Assert.IsTrue(restored.val.SequenceEqual(old.vals.Select(iv => iv.Value)));
    2295       Assert.IsTrue(restored.items.Select(item => item.Value).SequenceEqual(old.items.Select(iv => (double)((dynamic)iv).Value)));
    2296       // Assert.AreSame(restored.items[0], restored.items[1]);
    2297       Assert.AreSame(restored, restored.mySelf);
    2298 
    2299       //string msg = Profile(test);
    2300       //Console.WriteLine(msg);
    2301     }
    2302 
    2303     [TestMethod]
    2304     [TestCategory("Persistence4")]
    2305     [TestProperty("Time", "short")]
    2306     public void TestConversion2() {
    2307       var test = new Func<V2>(() => {
    2308         var p = new V2();
    2309         p.a = 1;
    2310         p.mySelf = p;
    2311         p.val = new int[] { 2, 3, 4 };
    2312         p.TupItem1 = 17;
    2313         p.TupItem2 = 4;
    2314         p.items = new DoubleValue[] { new DoubleValue(1.0), new DoubleValue(2.0) };
    2315         return p;
    2316       });
    2317 
    2318       ProtoBufSerializer serializer = new ProtoBufSerializer();
    2319       var old = test();
    2320       serializer.Serialize(old, tempFile);
    2321       Mapper.StaticCache.DeregisterType(StorableTypeAttribute.GetStorableTypeAttribute(typeof(V1)).Guid);
    2322       Mapper.StaticCache.DeregisterType(StorableTypeAttribute.GetStorableTypeAttribute(typeof(V2)).Guid);
    2323       Mapper.StaticCache.DeregisterType(StorableTypeAttribute.GetStorableTypeAttribute(typeof(V3)).Guid);
    2324 
    2325       Mapper.StaticCache.RegisterType(StorableTypeAttribute.GetStorableTypeAttribute(typeof(V2)).Guid, typeof(V3));
    2326 
    2327       object o = serializer.Deserialize(tempFile);
    2328       var restored = (V3)o;
    2329       Assert.AreEqual(restored.a, old.a);
    2330       Assert.IsTrue(restored.val.SequenceEqual(old.val));
     2275      Assert.IsTrue(restored.val.SequenceEqual(old.vals.Select(iv=>iv.Value)));
    23312276      Assert.IsTrue(restored.items.Select(item => item.Value).SequenceEqual(old.items.Select(iv => (double)((dynamic)iv).Value)));
    23322277      // Assert.AreSame(restored.items[0], restored.items[1]);
Note: See TracChangeset for help on using the changeset viewer.