diff --git a/src/SimpleJson.Tests/DataContractTests/DataContractSampleClassess.cs b/src/SimpleJson.Tests/DataContractTests/DataContractSampleClassess.cs
index eff39e2..ae2092f 100644
--- a/src/SimpleJson.Tests/DataContractTests/DataContractSampleClassess.cs
+++ b/src/SimpleJson.Tests/DataContractTests/DataContractSampleClassess.cs
@@ -157,6 +157,26 @@ private string NoDataMember { set { } }
#endregion
#region Getter/Setters
+ [DataContract]
+ public class DataContractEmitDefaultValuePublicGetterSetters
+ {
+ public DataContractEmitDefaultValuePublicGetterSetters()
+ {
+ DataMemberWithoutName = "dmv";
+ DatMemberWithName = "dmnv";
+ }
+
+ [DataMember]
+ public string DataMemberWithoutName { get; set; }
+
+ [DataMember(Name = "name", EmitDefaultValue = false)]
+ public string DatMemberWithName { get; set; }
+
+ [IgnoreDataMember]
+ public string IgnoreDataMember { get; set; }
+
+ public string NoDataMember { get; set; }
+ }
[DataContract]
public class DataContractPublicGetterSetters
diff --git a/src/SimpleJson.Tests/DataContractTests/EmitDefaultValueSerializeTests.cs b/src/SimpleJson.Tests/DataContractTests/EmitDefaultValueSerializeTests.cs
new file mode 100644
index 0000000..fe92ea8
--- /dev/null
+++ b/src/SimpleJson.Tests/DataContractTests/EmitDefaultValueSerializeTests.cs
@@ -0,0 +1,74 @@
+//-----------------------------------------------------------------------
+//
+// Copyright (c) 2011, The Outercurve Foundation.
+//
+// Licensed under the MIT License (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.opensource.org/licenses/mit-license.php
+//
+// 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.
+//
+// Nathan Totten (ntotten.com), Jim Zimmerman (jimzimmerman.com) and Prabir Shrestha (prabir.me)
+// https://github.com/facebook-csharp-sdk/simple-json
+//-----------------------------------------------------------------------
+
+namespace SimpleJsonTests.DataContractTests
+{
+#if NUNIT
+ using TestClass = NUnit.Framework.TestFixtureAttribute;
+ using TestMethod = NUnit.Framework.TestAttribute;
+ using TestCleanup = NUnit.Framework.TearDownAttribute;
+ using TestInitialize = NUnit.Framework.SetUpAttribute;
+ using ClassCleanup = NUnit.Framework.TestFixtureTearDownAttribute;
+ using ClassInitialize = NUnit.Framework.TestFixtureSetUpAttribute;
+ using NUnit.Framework;
+#else
+#if NETFX_CORE
+ using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
+#else
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+#endif
+#endif
+
+ using SimpleJson;
+
+ [TestClass]
+ public class EmitDefaultValueSerializeTests
+ {
+ private DataContractEmitDefaultValuePublicGetterSetters _dataContractEmitDefaultValuePublicGetterSetters;
+
+ public EmitDefaultValueSerializeTests()
+ {
+ _dataContractEmitDefaultValuePublicGetterSetters = new DataContractEmitDefaultValuePublicGetterSetters();
+ }
+
+ [TestMethod]
+ public void SerializesCorrectlyWithDefaultValue()
+ {
+ _dataContractEmitDefaultValuePublicGetterSetters.DatMemberWithName = null;
+ var result = SimpleJson.SerializeObject(_dataContractEmitDefaultValuePublicGetterSetters, SimpleJson.DataContractJsonSerializerStrategy);
+
+ // As the property has a DataMemberAttribute and EmitDefaultValue = false, and the value is false
+ // there should be a name property in there. (The case is important here)
+ Assert.IsFalse(result.Contains("name"));
+ Assert.IsTrue(result.Contains("DataMemberWithoutName"));
+ }
+
+ [TestMethod]
+ public void SerializesCorrectlyWithoutDefaultValue()
+ {
+ _dataContractEmitDefaultValuePublicGetterSetters.DatMemberWithName = "SimpleJson";
+ var result = SimpleJson.SerializeObject(_dataContractEmitDefaultValuePublicGetterSetters, SimpleJson.DataContractJsonSerializerStrategy);
+
+ // As the property has a DataMemberAttribute and EmitDefaultValue = false, and the value is false
+ // there should be a name property in there. (The case is important here)
+ Assert.IsTrue(result.Contains("SimpleJson"));
+ Assert.IsTrue(result.Contains("DataMemberWithoutName"));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/SimpleJson.Tests/SimpleJson.Tests.csproj b/src/SimpleJson.Tests/SimpleJson.Tests.csproj
index eafe9c8..5fb663f 100644
--- a/src/SimpleJson.Tests/SimpleJson.Tests.csproj
+++ b/src/SimpleJson.Tests/SimpleJson.Tests.csproj
@@ -52,6 +52,7 @@
+
diff --git a/src/SimpleJson/SimpleJson.cs b/src/SimpleJson/SimpleJson.cs
index 2ab9742..26c704e 100644
--- a/src/SimpleJson/SimpleJson.cs
+++ b/src/SimpleJson/SimpleJson.cs
@@ -1244,9 +1244,12 @@ interface IJsonSerializerStrategy
#endif
class PocoJsonSerializerStrategy : IJsonSerializerStrategy
{
+ public delegate bool EmitPredicate(object value);
+
internal IDictionary ConstructorCache;
internal IDictionary> GetCache;
internal IDictionary>> SetCache;
+ protected internal IDictionary> EmitPredicateCache;
internal static readonly Type[] EmptyTypes = new Type[0];
internal static readonly Type[] ArrayConstructorParameterTypes = new Type[] { typeof(int) };
@@ -1270,6 +1273,11 @@ protected virtual string MapClrMemberNameToJsonFieldName(string clrPropertyName)
return clrPropertyName;
}
+ internal virtual IDictionary EmitPredicateFactory(Type type)
+ {
+ return null;
+ }
+
internal virtual ReflectionUtils.ConstructorDelegate ContructorDelegateFactory(Type key)
{
return ReflectionUtils.GetContructor(key, key.IsArray ? ArrayConstructorParameterTypes : EmptyTypes);
@@ -1504,10 +1512,21 @@ protected virtual bool TrySerializeUnknownTypes(object input, out object output)
return false;
IDictionary obj = new JsonObject();
IDictionary getters = GetCache[type];
+ IDictionary emitPredicate = EmitPredicateCache == null ? null : EmitPredicateCache[type];
foreach (KeyValuePair getter in getters)
{
if (getter.Value != null)
- obj.Add(MapClrMemberNameToJsonFieldName(getter.Key), getter.Value(input));
+ {
+ object value = getter.Value(input);
+ if (emitPredicate != null && emitPredicate.ContainsKey(getter.Key) == true)
+ {
+ if (!emitPredicate[getter.Key](value))
+ {
+ continue;
+ }
+ }
+ obj.Add(MapClrMemberNameToJsonFieldName(getter.Key), value);
+ }
}
output = obj;
return true;
@@ -1527,28 +1546,95 @@ public DataContractJsonSerializerStrategy()
{
GetCache = new ReflectionUtils.ThreadSafeDictionary>(GetterValueFactory);
SetCache = new ReflectionUtils.ThreadSafeDictionary>>(SetterValueFactory);
+ EmitPredicateCache = new ReflectionUtils.ThreadSafeDictionary>(EmitPredicateFactory);
+ }
+
+ ///
+ /// Helper method to supply the name of the json key, either from the DataMemberAttribute or from the MemberInfo
+ ///
+ /// DataMemberAttribute
+ ///
+ /// string with the name in the Json
+ private string JsonKey(DataMemberAttribute dataMemberAttribute, MemberInfo memberInfo)
+ {
+ return string.IsNullOrEmpty(dataMemberAttribute.Name) ? memberInfo.Name : dataMemberAttribute.Name;
+ }
+
+ ///
+ /// Create a default value for a type, this usually is "null" for reference type, but for other, e.g. bool it's false or for int it's 0
+ ///
+ /// Type to create a default for
+ /// Default for type
+ private static object Default(Type type)
+ {
+#if SIMPLE_JSON_TYPEINFO
+ if (type.GetTypeInfo().IsValueType)
+#else
+ if (type.IsValueType)
+#endif
+ {
+ return Activator.CreateInstance(type);
+ }
+
+ return null;
+ }
+
+ ///
+ /// Generate a cache with predicates which decides if the value needs to be emitted
+ /// Would have been nicer to integrate it into the getter, but this would mean more changes
+ ///
+ ///
+ internal override IDictionary EmitPredicateFactory(Type type)
+ {
+ IDictionary result = new Dictionary();
+ DataContractAttribute dataContractAttribute = (DataContractAttribute)ReflectionUtils.GetAttribute(type, typeof(DataContractAttribute));
+ if (dataContractAttribute == null) {
+ return result;
+ }
+ foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type))
+ {
+ DataMemberAttribute dataMemberAttribute;
+ if (CanAdd(propertyInfo, out dataMemberAttribute))
+ {
+ string jsonKey = JsonKey(dataMemberAttribute, propertyInfo);
+ if (dataMemberAttribute != null && dataMemberAttribute.EmitDefaultValue == false)
+ {
+ object def = Default(propertyInfo.PropertyType);
+ result[jsonKey] = delegate(object value) { return !Equals(def, value); };
+ }
+ }
+ }
+ return result;
}
internal override IDictionary GetterValueFactory(Type type)
{
- bool hasDataContract = ReflectionUtils.GetAttribute(type, typeof(DataContractAttribute)) != null;
- if (!hasDataContract)
+ DataContractAttribute dataContractAttribute = (DataContractAttribute)ReflectionUtils.GetAttribute(type, typeof(DataContractAttribute));
+ if (dataContractAttribute == null)
return base.GetterValueFactory(type);
+
string jsonKey;
+ DataMemberAttribute dataMemberAttribute;
IDictionary result = new Dictionary();
foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type))
{
if (propertyInfo.CanRead)
{
MethodInfo getMethod = ReflectionUtils.GetGetterMethodInfo(propertyInfo);
- if (!getMethod.IsStatic && CanAdd(propertyInfo, out jsonKey))
+ if (!getMethod.IsStatic && CanAdd(propertyInfo, out dataMemberAttribute))
+ {
+ jsonKey = string.IsNullOrEmpty(dataMemberAttribute.Name) ? propertyInfo.Name : dataMemberAttribute.Name;
result[jsonKey] = ReflectionUtils.GetGetMethod(propertyInfo);
+ }
}
}
foreach (FieldInfo fieldInfo in ReflectionUtils.GetFields(type))
{
- if (!fieldInfo.IsStatic && CanAdd(fieldInfo, out jsonKey))
+ if (!fieldInfo.IsStatic && CanAdd(fieldInfo, out dataMemberAttribute))
+ {
+ jsonKey = string.IsNullOrEmpty(dataMemberAttribute.Name) ? fieldInfo.Name : dataMemberAttribute.Name;
result[jsonKey] = ReflectionUtils.GetGetMethod(fieldInfo);
+ }
}
return result;
}
@@ -1559,34 +1645,41 @@ public DataContractJsonSerializerStrategy()
if (!hasDataContract)
return base.SetterValueFactory(type);
string jsonKey;
+ DataMemberAttribute dataMemberAttribute;
IDictionary> result = new Dictionary>();
foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type))
{
if (propertyInfo.CanWrite)
{
MethodInfo setMethod = ReflectionUtils.GetSetterMethodInfo(propertyInfo);
- if (!setMethod.IsStatic && CanAdd(propertyInfo, out jsonKey))
+ if (!setMethod.IsStatic && CanAdd(propertyInfo, out dataMemberAttribute))
+ {
+ jsonKey = string.IsNullOrEmpty(dataMemberAttribute.Name) ? propertyInfo.Name : dataMemberAttribute.Name;
result[jsonKey] = new KeyValuePair(propertyInfo.PropertyType, ReflectionUtils.GetSetMethod(propertyInfo));
+ }
}
}
foreach (FieldInfo fieldInfo in ReflectionUtils.GetFields(type))
{
- if (!fieldInfo.IsInitOnly && !fieldInfo.IsStatic && CanAdd(fieldInfo, out jsonKey))
+ if (!fieldInfo.IsInitOnly && !fieldInfo.IsStatic && CanAdd(fieldInfo, out dataMemberAttribute))
+ {
+ jsonKey = string.IsNullOrEmpty(dataMemberAttribute.Name) ? fieldInfo.Name : dataMemberAttribute.Name;
result[jsonKey] = new KeyValuePair(fieldInfo.FieldType, ReflectionUtils.GetSetMethod(fieldInfo));
+ }
}
// todo implement sorting for DATACONTRACT.
return result;
}
- private static bool CanAdd(MemberInfo info, out string jsonKey)
+ private static bool CanAdd(MemberInfo info, out DataMemberAttribute dataMemberAttribute)
{
- jsonKey = null;
+ dataMemberAttribute = null;
+
if (ReflectionUtils.GetAttribute(info, typeof(IgnoreDataMemberAttribute)) != null)
return false;
- DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)ReflectionUtils.GetAttribute(info, typeof(DataMemberAttribute));
+ dataMemberAttribute = (DataMemberAttribute)ReflectionUtils.GetAttribute(info, typeof(DataMemberAttribute));
if (dataMemberAttribute == null)
return false;
- jsonKey = string.IsNullOrEmpty(dataMemberAttribute.Name) ? info.Name : dataMemberAttribute.Name;
return true;
}
}