You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2017/05/18 08:54:25 UTC
[07/17] ignite git commit: IGNITE-4406 .NET: Control DateTime
serialization via attribute
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 <pt...@apache.org>
Authored: Thu May 18 10:39:16 2017 +0300
Committer: Pavel Tupitsyn <pt...@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;