IGNITE-5172 .NET: Fix type name parser and resolver to handle arrays and simple names
This closes #1909 Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/ba21c46c Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/ba21c46c Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/ba21c46c Branch: refs/heads/ignite-5009 Commit: ba21c46cc15661d550e9018349ad266517446131 Parents: dddc6d4 Author: Pavel Tupitsyn <[email protected]> Authored: Fri May 5 18:38:29 2017 +0300 Committer: Pavel Tupitsyn <[email protected]> Committed: Fri May 5 18:38:29 2017 +0300 ---------------------------------------------------------------------- .../Apache.Ignite.Core.Tests.csproj | 1 + .../Binary/BinaryDynamicRegistrationTest.cs | 40 +++++++ .../Binary/BinaryNameMapperTest.cs | 7 ++ .../Binary/TypeNameParserTest.cs | 93 ++++++++++++--- .../Binary/TypeResolverTest.cs | 104 +++++++++++++++++ .../Cache/Query/CacheQueriesTest.cs | 5 +- .../Apache.Ignite.Core.Tests/DeploymentTest.cs | 1 + .../Examples/ExamplesTest.cs | 5 +- .../Binary/BinaryBasicNameMapper.cs | 6 +- .../Impl/Binary/BinaryProcessor.cs | 15 +-- .../Impl/Binary/BinaryReader.cs | 6 +- .../Impl/Binary/Marshaller.cs | 18 ++- .../Impl/Binary/TypeNameParser.cs | 31 ++++- .../Impl/Binary/TypeResolver.cs | 115 +++++++++++++++---- .../Impl/Memory/PlatformMemoryStream.cs | 2 +- 15 files changed, 380 insertions(+), 69 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/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 c6b183b..7adbbbe 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 @@ -256,6 +256,7 @@ <ProjectReference Include="..\Examples\Apache.Ignite.ExamplesDll\Apache.Ignite.ExamplesDll.csproj"> <Project>{dfb08363-202e-412d-8812-349ef10a8702}</Project> <Name>Apache.Ignite.ExamplesDll</Name> + <Aliases>ExamplesDll</Aliases> </ProjectReference> <ProjectReference Include="..\Examples\Apache.Ignite.Examples\Apache.Ignite.Examples.csproj"> <Project>{069fa680-3c4d-43a9-b84f-e67513b87827}</Project> http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs index 549e453..927aa32 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs @@ -18,6 +18,8 @@ // ReSharper disable UnusedAutoPropertyAccessor.Local namespace Apache.Ignite.Core.Tests.Binary { + extern alias ExamplesDll; + using System; using System.Collections; using System.Collections.Generic; @@ -31,8 +33,11 @@ namespace Apache.Ignite.Core.Tests.Binary using Apache.Ignite.Core.Impl.Binary; using Apache.Ignite.Core.Impl.Common; using Apache.Ignite.Core.Tests.Compute; + using Apache.Ignite.ExamplesDll.Binary; using NUnit.Framework; + using ExamplesAccount = ExamplesDll::Apache.Ignite.ExamplesDll.Binary.Account; + /// <summary> /// Tests the dynamic type registration. /// </summary> @@ -329,6 +334,28 @@ namespace Apache.Ignite.Core.Tests.Binary } /// <summary> + /// Tests that types with same FullName from different assemblies are mapped to each other. + /// </summary> + [Test] + public void TestSameTypeInDifferentAssemblies() + { + using (var ignite1 = Ignition.Start(TestUtils.GetTestConfiguration())) + { + var cache1 = ignite1.CreateCache<int, ExamplesAccount>("acc"); + cache1[1] = new ExamplesAccount(1, 2.2m); + + using (var ignite2 = Ignition.Start(TestUtils.GetTestConfiguration(name: "ignite2"))) + { + var cache2 = ignite2.GetCache<int, Account>("acc"); + cache2[2] = new Account {Id = 2, Balance = 3.3m}; + + Assert.AreEqual(1, cache2[1].Id); // Read ExamplesAccount as Account. + Assert.AreEqual(2, cache1[2].Id); // Read Account as ExamplesAccount. + } + } + } + + /// <summary> /// Tests the type registration. /// </summary> private static void Test(IIgnite ignite1, IIgnite ignite2) @@ -492,3 +519,16 @@ namespace Apache.Ignite.Core.Tests.Binary } } } + +namespace Apache.Ignite.ExamplesDll.Binary +{ + /// <summary> + /// Copy of Account class in ExamplesDll. Same name and namespace, different assembly. + /// </summary> + public class Account + { + public int Id { get; set; } + + public decimal Balance { get; set; } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryNameMapperTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryNameMapperTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryNameMapperTest.cs index b3ace97..ff1f91d 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryNameMapperTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryNameMapperTest.cs @@ -61,6 +61,13 @@ namespace Apache.Ignite.Core.Tests.Binary Assert.AreEqual("Apache.Ignite.Core.Tests.Binary.BinaryNameMapperTest+Bar`1[[Apache.Ignite.Core.Tests." + "Binary.BinaryNameMapperTest+Foo[]]][]", mapper.GetTypeName(typeof(Bar<Foo[]>[]).AssemblyQualifiedName)); + + // Open generics. + Assert.AreEqual("System.Collections.Generic.List`1", + mapper.GetTypeName(typeof(List<>).AssemblyQualifiedName)); + + Assert.AreEqual("System.Collections.Generic.Dictionary`2", + mapper.GetTypeName(typeof(Dictionary<,>).AssemblyQualifiedName)); } /// <summary> http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeNameParserTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeNameParserTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeNameParserTest.cs index f3394a3..e566a4b 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeNameParserTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeNameParserTest.cs @@ -39,7 +39,7 @@ namespace Apache.Ignite.Core.Tests.Binary { // One letter. var res = TypeNameParser.Parse("x"); - Assert.AreEqual("x", res.GetFullName()); + Assert.AreEqual("x", res.GetNameWithNamespace()); Assert.AreEqual("x", res.GetName()); Assert.AreEqual(0, res.NameStart); Assert.AreEqual(0, res.NameEnd); @@ -79,78 +79,115 @@ namespace Apache.Ignite.Core.Tests.Binary [Test] public void TestGenericTypes() { - // Custom strings. + // Simple name. var res = TypeNameParser.Parse("List`1[[Int]]"); Assert.AreEqual("List`1", res.GetName()); - Assert.AreEqual("List`1", res.GetFullName()); + Assert.AreEqual("List`1", res.GetNameWithNamespace()); Assert.AreEqual("Int", res.Generics.Single().GetName()); - Assert.AreEqual("Int", res.Generics.Single().GetFullName()); + Assert.AreEqual("Int", res.Generics.Single().GetNameWithNamespace()); + + // Simple name array. + res = TypeNameParser.Parse("List`1[[Byte[]]]"); + Assert.AreEqual("List`1", res.GetName()); + Assert.AreEqual("List`1", res.GetNameWithNamespace()); + Assert.AreEqual("Byte", res.Generics.Single().GetName()); + Assert.AreEqual("Byte", res.Generics.Single().GetNameWithNamespace()); + Assert.AreEqual("[]", res.Generics.Single().GetArray()); + + // Simple name two-dimension array. + res = TypeNameParser.Parse("List`1[[Byte[,]]]"); + Assert.AreEqual("List`1", res.GetName()); + Assert.AreEqual("List`1", res.GetNameWithNamespace()); + Assert.AreEqual("Byte", res.Generics.Single().GetName()); + Assert.AreEqual("Byte", res.Generics.Single().GetNameWithNamespace()); + Assert.AreEqual("[,]", res.Generics.Single().GetArray()); + + // Simple name jagged array. + res = TypeNameParser.Parse("List`1[[Byte[][]]]"); + Assert.AreEqual("List`1", res.GetName()); + Assert.AreEqual("List`1", res.GetNameWithNamespace()); + Assert.AreEqual("Byte", res.Generics.Single().GetName()); + Assert.AreEqual("Byte", res.Generics.Single().GetNameWithNamespace()); + Assert.AreEqual("[][]", res.Generics.Single().GetArray()); + + // Open generic. + res = TypeNameParser.Parse("List`1"); + Assert.AreEqual("List`1", res.GetName()); + Assert.AreEqual("List`1", res.GetNameWithNamespace()); + Assert.IsEmpty(res.Generics); // One arg. res = TypeNameParser.Parse(typeof(List<int>).AssemblyQualifiedName); Assert.AreEqual("List`1", res.GetName()); - Assert.AreEqual("System.Collections.Generic.List`1", res.GetFullName()); + Assert.AreEqual("System.Collections.Generic.List`1", res.GetNameWithNamespace()); Assert.IsTrue(res.GetAssemblyName().StartsWith("mscorlib,")); Assert.AreEqual(1, res.Generics.Count); var gen = res.Generics.Single(); Assert.AreEqual("Int32", gen.GetName()); - Assert.AreEqual("System.Int32", gen.GetFullName()); + Assert.AreEqual("System.Int32", gen.GetNameWithNamespace()); Assert.IsTrue(gen.GetAssemblyName().StartsWith("mscorlib,")); + // One arg open. + res = TypeNameParser.Parse(typeof(List<>).AssemblyQualifiedName); + Assert.AreEqual("List`1", res.GetName()); + Assert.AreEqual("System.Collections.Generic.List`1", res.GetNameWithNamespace()); + Assert.IsTrue(res.GetAssemblyName().StartsWith("mscorlib,")); + Assert.IsEmpty(res.Generics); + // Two args. res = TypeNameParser.Parse(typeof(Dictionary<int, string>).AssemblyQualifiedName); Assert.AreEqual("Dictionary`2", res.GetName()); - Assert.AreEqual("System.Collections.Generic.Dictionary`2", res.GetFullName()); + Assert.AreEqual("System.Collections.Generic.Dictionary`2", res.GetNameWithNamespace()); Assert.IsTrue(res.GetAssemblyName().StartsWith("mscorlib,")); Assert.AreEqual(2, res.Generics.Count); gen = res.Generics.First(); Assert.AreEqual("Int32", gen.GetName()); - Assert.AreEqual("System.Int32", gen.GetFullName()); + Assert.AreEqual("System.Int32", gen.GetNameWithNamespace()); Assert.IsTrue(gen.GetAssemblyName().StartsWith("mscorlib,")); gen = res.Generics.Last(); Assert.AreEqual("String", gen.GetName()); - Assert.AreEqual("System.String", gen.GetFullName()); + Assert.AreEqual("System.String", gen.GetNameWithNamespace()); Assert.IsTrue(gen.GetAssemblyName().StartsWith("mscorlib,")); // Nested args. res = TypeNameParser.Parse(typeof(Dictionary<int, List<string>>).FullName); Assert.AreEqual("Dictionary`2", res.GetName()); - Assert.AreEqual("System.Collections.Generic.Dictionary`2", res.GetFullName()); + Assert.AreEqual("System.Collections.Generic.Dictionary`2", res.GetNameWithNamespace()); Assert.IsNull(res.GetAssemblyName()); Assert.AreEqual(2, res.Generics.Count); gen = res.Generics.Last(); Assert.AreEqual("List`1", gen.GetName()); - Assert.AreEqual("System.Collections.Generic.List`1", gen.GetFullName()); + Assert.AreEqual("System.Collections.Generic.List`1", gen.GetNameWithNamespace()); Assert.IsTrue(gen.GetAssemblyName().StartsWith("mscorlib,")); Assert.AreEqual(1, gen.Generics.Count); gen = gen.Generics.Single(); Assert.AreEqual("String", gen.GetName()); - Assert.AreEqual("System.String", gen.GetFullName()); + Assert.AreEqual("System.String", gen.GetNameWithNamespace()); Assert.IsTrue(gen.GetAssemblyName().StartsWith("mscorlib,")); // Nested class. res = TypeNameParser.Parse(typeof(NestedGeneric<int>).FullName); Assert.AreEqual("NestedGeneric`1", res.GetName()); - Assert.AreEqual("Apache.Ignite.Core.Tests.Binary.TypeNameParserTest+NestedGeneric`1", res.GetFullName()); + Assert.AreEqual("Apache.Ignite.Core.Tests.Binary.TypeNameParserTest+NestedGeneric`1", res.GetNameWithNamespace()); gen = res.Generics.Single(); Assert.AreEqual("Int32", gen.GetName()); - Assert.AreEqual("System.Int32", gen.GetFullName()); + Assert.AreEqual("System.Int32", gen.GetNameWithNamespace()); res = TypeNameParser.Parse(typeof(NestedGeneric<int>.NestedGeneric2<string>).AssemblyQualifiedName); Assert.AreEqual("NestedGeneric2`1", res.GetName()); Assert.AreEqual("Apache.Ignite.Core.Tests.Binary.TypeNameParserTest+NestedGeneric`1+NestedGeneric2`1", - res.GetFullName()); + res.GetNameWithNamespace()); Assert.AreEqual(2, res.Generics.Count); Assert.AreEqual("Int32", res.Generics.First().GetName()); @@ -163,9 +200,30 @@ namespace Apache.Ignite.Core.Tests.Binary [Test] public void TestArrays() { + var res = TypeNameParser.Parse("Int32[]"); + Assert.AreEqual("Int32", res.GetName()); + Assert.AreEqual("Int32", res.GetNameWithNamespace()); + Assert.AreEqual("Int32[]", res.GetFullName()); + Assert.AreEqual("[]", res.GetArray()); + + res = TypeNameParser.Parse("Int32[*]"); + Assert.AreEqual("Int32", res.GetName()); + Assert.AreEqual("Int32", res.GetNameWithNamespace()); + Assert.AreEqual("Int32[*]", res.GetFullName()); + Assert.AreEqual("[*]", res.GetArray()); + + res = TypeNameParser.Parse("List`1[[Int32]][]"); + Assert.AreEqual("List`1", res.GetName()); + Assert.AreEqual("List`1", res.GetNameWithNamespace()); + Assert.AreEqual("List`1[[Int32]][]", res.GetFullName()); + Assert.AreEqual("[]", res.GetArray()); + CheckType(typeof(int[])); + CheckType(typeof(int).MakeArrayType(1)); CheckType(typeof(int[,])); + CheckType(typeof(int[,,])); CheckType(typeof(int[][])); + CheckType(typeof(int[,,,][,,])); CheckType(typeof(List<int>[])); CheckType(typeof(List<int>[,])); @@ -184,12 +242,9 @@ namespace Apache.Ignite.Core.Tests.Binary Assert.Throws<IgniteException>(() => TypeNameParser.Parse("x[")); Assert.Throws<IgniteException>(() => TypeNameParser.Parse("x[[]")); Assert.Throws<IgniteException>(() => TypeNameParser.Parse("x`[")); - Assert.Throws<IgniteException>(() => TypeNameParser.Parse("x`]")); Assert.Throws<IgniteException>(() => TypeNameParser.Parse("x`[ ]")); Assert.Throws<IgniteException>(() => TypeNameParser.Parse("x,")); - Assert.Throws<IgniteException>(() => TypeNameParser.Parse("x`x")); Assert.Throws<IgniteException>(() => TypeNameParser.Parse("x`2[x")); - Assert.Throws<IgniteException>(() => TypeNameParser.Parse("x`2xx")); } /// <summary> @@ -207,7 +262,7 @@ namespace Apache.Ignite.Core.Tests.Binary if (res.Generics == null) { - Assert.AreEqual(type.FullName, res.GetFullName() + res.GetArray()); + Assert.AreEqual(type.FullName, res.GetNameWithNamespace() + res.GetArray()); } Assert.AreEqual(type.FullName.Length + 2, res.AssemblyStart); http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeResolverTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeResolverTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeResolverTest.cs index 7d37584..6ed1a5f 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeResolverTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeResolverTest.cs @@ -21,6 +21,7 @@ namespace Apache.Ignite.Core.Tests.Binary using System.Collections.Generic; using System.Linq; using System.Reflection; + using Apache.Ignite.Core.Binary; using Apache.Ignite.Core.Impl.Binary; using Apache.Ignite.Core.Tests.TestDll; using NUnit.Framework; @@ -31,6 +32,35 @@ namespace Apache.Ignite.Core.Tests.Binary public class TypeResolverTest { /// <summary> + /// Tests basic types. + /// </summary> + [Test] + public void TestBasicTypes() + { + var resolver = new TypeResolver(); + + Assert.AreEqual(typeof(int), resolver.ResolveType("System.Int32")); + Assert.AreEqual(GetType(), resolver.ResolveType(GetType().FullName)); + + Assert.IsNull(resolver.ResolveType("invalidType")); + } + + /// <summary> + /// Tests basic types. + /// </summary> + [Test] + public void TestBasicTypesSimpleMapper() + { + var resolver = new TypeResolver(); + var mapper = BinaryBasicNameMapper.SimpleNameInstance; + + Assert.AreEqual(typeof(int), resolver.ResolveType("Int32", nameMapper: mapper)); + Assert.AreEqual(GetType(), resolver.ResolveType("TypeResolverTest", nameMapper: mapper)); + + Assert.IsNull(resolver.ResolveType("invalidType", nameMapper: mapper)); + } + + /// <summary> /// Tests generic type resolve. /// </summary> [Test] @@ -67,6 +97,80 @@ namespace Apache.Ignite.Core.Tests.Binary } /// <summary> + /// Tests generic type resolve. + /// </summary> + [Test] + public void TestGenericsSimpleName() + { + var resolver = new TypeResolver(); + var mapper = BinaryBasicNameMapper.SimpleNameInstance; + + Assert.AreEqual(typeof(TestGenericBinarizable<int>), + resolver.ResolveType("TestGenericBinarizable`1[[Int32]]", nameMapper: mapper)); + + Assert.IsNull(resolver.ResolveType("TestGenericBinarizable`1[[Invalid-Type]]", nameMapper: mapper)); + + var testTypes = new[] + { + typeof (TestGenericBinarizable<int>), + typeof (TestGenericBinarizable<string>), + typeof (TestGenericBinarizable<TestGenericBinarizable<int>>), + typeof (TestGenericBinarizable<List<Tuple<int, string>>>), + typeof (TestGenericBinarizable<List<TestGenericBinarizable<List<Tuple<int, string>>>>>), + typeof (List<TestGenericBinarizable<List<TestGenericBinarizable<List<Tuple<int, string>>>>>>), + typeof (TestGenericBinarizable<int, string>), + typeof (TestGenericBinarizable<int, TestGenericBinarizable<string>>), + typeof (TestGenericBinarizable<int, string, Type>), + typeof (TestGenericBinarizable<int, string, TestGenericBinarizable<int, string, Type>>) + }; + + foreach (var type in testTypes) + { + var typeName = mapper.GetTypeName(type.AssemblyQualifiedName); + var resolvedType = resolver.ResolveType(typeName, nameMapper: mapper); + Assert.AreEqual(type, resolvedType); + } + } + + /// <summary> + /// Tests array type resolve. + /// </summary> + [Test] + public void TestArrays() + { + var resolver = new TypeResolver(); + + Assert.AreEqual(typeof(int[]), resolver.ResolveType("System.Int32[]")); + Assert.AreEqual(typeof(int[][]), resolver.ResolveType("System.Int32[][]")); + Assert.AreEqual(typeof(int[,,][,]), resolver.ResolveType("System.Int32[,][,,]")); + + Assert.AreEqual(typeof(int).MakeArrayType(1), resolver.ResolveType("System.Int32[*]")); + + Assert.AreEqual(typeof(TestGenericBinarizable<TypeResolverTest>[]), + resolver.ResolveType("Apache.Ignite.Core.Tests.TestGenericBinarizable`1" + + "[[Apache.Ignite.Core.Tests.Binary.TypeResolverTest]][]")); + } + + /// <summary> + /// Tests array type resolve. + /// </summary> + [Test] + public void TestArraysSimpleName() + { + var resolver = new TypeResolver(); + var mapper = BinaryBasicNameMapper.SimpleNameInstance; + + Assert.AreEqual(typeof(int[]), resolver.ResolveType("Int32[]", nameMapper: mapper)); + Assert.AreEqual(typeof(int[][]), resolver.ResolveType("Int32[][]", nameMapper: mapper)); + Assert.AreEqual(typeof(int[,,][,]), resolver.ResolveType("Int32[,][,,]", nameMapper: mapper)); + + Assert.AreEqual(typeof(int).MakeArrayType(1), resolver.ResolveType("Int32[*]", nameMapper: mapper)); + + Assert.AreEqual(typeof(TestGenericBinarizable<TypeResolverTest>[]), + resolver.ResolveType("TestGenericBinarizable`1[[TypeResolverTest]][]", nameMapper: mapper)); + } + + /// <summary> /// Tests loading a type from referenced assembly that is not yet loaded. /// </summary> [Test] http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs index 1fa993b..01277e1 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs @@ -30,7 +30,6 @@ namespace Apache.Ignite.Core.Tests.Cache.Query using Apache.Ignite.Core.Cache.Configuration; using Apache.Ignite.Core.Cache.Query; using Apache.Ignite.Core.Common; - using Apache.Ignite.Core.Impl.Binary; using NUnit.Framework; /// <summary> @@ -442,7 +441,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Query [Test] public void TestScanQueryBinary([Values(true, false)] bool loc) { - CheckScanQuery<BinaryObject>(loc, true); + CheckScanQuery<IBinaryObject>(loc, true); } /// <summary> @@ -460,7 +459,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Query [Test] public void TestScanQueryPartitionsBinary([Values(true, false)] bool loc) { - CheckScanQueryPartitions<BinaryObject>(loc, true); + CheckScanQueryPartitions<IBinaryObject>(loc, true); } /// <summary> http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core.Tests/DeploymentTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/DeploymentTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/DeploymentTest.cs index 74da531..cb97076 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/DeploymentTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/DeploymentTest.cs @@ -79,6 +79,7 @@ namespace Apache.Ignite.Core.Tests { "-springConfigUrl=" + springFile, "-jvmClasspath=" + classpath, + "-assembly=" + Path.GetFileName(GetType().Assembly.Location), "-J-ea", "-J-Xms512m", "-J-Xmx512m" http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs index e041fd7..9389185 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs @@ -17,12 +17,12 @@ namespace Apache.Ignite.Core.Tests.Examples { + extern alias ExamplesDll; using System; using System.Collections.Generic; using System.IO; using System.Linq; using Apache.Ignite.Core.Tests.Process; - using Apache.Ignite.ExamplesDll.Compute; using NUnit.Framework; /// <summary> @@ -130,7 +130,8 @@ namespace Apache.Ignite.Core.Tests.Examples var args = new List<string> { "-configFileName=" + _configPath, - "-assembly=" + typeof(AverageSalaryJob).Assembly.Location + "-assembly=" + typeof(ExamplesDll::Apache.Ignite.ExamplesDll.Compute.AverageSalaryJob) + .Assembly.Location }; var proc = new IgniteProcess(args.ToArray()); http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryBasicNameMapper.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryBasicNameMapper.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryBasicNameMapper.cs index 0a6406b..c75303f 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryBasicNameMapper.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryBasicNameMapper.cs @@ -57,7 +57,7 @@ namespace Apache.Ignite.Core.Binary if (parsedName.Generics == null) { // Generics are rare, use simpler logic for the common case. - var res = IsSimpleName ? parsedName.GetName() : parsedName.GetFullName(); + var res = IsSimpleName ? parsedName.GetName() : parsedName.GetNameWithNamespace(); var arr = parsedName.GetArray(); @@ -71,7 +71,7 @@ namespace Apache.Ignite.Core.Binary var nameFunc = IsSimpleName ? (Func<TypeNameParser, string>) (x => x.GetName()) - : (x => x.GetFullName()); + : (x => x.GetNameWithNamespace()); return BuildTypeName(parsedName, new StringBuilder(), nameFunc).ToString(); } @@ -94,7 +94,7 @@ namespace Apache.Ignite.Core.Binary var generics = typeName.Generics; - if (generics != null) + if (generics != null && generics.Count > 0) // Generics are non-null but empty when unbound. { sb.Append('['); http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs index 555a042..df30a6d 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs @@ -161,17 +161,17 @@ namespace Apache.Ignite.Core.Impl.Binary /// Registers the type. /// </summary> /// <param name="id">The identifier.</param> - /// <param name="type">The type.</param> + /// <param name="typeName">The type name.</param> /// <returns>True if registration succeeded; otherwise, false.</returns> - public bool RegisterType(int id, Type type) + public bool RegisterType(int id, string typeName) { - Debug.Assert(type != null); + Debug.Assert(typeName != null); Debug.Assert(id != BinaryUtils.TypeUnregistered); return DoOutOp((int) Op.RegisterType, w => { w.WriteInt(id); - w.WriteString(type.AssemblyQualifiedName); + w.WriteString(typeName); }) == True; } @@ -180,12 +180,9 @@ namespace Apache.Ignite.Core.Impl.Binary /// </summary> /// <param name="id">The identifier.</param> /// <returns>Type or null.</returns> - public Type GetType(int id) + public string GetTypeName(int id) { - var typeName = DoOutInOp((int) Op.GetType, w => w.WriteInt(id), - r => Marshaller.StartUnmarshal(r).ReadString()); - - return new TypeResolver().ResolveType(typeName); + return DoOutInOp((int) Op.GetType, w => w.WriteInt(id), r => Marshaller.StartUnmarshal(r).ReadString()); } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs index 49bab77..a5c6814 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs @@ -704,13 +704,13 @@ namespace Apache.Ignite.Core.Impl.Binary { throw new BinaryObjectException(string.Format( "Unknown type ID: {0}. " + - "This usually indicates missing BinaryConfiguration." + + "This usually indicates missing BinaryConfiguration. " + "Make sure that all nodes have the same BinaryConfiguration.", hdr.TypeId)); } throw new BinaryObjectException(string.Format( - "No matching type found for object [typeId={0}, typeName={1}]." + - "This usually indicates that assembly with specified type is not loaded on a node." + + "No matching type found for object [typeId={0}, typeName={1}]. " + + "This usually indicates that assembly with specified type is not loaded on a node. " + "When using Apache.Ignite.exe, make sure to load assemblies with -assembly parameter.", desc.TypeId, desc.TypeName)); } http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs index 4707ce2..ea2964a 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs @@ -439,13 +439,21 @@ namespace Apache.Ignite.Core.Impl.Binary if (!userType) return null; - if (requiresType) + if (requiresType && _ignite != null) { // Check marshaller context for dynamically registered type. - var type = _ignite == null ? null : _ignite.BinaryProcessor.GetType(typeId); + var typeName = _ignite.BinaryProcessor.GetTypeName(typeId); - if (type != null) - return AddUserType(type, typeId, GetTypeName(type), true, desc); + if (typeName != null) + { + var type = new TypeResolver().ResolveType(typeName, nameMapper: + _cfg.NameMapper ?? GetDefaultNameMapper()); + + if (type != null) + { + return AddUserType(type, typeId, GetTypeName(type), true, desc); + } + } } var meta = GetBinaryType(typeId); @@ -475,7 +483,7 @@ namespace Apache.Ignite.Core.Impl.Binary var typeName = GetTypeName(type); var typeId = GetTypeId(typeName, _cfg.IdMapper); - var registered = _ignite != null && _ignite.BinaryProcessor.RegisterType(typeId, type); + var registered = _ignite != null && _ignite.BinaryProcessor.RegisterType(typeId, typeName); return AddUserType(type, typeId, typeName, registered, desc); } http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeNameParser.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeNameParser.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeNameParser.cs index 527d47c..a925770 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeNameParser.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeNameParser.cs @@ -78,6 +78,11 @@ namespace Apache.Ignite.Core.Impl.Binary public int NameEnd { get; private set; } /// <summary> + /// Gets the name end. + /// </summary> + public int FullNameEnd { get; private set; } + + /// <summary> /// Gets the start of the assembly name. /// </summary> public int AssemblyStart { get; private set; } @@ -116,7 +121,7 @@ namespace Apache.Ignite.Core.Impl.Binary /// <summary> /// Gets the full type name (with namespace). /// </summary> - public string GetFullName() + public string GetNameWithNamespace() { if (NameEnd < 0) return null; @@ -125,6 +130,14 @@ namespace Apache.Ignite.Core.Impl.Binary } /// <summary> + /// Gets the full name (with namespace, generics and arrays). + /// </summary> + public string GetFullName() + { + return _typeName.Substring(_start, FullNameEnd - _start + 1); + } + + /// <summary> /// Gets the array part. /// </summary> public string GetArray() @@ -164,6 +177,7 @@ namespace Apache.Ignite.Core.Impl.Binary ParseTypeName(); ParseGeneric(); ParseArrayDefinition(); + FullNameEnd = End ? _pos : _pos - 1; ParseAssemblyName(); } @@ -183,7 +197,7 @@ namespace Apache.Ignite.Core.Impl.Binary if (Char == '`') { - // Non-null ist indicates detected generic type. + // Non-null list indicates detected generic type. Generics = Generics ?? new List<TypeNameParser>(); } @@ -207,6 +221,12 @@ namespace Apache.Ignite.Core.Impl.Binary return; } + if (End || Char == ',') + { + // Open (unbound) generic. + return; + } + if (Char != '[') { throw new IgniteException("Invalid generic type name, number must be followed by '[': " + _typeName); @@ -274,15 +294,18 @@ namespace Apache.Ignite.Core.Impl.Binary { if (!bracket) { - throw new IgniteException("Invalid array specification: " + _typeName); + ArrayEnd = _pos - 1; + return; } bracket = false; } - else if (Char == ',') + else if (Char == ',' || Char == '*') { if (!bracket) + { break; + } } else { http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs index 68222d4..fa59d62 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs @@ -23,6 +23,7 @@ namespace Apache.Ignite.Core.Impl.Binary using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; + using Apache.Ignite.Core.Binary; /// <summary> /// Resolves types by name. @@ -37,10 +38,11 @@ namespace Apache.Ignite.Core.Impl.Binary /// </summary> /// <param name="typeName">Name of the type.</param> /// <param name="assemblyName">Optional, name of the assembly.</param> + /// <param name="nameMapper">The name mapper.</param> /// <returns> /// Resolved type. /// </returns> - public Type ResolveType(string typeName, string assemblyName = null) + public Type ResolveType(string typeName, string assemblyName = null, IBinaryNameMapper nameMapper = null) { Debug.Assert(!string.IsNullOrEmpty(typeName)); @@ -55,8 +57,8 @@ namespace Apache.Ignite.Core.Impl.Binary var parsedType = TypeNameParser.Parse(typeName); // Partial names should be resolved by scanning assemblies. - return ResolveType(assemblyName, parsedType, AppDomain.CurrentDomain.GetAssemblies()) - ?? ResolveTypeInReferencedAssemblies(assemblyName, parsedType); + return ResolveType(assemblyName, parsedType, AppDomain.CurrentDomain.GetAssemblies(), nameMapper) + ?? ResolveTypeInReferencedAssemblies(assemblyName, parsedType, nameMapper); } /// <summary> @@ -65,12 +67,14 @@ namespace Apache.Ignite.Core.Impl.Binary /// <param name="assemblyName">Name of the assembly.</param> /// <param name="typeName">Name of the type.</param> /// <param name="assemblies">Assemblies to look in.</param> + /// <param name="nameMapper">The name mapper.</param> /// <returns> /// Resolved type. /// </returns> - private static Type ResolveType(string assemblyName, TypeNameParser typeName, ICollection<Assembly> assemblies) + private static Type ResolveType(string assemblyName, TypeNameParser typeName, ICollection<Assembly> assemblies, + IBinaryNameMapper nameMapper) { - var type = ResolveNonGenericType(assemblyName, typeName.GetFullName(), assemblies); + var type = ResolveNonGenericType(assemblyName, typeName.GetNameWithNamespace(), assemblies, nameMapper); if (type == null) { @@ -79,9 +83,54 @@ namespace Apache.Ignite.Core.Impl.Binary if (type.IsGenericTypeDefinition && typeName.Generics != null) { - var genArgs = typeName.Generics.Select(x => ResolveType(assemblyName, x, assemblies)).ToArray(); + var genArgs = typeName.Generics + .Select(x => ResolveType(assemblyName, x, assemblies, nameMapper)).ToArray(); - return type.MakeGenericType(genArgs); + if (genArgs.Any(x => x == null)) + { + return null; + } + + type = type.MakeGenericType(genArgs); + } + + return MakeArrayType(type, typeName.GetArray()); + } + + /// <summary> + /// Makes the array type according to spec, e.g. "[,][]". + /// </summary> + private static Type MakeArrayType(Type type, string arraySpec) + { + if (arraySpec == null) + { + return type; + } + + int? rank = null; + + foreach (var c in arraySpec) + { + switch (c) + { + case '[': + rank = null; + break; + + case ',': + rank = rank == null ? 2 : rank + 1; + break; + + case '*': + rank = 1; + break; + + case ']': + type = rank == null + ? type.MakeArrayType() + : type.MakeArrayType(rank.Value); + break; + } } return type; @@ -93,8 +142,10 @@ namespace Apache.Ignite.Core.Impl.Binary /// <param name="assemblyName">Name of the assembly.</param> /// <param name="typeName">Name of the type.</param> /// <param name="assemblies">The assemblies.</param> + /// <param name="nameMapper">The name mapper.</param> /// <returns>Resolved type, or null.</returns> - private static Type ResolveNonGenericType(string assemblyName, string typeName, ICollection<Assembly> assemblies) + private static Type ResolveNonGenericType(string assemblyName, string typeName, + ICollection<Assembly> assemblies, IBinaryNameMapper nameMapper) { // Fully-qualified name can be resolved with system mechanism. var type = Type.GetType(typeName, false); @@ -115,15 +166,7 @@ namespace Apache.Ignite.Core.Impl.Binary return null; } - // Trim assembly qualification - var commaIdx = typeName.IndexOf(','); - - if (commaIdx > 0) - { - typeName = typeName.Substring(0, commaIdx); - } - - return assemblies.Select(a => a.GetType(typeName, false, false)).FirstOrDefault(x => x != null); + return assemblies.Select(a => FindType(a, typeName, nameMapper)).FirstOrDefault(x => x != null); } /// <summary> @@ -131,10 +174,12 @@ namespace Apache.Ignite.Core.Impl.Binary /// </summary> /// <param name="assemblyName">Name of the assembly.</param> /// <param name="typeName">Name of the type.</param> + /// <param name="nameMapper">The name mapper.</param> /// <returns> /// Resolved type. /// </returns> - private Type ResolveTypeInReferencedAssemblies(string assemblyName, TypeNameParser typeName) + private Type ResolveTypeInReferencedAssemblies(string assemblyName, TypeNameParser typeName, + IBinaryNameMapper nameMapper) { ResolveEventHandler resolver = (sender, args) => GetReflectionOnlyAssembly(args.Name); @@ -142,7 +187,8 @@ namespace Apache.Ignite.Core.Impl.Binary try { - var result = ResolveType(assemblyName, typeName, GetNotLoadedReferencedAssemblies().ToArray()); + var result = ResolveType(assemblyName, typeName, GetNotLoadedReferencedAssemblies().ToArray(), + nameMapper); if (result == null) return null; @@ -150,7 +196,7 @@ namespace Apache.Ignite.Core.Impl.Binary // result is from ReflectionOnly assembly, load it properly into current domain var asm = AppDomain.CurrentDomain.Load(result.Assembly.GetName()); - return asm.GetType(result.FullName); + return FindType(asm, result.FullName, nameMapper); } finally { @@ -215,5 +261,34 @@ namespace Apache.Ignite.Core.Impl.Binary roots.Push(refAsm); } } + + /// <summary> + /// Finds the type within assembly. + /// </summary> + private static Type FindType(Assembly asm, string typeName, IBinaryNameMapper mapper) + { + if (mapper == null) + { + return asm.GetType(typeName); + } + + return GetAssemblyTypesSafe(asm).FirstOrDefault(x => mapper.GetTypeName(x.FullName) == typeName); + } + + /// <summary> + /// Safely gets all assembly types. + /// </summary> + private static IEnumerable<Type> GetAssemblyTypesSafe(Assembly asm) + { + try + { + return asm.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { + // Handle the situation where some assembly dependencies are not available. + return ex.Types.Where(x => x != null); + } + } } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs index f8ff85c..033de7e 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs @@ -893,7 +893,7 @@ namespace Apache.Ignite.Core.Impl.Memory /// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing) SynchronizeOutput();
