IGNITE-4406 .NET: Control DateTime serialization via attribute
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/25bcd43a Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/25bcd43a Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/25bcd43a Branch: refs/heads/ignite-5075 Commit: 25bcd43a63c7d6496e92237cb965d32d4075722d Parents: 0eb9507 Author: Pavel Tupitsyn <ptupit...@apache.org> Authored: Thu May 18 10:39:16 2017 +0300 Committer: Pavel Tupitsyn <ptupit...@apache.org> Committed: Thu May 18 10:39:16 2017 +0300 ---------------------------------------------------------------------- .../Apache.Ignite.Core.Tests.csproj | 1 + .../Binary/BinaryDateTimeTest.cs | 204 +++++++++++++++++++ .../Binary/BinarySelfTest.cs | 2 +- .../Cache/Query/CacheLinqTest.cs | 2 +- .../Apache.Ignite.Core.csproj | 1 + .../Binary/BinaryReflectiveSerializer.cs | 44 +++- .../Binary/TimestampAttribute.cs | 40 ++++ .../Impl/Binary/BinaryReflectiveActions.cs | 89 ++++---- .../BinaryReflectiveSerializerInternal.cs | 10 +- .../Impl/Binary/BinaryUtils.cs | 4 +- 10 files changed, 351 insertions(+), 46 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/25bcd43a/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 13e4889..f27e774 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 @@ -69,6 +69,7 @@ </ItemGroup> <ItemGroup> <Compile Include="Binary\BinaryBuilderSelfTestSimpleName.cs" /> + <Compile Include="Binary\BinaryDateTimeTest.cs" /> <Compile Include="Binary\BinaryEqualityComparerTest.cs" /> <Compile Include="Binary\BinaryBuilderSelfTestDynamicRegistration.cs" /> <Compile Include="Binary\BinaryNameMapperTest.cs" /> http://git-wip-us.apache.org/repos/asf/ignite/blob/25bcd43a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDateTimeTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDateTimeTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDateTimeTest.cs new file mode 100644 index 0000000..e971eea --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDateTimeTest.cs @@ -0,0 +1,204 @@ +/* + * 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 +{ + using System; + using System.Linq; + using Apache.Ignite.Core.Binary; + using Apache.Ignite.Core.Cache.Configuration; + using NUnit.Framework; + + /// <summary> + /// DateTime binary serialization tests. + /// </summary> + public class BinaryDateTimeTest + { + /// <summary> + /// Sets up the test fixture. + /// </summary> + [TestFixtureSetUp] + public void FixtureSetUp() + { + Ignition.Start(new IgniteConfiguration(TestUtils.GetTestConfiguration()) + { + BinaryConfiguration = new BinaryConfiguration + { + TypeConfigurations = new[] + { + new BinaryTypeConfiguration(typeof(DateTimeObj2)) + { + Serializer = new BinaryReflectiveSerializer {ForceTimestamp = true} + } + } + } + }); + } + + /// <summary> + /// Tears down the test fixture. + /// </summary> + [TestFixtureTearDown] + public void FixtureTearDown() + { + Ignition.StopAll(true); + } + + /// <summary> + /// Tests the default behavior: DateTime is written as ISerializable object. + /// </summary> + [Test] + public void TestDefaultBehavior() + { + AssertDateTimeField<DateTimeObj>((o, d) => o.Value = d, o => o.Value, "Value"); + } + + /// <summary> + /// Tests the ForceTimestamp option in serializer. + /// </summary> + [Test] + public void TestSerializerForceTimestamp() + { + // Check config. + var ser = Ignition.GetIgnite() + .GetConfiguration() + .BinaryConfiguration.TypeConfigurations + .Select(x => x.Serializer) + .OfType<BinaryReflectiveSerializer>() + .Single(); + + Assert.IsTrue(ser.ForceTimestamp); + + AssertTimestampField<DateTimeObj2>((o, d) => o.Value = d, o => o.Value, "Value"); + } + + /// <summary> + /// Tests TimestampAttribute applied to class members. + /// </summary> + [Test] + public void TestMemberAttributes() + { + AssertTimestampField<DateTimePropertyAttribute>((o, d) => o.Value = d, o => o.Value, "Value"); + + AssertTimestampField<DateTimeFieldAttribute>((o, d) => o.Value = d, o => o.Value, "Value"); + + AssertTimestampField<DateTimeQueryFieldAttribute>((o, d) => o.Value = d, o => o.Value, "Value"); + } + + /// <summary> + /// Tests TimestampAttribute applied to entire class. + /// </summary> + [Test] + public void TestClassAttributes() + { + AssertTimestampField<DateTimeClassAttribute>((o, d) => o.Value = d, o => o.Value, "Value"); + + AssertTimestampField<DateTimeClassAttribute2>((o, d) => o.Value = d, o => o.Value, "Value"); + } + + /// <summary> + /// Asserts that specified field is serialized as DateTime object. + /// </summary> + private static void AssertDateTimeField<T>(Action<T, DateTime> setValue, + Func<T, DateTime> getValue, string fieldName) where T : new() + { + var binary = Ignition.GetIgnite().GetBinary(); + + foreach (var dateTime in new[] { DateTime.Now, DateTime.UtcNow, DateTime.MinValue, DateTime.MaxValue }) + { + var obj = new T(); + setValue(obj, dateTime); + + var bin = binary.ToBinary<IBinaryObject>(obj); + var res = bin.Deserialize<T>(); + + Assert.AreEqual(getValue(obj), getValue(res)); + Assert.AreEqual(getValue(obj), bin.GetField<IBinaryObject>(fieldName).Deserialize<DateTime>()); + Assert.AreEqual("Object", bin.GetBinaryType().GetFieldTypeName(fieldName)); + } + } + + /// <summary> + /// Asserts that specified field is serialized as Timestamp. + /// </summary> + private static void AssertTimestampField<T>(Action<T, DateTime> setValue, + Func<T, DateTime> getValue, string fieldName) where T : new() + { + // Non-UTC DateTime throws. + var binary = Ignition.GetIgnite().GetBinary(); + + var obj = new T(); + + setValue(obj, DateTime.Now); + + var ex = Assert.Throws<BinaryObjectException>(() => binary.ToBinary<IBinaryObject>(obj), + "Timestamp fields should throw an error on non-UTC values"); + + Assert.AreEqual("DateTime is not UTC. Only UTC DateTime can be used for interop with other platforms.", + ex.Message); + + // UTC DateTime works. + setValue(obj, DateTime.UtcNow); + var bin = binary.ToBinary<IBinaryObject>(obj); + var res = bin.Deserialize<T>(); + + Assert.AreEqual(getValue(obj), getValue(res)); + Assert.AreEqual(getValue(obj), bin.GetField<DateTime>(fieldName)); + Assert.AreEqual("Timestamp", bin.GetBinaryType().GetFieldTypeName(fieldName)); + } + + private class DateTimeObj + { + public DateTime Value { get; set; } + } + + private class DateTimeObj2 + { + public DateTime Value { get; set; } + } + + private class DateTimePropertyAttribute + { + [Timestamp] + public DateTime Value { get; set; } + } + + private class DateTimeFieldAttribute + { + [Timestamp] + public DateTime Value; + } + + private class DateTimeQueryFieldAttribute + { + [QuerySqlField] + public DateTime Value { get; set; } + } + + [Timestamp] + private class DateTimeClassAttribute + { + public DateTime Value { get; set; } + } + + [Timestamp] + private class DateTimeClassAttribute2 + { + public DateTime Value; + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/25bcd43a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs index 4a0827b..bae126f 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinarySelfTest.cs @@ -673,7 +673,7 @@ namespace Apache.Ignite.Core.Tests.Binary // Check exception with non-UTC date var stream = new BinaryHeapStream(128); var writer = _marsh.StartMarshal(stream); - Assert.Throws<InvalidOperationException>(() => writer.WriteTimestamp(DateTime.Now)); + Assert.Throws<BinaryObjectException>(() => writer.WriteTimestamp(DateTime.Now)); } /** http://git-wip-us.apache.org/repos/asf/ignite/blob/25bcd43a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs index ab661cf..265a149 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs @@ -895,7 +895,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Query // Invalid dateTime // ReSharper disable once ReturnValueOfPureMethodIsNotUsed - var ex = Assert.Throws<InvalidOperationException>(() => + var ex = Assert.Throws<BinaryObjectException>(() => roles.Where(x => x.Value.Date > DateTime.Now).ToArray()); Assert.AreEqual("DateTime is not UTC. Only UTC DateTime can be used for interop with other platforms.", ex.Message); http://git-wip-us.apache.org/repos/asf/ignite/blob/25bcd43a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj index fd6e5ec..25b9603 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj @@ -92,6 +92,7 @@ </ItemGroup> <ItemGroup> <Compile Include="Binary\BinaryBasicNameMapper.cs" /> + <Compile Include="Binary\TimestampAttribute.cs" /> <Compile Include="Cache\Configuration\DataPageEvictionMode.cs" /> <Compile Include="Cache\Configuration\MemoryPolicyConfiguration.cs" /> <Compile Include="Cache\Configuration\PartitionLossPolicy.cs" /> http://git-wip-us.apache.org/repos/asf/ignite/blob/25bcd43a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryReflectiveSerializer.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryReflectiveSerializer.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryReflectiveSerializer.cs index c2f00e6..f9874ba 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryReflectiveSerializer.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryReflectiveSerializer.cs @@ -45,6 +45,9 @@ namespace Apache.Ignite.Core.Binary /** In use flag. */ private bool _isInUse; + /** Force timestamp flag. */ + private bool _forceTimestamp; + /// <summary> /// Write binary object. /// </summary> @@ -76,15 +79,35 @@ namespace Apache.Ignite.Core.Binary get { return _rawMode; } set { - if (_isInUse) - throw new InvalidOperationException(typeof(BinaryReflectiveSerializer).Name + - ".RawMode cannot be changed after first serialization."); + ThrowIfInUse(); _rawMode = value; } } /// <summary> + /// Gets or sets a value indicating whether all DateTime values should be written as Timestamp. + /// <para /> + /// Timestamp format is required for values used in SQL and for interoperation with other platforms. + /// Only UTC values are supported in Timestamp format. Other values will cause an exception on write. + /// <para /> + /// Normally serializer uses <see cref="IBinaryWriter.WriteObject{T}"/> for DateTime fields. + /// This attribute changes the behavior to <see cref="IBinaryWriter.WriteTimestamp"/>. + /// <para /> + /// See also <see cref="TimestampAttribute"/>. + /// </summary> + public bool ForceTimestamp + { + get { return _forceTimestamp; } + set + { + ThrowIfInUse(); + + _forceTimestamp = value; + } + } + + /// <summary> /// Registers the specified type. /// </summary> internal IBinarySerializerInternal Register(Type type, int typeId, IBinaryNameMapper converter, @@ -92,7 +115,20 @@ namespace Apache.Ignite.Core.Binary { _isInUse = true; - return new BinaryReflectiveSerializerInternal(_rawMode).Register(type, typeId, converter, idMapper); + return new BinaryReflectiveSerializerInternal(_rawMode) + .Register(type, typeId, converter, idMapper, _forceTimestamp); + } + + /// <summary> + /// Throws an exception if this instance is already in use. + /// </summary> + private void ThrowIfInUse() + { + if (_isInUse) + { + throw new InvalidOperationException(typeof(BinaryReflectiveSerializer).Name + + ".RawMode cannot be changed after first serialization."); + } } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/25bcd43a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/TimestampAttribute.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/TimestampAttribute.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/TimestampAttribute.cs new file mode 100644 index 0000000..9e7d654 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/TimestampAttribute.cs @@ -0,0 +1,40 @@ +/* + * 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.Binary +{ + using System; + + /// <summary> + /// Instructs the serializer to write DateTime fields and properties in Timestamp format, + /// which is interoperable with other platforms and works in SQL, + /// but does not allow non-UTC values. + /// <para /> + /// When applied to a struct or a class, changes behavior for all fields and properties. + /// <para /> + /// Normally serializer uses <see cref="IBinaryWriter.WriteObject{T}"/> for DateTime fields. + /// This attribute changes the behavior to <see cref="IBinaryWriter.WriteTimestamp"/>. + /// <para /> + /// See also <see cref="BinaryReflectiveSerializer.ForceTimestamp"/>. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | + AttributeTargets.Class | AttributeTargets.Struct)] + public class TimestampAttribute : Attribute + { + // No-op. + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/25bcd43a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs index bdcdd09..5b6e5f1 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveActions.cs @@ -106,17 +106,24 @@ namespace Apache.Ignite.Core.Impl.Binary /// <param name="writeAction">Write action.</param> /// <param name="readAction">Read action.</param> /// <param name="raw">Raw mode.</param> + /// <param name="forceTimestamp">Force timestamp serialization for DateTime fields..</param> public static void GetTypeActions(FieldInfo field, out BinaryReflectiveWriteAction writeAction, - out BinaryReflectiveReadAction readAction, bool raw) + out BinaryReflectiveReadAction readAction, bool raw, bool forceTimestamp) { + Debug.Assert(field != null); + Debug.Assert(field.DeclaringType != null); + var type = field.FieldType; + forceTimestamp = forceTimestamp || + field.DeclaringType.GetCustomAttributes(typeof(TimestampAttribute), true).Any(); + if (type.IsPrimitive) HandlePrimitive(field, out writeAction, out readAction, raw); else if (type.IsArray) HandleArray(field, out writeAction, out readAction, raw); else - HandleOther(field, out writeAction, out readAction, raw); + HandleOther(field, out writeAction, out readAction, raw, forceTimestamp); } /// <summary> @@ -400,39 +407,15 @@ namespace Apache.Ignite.Core.Impl.Binary } /// <summary> - /// Determines whether specified field is a query field (has QueryFieldAttribute). - /// </summary> - private static bool IsQueryField(FieldInfo fieldInfo) - { - Debug.Assert(fieldInfo != null && fieldInfo.DeclaringType != null); - - var fieldName = BinaryUtils.CleanFieldName(fieldInfo.Name); - - object[] attrs = null; - - if (fieldName != fieldInfo.Name) - { - // Backing field, check corresponding property - var prop = fieldInfo.DeclaringType.GetProperty(fieldName, fieldInfo.FieldType); - - if (prop != null) - attrs = prop.GetCustomAttributes(true); - } - - attrs = attrs ?? fieldInfo.GetCustomAttributes(true); - - return attrs.OfType<QuerySqlFieldAttribute>().Any(); - } - - /// <summary> /// Handle other type. /// </summary> /// <param name="field">The field.</param> /// <param name="writeAction">Write action.</param> /// <param name="readAction">Read action.</param> /// <param name="raw">Raw mode.</param> + /// <param name="forceTimestamp">Force timestamp serialization for DateTime fields..</param> private static void HandleOther(FieldInfo field, out BinaryReflectiveWriteAction writeAction, - out BinaryReflectiveReadAction readAction, bool raw) + out BinaryReflectiveReadAction readAction, bool raw, bool forceTimestamp) { var type = field.FieldType; @@ -501,18 +484,12 @@ namespace Apache.Ignite.Core.Impl.Binary ? GetRawReader(field, r => r.ReadCollection()) : GetReader(field, (f, r) => r.ReadCollection(f)); } - else if (type == typeof(DateTime) && IsQueryField(field) && !raw) + else if (type == typeof(DateTime) && IsTimestamp(field, forceTimestamp, raw)) { - // Special case for DateTime and query fields. - // If a field is marked with [QuerySqlField], write it as TimeStamp so that queries work. - // This is not needed in raw mode (queries do not work anyway). - // It may cause issues when field has attribute, but is used in a cache without queries, and user - // may expect non-UTC dates to work. However, such cases are rare, and there are workarounds. - writeAction = GetWriter<DateTime>(field, (f, w, o) => w.WriteTimestamp(f, o)); readAction = GetReader(field, (f, r) => r.ReadObject<DateTime>(f)); } - else if (nullableType == typeof(DateTime) && IsQueryField(field) && !raw) + else if (nullableType == typeof(DateTime) && IsTimestamp(field, forceTimestamp, raw)) { writeAction = GetWriter<DateTime?>(field, (f, w, o) => w.WriteTimestamp(f, o)); readAction = GetReader(field, (f, r) => r.ReadTimestamp(f)); @@ -525,6 +502,46 @@ namespace Apache.Ignite.Core.Impl.Binary } /// <summary> + /// Determines whether specified field should be written as timestamp. + /// </summary> + private static bool IsTimestamp(FieldInfo field, bool forceTimestamp, bool raw) + { + if (forceTimestamp) + { + return true; + } + + Debug.Assert(field != null && field.DeclaringType != null); + + var fieldName = BinaryUtils.CleanFieldName(field.Name); + + object[] attrs = null; + + if (fieldName != field.Name) + { + // Backing field, check corresponding property + var prop = field.DeclaringType.GetProperty(fieldName, field.FieldType); + + if (prop != null) + attrs = prop.GetCustomAttributes(true); + } + + attrs = attrs ?? field.GetCustomAttributes(true); + + if (attrs.Any(x => x is TimestampAttribute)) + { + return true; + } + + // Special case for DateTime and query fields. + // If a field is marked with [QuerySqlField], write it as TimeStamp so that queries work. + // This is not needed in raw mode (queries do not work anyway). + // It may cause issues when field has attribute, but is used in a cache without queries, and user + // may expect non-UTC dates to work. However, such cases are rare, and there are workarounds. + return !raw && attrs.Any(x => x is QuerySqlFieldAttribute); + } + + /// <summary> /// Gets the reader with a specified write action. /// </summary> private static BinaryReflectiveWriteAction GetWriter<T>(FieldInfo field, http://git-wip-us.apache.org/repos/asf/ignite/blob/25bcd43a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveSerializerInternal.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveSerializerInternal.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveSerializerInternal.cs index b179f92..69f7132 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveSerializerInternal.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReflectiveSerializerInternal.cs @@ -125,13 +125,17 @@ namespace Apache.Ignite.Core.Impl.Binary get { return true; } } - /// <summary>Register type.</summary> + /// <summary> + /// Register type. + /// </summary> /// <param name="type">Type.</param> /// <param name="typeId">Type ID.</param> /// <param name="converter">Name converter.</param> /// <param name="idMapper">ID mapper.</param> + /// <param name="forceTimestamp">Force timestamp serialization for DateTime fields..</param> + /// <returns>Resulting serializer.</returns> internal BinaryReflectiveSerializerInternal Register(Type type, int typeId, IBinaryNameMapper converter, - IBinaryIdMapper idMapper) + IBinaryIdMapper idMapper, bool forceTimestamp) { Debug.Assert(_wActions == null && _rActions == null); @@ -165,7 +169,7 @@ namespace Apache.Ignite.Core.Impl.Binary BinaryReflectiveWriteAction writeAction; BinaryReflectiveReadAction readAction; - BinaryReflectiveActions.GetTypeActions(fields[i], out writeAction, out readAction, _rawMode); + BinaryReflectiveActions.GetTypeActions(fields[i], out writeAction, out readAction, _rawMode, forceTimestamp); wActions[i] = writeAction; rActions[i] = readAction; http://git-wip-us.apache.org/repos/asf/ignite/blob/25bcd43a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs index 977251c..a2783ba 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs @@ -1670,8 +1670,10 @@ namespace Apache.Ignite.Core.Impl.Binary private static void ToJavaDate(DateTime date, out long high, out int low) { if (date.Kind != DateTimeKind.Utc) - throw new InvalidOperationException( + { + throw new BinaryObjectException( "DateTime is not UTC. Only UTC DateTime can be used for interop with other platforms."); + } long diff = date.Ticks - JavaDateTicks;