You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by pt...@apache.org on 2017/10/17 11:45:59 UTC
ignite git commit: IGNITE-6627 .NET: Fix serialization of enums
within generic collections
Repository: ignite
Updated Branches:
refs/heads/master ec12824a5 -> 93bf555a9
IGNITE-6627 .NET: Fix serialization of enums within generic collections
* Fix EnumEqualityComparer serialization
* Fix enum arrays serialization
* Fix empty objects missing metadata
This closes #2864
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/93bf555a
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/93bf555a
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/93bf555a
Branch: refs/heads/master
Commit: 93bf555a98c472ff7028a641b32ef5d8ba8df7cd
Parents: ec12824
Author: Alexey Popov <ta...@gmail.com>
Authored: Tue Oct 17 14:45:42 2017 +0300
Committer: Pavel Tupitsyn <pt...@apache.org>
Committed: Tue Oct 17 14:45:42 2017 +0300
----------------------------------------------------------------------
.../Apache.Ignite.Core.Tests.csproj | 2 +
.../Serializable/GenericCollectionsTest.cs | 112 +++++++++++++++++++
.../Client/Cache/CacheTest.cs | 76 +++++++++++++
.../Client/Cache/EmptyObject.cs | 54 +++++++++
.../Impl/Binary/BinarySystemHandlers.cs | 16 +--
.../Impl/Binary/BinaryWriter.cs | 7 ++
.../Impl/Binary/SerializableSerializer.cs | 11 +-
.../Binary/Structure/BinaryStructureTracker.cs | 12 +-
8 files changed, 274 insertions(+), 16 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/93bf555a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
index ec85ca2..7ec75af 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
@@ -78,6 +78,7 @@
<Compile Include="Binary\BinaryReaderWriterTest.cs" />
<Compile Include="Binary\BinarySelfTestSimpleName.cs" />
<Compile Include="Binary\EnumsTestOnline.cs" />
+ <Compile Include="Binary\Serializable\GenericCollectionsTest.cs" />
<Compile Include="Cache\PersistentStoreTest.cs" />
<Compile Include="Cache\Query\Linq\CacheLinqTest.CompiledQuery.cs" />
<Compile Include="Cache\Query\Linq\CacheLinqTest.DateTime.cs" />
@@ -94,6 +95,7 @@
<Compile Include="Cache\Store\CacheStoreSessionTestSharedFactory.cs" />
<Compile Include="Client\Cache\CacheTest.cs" />
<Compile Include="Client\Cache\CacheTestNoMeta.cs" />
+ <Compile Include="Client\Cache\EmptyObject.cs" />
<Compile Include="Client\Cache\ScanQueryTest.cs" />
<Compile Include="Client\Cache\Person.cs" />
<Compile Include="Client\ClientTestBase.cs" />
http://git-wip-us.apache.org/repos/asf/ignite/blob/93bf555a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/GenericCollectionsTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/GenericCollectionsTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/GenericCollectionsTest.cs
new file mode 100644
index 0000000..cfbe824d
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/Serializable/GenericCollectionsTest.cs
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Tests.Binary.Serializable
+{
+ using System.Collections.Generic;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Tests Generic collections serializtion/deserialization scenarios.
+ /// </summary>
+ public class GenericCollectionsTest
+ {
+ /// <summary>
+ /// Tests Dictionary.
+ /// </summary>
+ [Test]
+ public void TestDictionary()
+ {
+ TestCollection(new Dictionary<int, int> {{1, 1}, {2, 2}});
+ TestCollection(new Dictionary<ByteEnum, int> {{ByteEnum.One, 1}, {ByteEnum.Two, 2}});
+ TestCollection(new Dictionary<IntEnum, int> {{IntEnum.One, 1}, {IntEnum.Two, 2}});
+ }
+
+ /// <summary>
+ /// Tests SortedDictionary.
+ /// </summary>
+ [Test]
+ public void TestSortedDictionary()
+ {
+ TestCollection(new SortedDictionary<int, int> {{1, 1}, {2, 2}});
+ TestCollection(new SortedDictionary<ByteEnum, int> {{ByteEnum.One, 1}, {ByteEnum.Two, 2}});
+ TestCollection(new SortedDictionary<IntEnum, int> {{IntEnum.One, 1}, {IntEnum.Two, 2}});
+ }
+
+ /// <summary>
+ /// Tests List.
+ /// </summary>
+ [Test]
+ public void TestList()
+ {
+ TestCollection(new List<int> {1, 2});
+ TestCollection(new List<ByteEnum> {ByteEnum.One, ByteEnum.Two});
+ TestCollection(new List<IntEnum> {IntEnum.One, IntEnum.Two});
+ }
+
+ /// <summary>
+ /// Tests LinkedList.
+ /// </summary>
+ [Test]
+ public void TestLinkedList()
+ {
+ TestCollection(new LinkedList<int>(new List<int> { 1, 2 }));
+ TestCollection(new LinkedList<ByteEnum>(new List<ByteEnum> {ByteEnum.One, ByteEnum.Two}));
+ TestCollection(new LinkedList<IntEnum>(new List<IntEnum> {IntEnum.One, IntEnum.Two}));
+ }
+
+ /// <summary>
+ /// Tests HashSet.
+ /// </summary>
+ [Test]
+ public void TestHashSet()
+ {
+ TestCollection(new HashSet<int> {1, 2});
+ TestCollection(new HashSet<ByteEnum> {ByteEnum.One, ByteEnum.Two});
+ TestCollection(new HashSet<IntEnum> {IntEnum.One, IntEnum.Two});
+ }
+
+ /// <summary>
+ /// Tests SortedSet.
+ /// </summary>
+ [Test]
+ public void TestSortedSet()
+ {
+ TestCollection(new SortedSet<int> {1, 2});
+ TestCollection(new SortedSet<ByteEnum> {ByteEnum.One, ByteEnum.Two});
+ TestCollection(new SortedSet<IntEnum> {IntEnum.One, IntEnum.Two});
+ }
+
+ private static void TestCollection<T>(ICollection<T> collection)
+ {
+ var res = TestUtils.SerializeDeserialize(collection);
+ Assert.AreEqual(collection, res);
+ }
+
+ private enum ByteEnum : byte
+ {
+ One = 1,
+ Two = 2,
+ }
+
+ private enum IntEnum
+ {
+ One = 1,
+ Two = 2,
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/93bf555a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CacheTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CacheTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CacheTest.cs
index 083038a..f2dd1de 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CacheTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CacheTest.cs
@@ -68,6 +68,22 @@ namespace Apache.Ignite.Core.Tests.Client.Cache
}
/// <summary>
+ /// Tests the cache put / get for Empty object type.
+ /// </summary>
+ [Test]
+ public void TestPutGetEmptyObject()
+ {
+ using (var client = GetClient())
+ {
+ var serverCache = GetCache<EmptyObject>();
+ var clientCache = client.GetCache<int, EmptyObject>(CacheName);
+
+ serverCache.Put(1, new EmptyObject());
+ Assert.IsNotNull(clientCache.Get(1));
+ }
+ }
+
+ /// <summary>
/// Tests the cache put / get with user data types.
/// </summary>
[Test]
@@ -116,6 +132,60 @@ namespace Apache.Ignite.Core.Tests.Client.Cache
}
/// <summary>
+ /// Tests the cache put / get for Dictionary with Enum keys.
+ /// </summary>
+ [Test]
+ public void TestPutGetDictionary([Values(true, false)] bool compactFooter)
+ {
+ var cfg = GetClientConfiguration();
+
+ cfg.BinaryConfiguration = new BinaryConfiguration
+ {
+ CompactFooter = compactFooter
+ };
+
+ using (var client = Ignition.StartClient(cfg))
+ {
+ var dict = new Dictionary<ByteEnum, int> { { ByteEnum.One, 1 }, { ByteEnum.Two, 2 } };
+
+ var serverCache = GetCache<Dictionary<ByteEnum, int>>();
+ var clientCache = client.GetCache<int, Dictionary<ByteEnum, int>>(CacheName);
+
+ serverCache.Put(1, dict);
+ var res = clientCache.Get(1);
+
+ Assert.AreEqual(dict, res);
+ }
+ }
+
+ /// <summary>
+ /// Tests the cache put / get for HashSet with Enum keys.
+ /// </summary>
+ [Test]
+ public void TestPutGetHashSet([Values(true, false)] bool compactFooter)
+ {
+ var cfg = GetClientConfiguration();
+
+ cfg.BinaryConfiguration = new BinaryConfiguration
+ {
+ CompactFooter = compactFooter
+ };
+
+ using (var client = Ignition.StartClient(cfg))
+ {
+ var hashSet = new HashSet<ByteEnum> { ByteEnum.One, ByteEnum.Two };
+
+ var serverCache = GetCache<HashSet<ByteEnum>>();
+ var clientCache = client.GetCache<int, HashSet<ByteEnum>>(CacheName);
+
+ serverCache.Put(1, hashSet);
+ var res = clientCache.Get(1);
+
+ Assert.AreEqual(hashSet, res);
+ }
+ }
+
+ /// <summary>
/// Tests the TryGet method.
/// </summary>
[Test]
@@ -779,5 +849,11 @@ namespace Apache.Ignite.Core.Tests.Client.Cache
{
public Container Inner;
}
+
+ public enum ByteEnum : byte
+ {
+ One = 1,
+ Two = 2,
+ }
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/93bf555a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/EmptyObject.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/EmptyObject.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/EmptyObject.cs
new file mode 100644
index 0000000..47db939
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/EmptyObject.cs
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Tests.Client.Cache
+{
+ using System;
+ using System.Runtime.Serialization;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Object with no fields.
+ /// </summary>
+ [Serializable]
+ public class EmptyObject : ISerializable
+ {
+ /// <summary>
+ /// Initializes a new instance of the EmptyObject class.
+ /// </summary>
+ public EmptyObject()
+ {
+ // No-op.
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the EmptyObject class.
+ /// </summary>
+ private EmptyObject(SerializationInfo info, StreamingContext context)
+ {
+ Assert.AreEqual(StreamingContextStates.All, context.State);
+ Assert.IsNull(context.Context);
+ }
+
+ /** <inheritdoc /> */
+ public void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ Assert.AreEqual(StreamingContextStates.All, context.State);
+ Assert.IsNull(context.Context);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/93bf555a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
index f55a11f..3f16bc0 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
@@ -110,9 +110,9 @@ namespace Apache.Ignite.Core.Impl.Binary
// 13. Arbitrary dictionary.
ReadHandlers[BinaryTypeId.Dictionary] = new BinarySystemReader(ReadDictionary);
-
- // 14. Enum.
- ReadHandlers[BinaryTypeId.ArrayEnum] = new BinarySystemReader(ReadEnumArray);
+
+ // 14. Enum. Should be read as Array, see WriteEnumArray implementation.
+ ReadHandlers[BinaryTypeId.ArrayEnum] = new BinarySystemReader(ReadArray);
}
/// <summary>
@@ -473,16 +473,6 @@ namespace Apache.Ignite.Core.Impl.Binary
ctx.WriteInt(binEnum.EnumValue);
}
- /**
- * <summary>Read enum array.</summary>
- */
- private static object ReadEnumArray(BinaryReader ctx, Type type)
- {
- var elemType = type.GetElementType() ?? typeof(object);
-
- return BinaryUtils.ReadTypedArray(ctx, true, elemType);
- }
-
/// <summary>
/// Reads the array.
/// </summary>
http://git-wip-us.apache.org/repos/asf/ignite/blob/93bf555a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
index f59f17c..b98ad5f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
@@ -1493,6 +1493,13 @@ namespace Apache.Ignite.Core.Impl.Binary
{
Debug.Assert(desc != null);
+ if (!desc.UserType && (fields == null || fields.Count == 0))
+ {
+ // System types with no fields (most of them) do not need to be sent.
+ // AffinityKey is an example of system type with metadata.
+ return;
+ }
+
if (_metas == null)
{
_metas = new Dictionary<int, BinaryType>(1)
http://git-wip-us.apache.org/repos/asf/ignite/blob/93bf555a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableSerializer.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableSerializer.cs
index e660cff..80f267a 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableSerializer.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/SerializableSerializer.cs
@@ -304,9 +304,16 @@ namespace Apache.Ignite.Core.Impl.Binary
{
return new TypeResolver().ResolveType(serInfo.FullTypeName, serInfo.AssemblyName);
}
-
- if (serInfo.ObjectType != serializable.GetType())
+
+ if (serInfo.ObjectType != serializable.GetType() &&
+ typeof(ISerializable).IsAssignableFrom(serInfo.ObjectType))
{
+ // serInfo.ObjectType should be ISerializable. There is a known case for generic collections:
+ // serializable is EnumEqualityComparer : ISerializable
+ // and serInfo.ObjectType is ObjectEqualityComparer (does not implement ISerializable interface).
+ // Please read a possible explanation here:
+ // http://dotnetstudio.blogspot.ru/2012/06/net-35-to-net-40-enum.html
+
return serInfo.ObjectType;
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/93bf555a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Structure/BinaryStructureTracker.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Structure/BinaryStructureTracker.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Structure/BinaryStructureTracker.cs
index 8f44e00..3517342 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Structure/BinaryStructureTracker.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Structure/BinaryStructureTracker.cs
@@ -110,11 +110,21 @@ namespace Apache.Ignite.Core.Impl.Binary.Structure
var fields = metaHnd.OnObjectWriteFinished();
- // A new schema may be added, but no new fields.
+ // A new schema may be added, but no new fields.
// In this case, we should still call SaveMetadata even if fields are null
writer.SaveMetadata(_desc, fields);
}
}
+ else
+ {
+ // Special case when the object is with no properties.
+ // Save meta to Marshaller.
+ writer.Marshaller.GetBinaryTypeHandler(_desc);
+
+ // Save meta to cluster.
+ writer.SaveMetadata(_desc, null);
+ return;
+ }
}
/// <summary>