diff --git a/src/Json.Schema.ToDotNet.UnitTests/DataModelGeneratorTests.cs b/src/Json.Schema.ToDotNet.UnitTests/DataModelGeneratorTests.cs
index 9a702e0b..b7c4104c 100644
--- a/src/Json.Schema.ToDotNet.UnitTests/DataModelGeneratorTests.cs
+++ b/src/Json.Schema.ToDotNet.UnitTests/DataModelGeneratorTests.cs
@@ -871,10 +871,43 @@ public void GeneratesCloningCode()
""type"": ""integer"",
""description"": ""An integer property.""
},
+ ""intPropWithDefault"": {
+ ""type"": ""integer"",
+ ""description"": ""An integer property with a default value."",
+ ""default"": 42
+ },
+ ""numberProp"": {
+ ""type"": ""number"",
+ ""description"": ""A number property.""
+ },
+ ""numberPropWithDefault"": {
+ ""type"": ""number"",
+ ""description"": ""A number property with a default value."",
+ ""default"": 42.1
+ },
""stringProp"": {
""type"": ""string"",
""description"": ""A string property.""
},
+ ""stringPropWithDefault"": {
+ ""type"": ""string"",
+ ""description"": ""A string property with a default value."",
+ ""default"": ""42""
+ },
+ ""boolProp"": {
+ ""type"": ""boolean"",
+ ""description"": ""A Boolean property.""
+ },
+ ""boolPropWithTrueDefault"": {
+ ""type"": ""boolean"",
+ ""description"": ""A Boolean property with a true default value."",
+ ""default"": true
+ },
+ ""boolPropWithFalseDefault"": {
+ ""type"": ""boolean"",
+ ""description"": ""A Boolean property with a false default value."",
+ ""default"": false
+ },
""arrayProp"": {
""type"": ""array"",
""description"": ""An array property."",
@@ -1006,6 +1039,7 @@ public void GeneratesCloningCode()
@"using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Runtime.Serialization;
namespace N
@@ -1031,12 +1065,59 @@ public SNodeKind SNodeKind
[DataMember(Name = ""intProp"", IsRequired = false, EmitDefaultValue = false)]
public int IntProp { get; set; }
+ ///
+ /// An integer property with a default value.
+ ///
+ [DataMember(Name = ""intPropWithDefault"", IsRequired = false, EmitDefaultValue = false)]
+ [DefaultValue(42)]
+ public int IntPropWithDefault { get; set; }
+
+ ///
+ /// A number property.
+ ///
+ [DataMember(Name = ""numberProp"", IsRequired = false, EmitDefaultValue = false)]
+ public double NumberProp { get; set; }
+
+ ///
+ /// A number property with a default value.
+ ///
+ [DataMember(Name = ""numberPropWithDefault"", IsRequired = false, EmitDefaultValue = false)]
+ [DefaultValue(42.1)]
+ public double NumberPropWithDefault { get; set; }
+
///
/// A string property.
///
[DataMember(Name = ""stringProp"", IsRequired = false, EmitDefaultValue = false)]
public string StringProp { get; set; }
+ ///
+ /// A string property with a default value.
+ ///
+ [DataMember(Name = ""stringPropWithDefault"", IsRequired = false, EmitDefaultValue = false)]
+ [DefaultValue(""42"")]
+ public string StringPropWithDefault { get; set; }
+
+ ///
+ /// A Boolean property.
+ ///
+ [DataMember(Name = ""boolProp"", IsRequired = false, EmitDefaultValue = false)]
+ public bool BoolProp { get; set; }
+
+ ///
+ /// A Boolean property with a true default value.
+ ///
+ [DataMember(Name = ""boolPropWithTrueDefault"", IsRequired = false, EmitDefaultValue = false)]
+ [DefaultValue(true)]
+ public bool BoolPropWithTrueDefault { get; set; }
+
+ ///
+ /// A Boolean property with a false default value.
+ ///
+ [DataMember(Name = ""boolPropWithFalseDefault"", IsRequired = false, EmitDefaultValue = false)]
+ [DefaultValue(false)]
+ public bool BoolPropWithFalseDefault { get; set; }
+
///
/// An array property.
///
@@ -1110,56 +1191,82 @@ public SNodeKind SNodeKind
///
public C()
{
+ IntPropWithDefault = 42;
+ NumberPropWithDefault = 42.1;
+ StringPropWithDefault = ""42"";
+ BoolPropWithTrueDefault = true;
+ BoolPropWithFalseDefault = false;
}
///
/// Initializes a new instance of the class from the supplied values.
///
///
- /// An initialization value for the property.
+ /// An initialization value for the property.
+ ///
+ ///
+ /// An initialization value for the property.
+ ///
+ ///
+ /// An initialization value for the property.
+ ///
+ ///
+ /// An initialization value for the property.
///
///
- /// An initialization value for the property.
+ /// An initialization value for the property.
+ ///
+ ///
+ /// An initialization value for the property.
+ ///
+ ///
+ /// An initialization value for the property.
+ ///
+ ///
+ /// An initialization value for the property.
+ ///
+ ///
+ /// An initialization value for the property.
///
///
- /// An initialization value for the property.
+ /// An initialization value for the property.
///
///
- /// An initialization value for the property.
+ /// An initialization value for the property.
///
///
- /// An initialization value for the property.
+ /// An initialization value for the property.
///
///
- /// An initialization value for the property.
+ /// An initialization value for the property.
///
///
- /// An initialization value for the property.
+ /// An initialization value for the property.
///
///
- /// An initialization value for the property.
+ /// An initialization value for the property.
///
///
- /// An initialization value for the property.
+ /// An initialization value for the property.
///
///
- /// An initialization value for the property.
+ /// An initialization value for the property.
///
///
- /// An initialization value for the property.
+ /// An initialization value for the property.
///
///
- /// An initialization value for the property.
+ /// An initialization value for the property.
///
///
- /// An initialization value for the property.
+ /// An initialization value for the property.
///
///
- /// An initialization value for the property.
+ /// An initialization value for the property.
///
- public C(int intProp, string stringProp, IEnumerable arrayProp, Uri uriProp, DateTime dateTimeProp, D referencedTypeProp, IEnumerable arrayOfRefProp, IEnumerable> arrayOfArrayProp, IDictionary dictionaryProp, IDictionary dictionaryWithPrimitiveSchemaProp, IDictionary dictionaryWithObjectSchemaProp, IDictionary> dictionaryWithObjectArraySchemaProp, IDictionary dictionaryWithUriKeyProp, IDictionary dictionaryWithHintedValueProp)
+ public C(int intProp, int intPropWithDefault, double numberProp, double numberPropWithDefault, string stringProp, string stringPropWithDefault, bool boolProp, bool boolPropWithTrueDefault, bool boolPropWithFalseDefault, IEnumerable arrayProp, Uri uriProp, DateTime dateTimeProp, D referencedTypeProp, IEnumerable arrayOfRefProp, IEnumerable> arrayOfArrayProp, IDictionary dictionaryProp, IDictionary dictionaryWithPrimitiveSchemaProp, IDictionary dictionaryWithObjectSchemaProp, IDictionary> dictionaryWithObjectArraySchemaProp, IDictionary dictionaryWithUriKeyProp, IDictionary dictionaryWithHintedValueProp)
{
- Init(intProp, stringProp, arrayProp, uriProp, dateTimeProp, referencedTypeProp, arrayOfRefProp, arrayOfArrayProp, dictionaryProp, dictionaryWithPrimitiveSchemaProp, dictionaryWithObjectSchemaProp, dictionaryWithObjectArraySchemaProp, dictionaryWithUriKeyProp, dictionaryWithHintedValueProp);
+ Init(intProp, intPropWithDefault, numberProp, numberPropWithDefault, stringProp, stringPropWithDefault, boolProp, boolPropWithTrueDefault, boolPropWithFalseDefault, arrayProp, uriProp, dateTimeProp, referencedTypeProp, arrayOfRefProp, arrayOfArrayProp, dictionaryProp, dictionaryWithPrimitiveSchemaProp, dictionaryWithObjectSchemaProp, dictionaryWithObjectArraySchemaProp, dictionaryWithUriKeyProp, dictionaryWithHintedValueProp);
}
///
@@ -1178,7 +1285,7 @@ public C(C other)
throw new ArgumentNullException(nameof(other));
}
- Init(other.IntProp, other.StringProp, other.ArrayProp, other.UriProp, other.DateTimeProp, other.ReferencedTypeProp, other.ArrayOfRefProp, other.ArrayOfArrayProp, other.DictionaryProp, other.DictionaryWithPrimitiveSchemaProp, other.DictionaryWithObjectSchemaProp, other.DictionaryWithObjectArraySchemaProp, other.DictionaryWithUriKeyProp, other.DictionaryWithHintedValueProp);
+ Init(other.IntProp, other.IntPropWithDefault, other.NumberProp, other.NumberPropWithDefault, other.StringProp, other.StringPropWithDefault, other.BoolProp, other.BoolPropWithTrueDefault, other.BoolPropWithFalseDefault, other.ArrayProp, other.UriProp, other.DateTimeProp, other.ReferencedTypeProp, other.ArrayOfRefProp, other.ArrayOfArrayProp, other.DictionaryProp, other.DictionaryWithPrimitiveSchemaProp, other.DictionaryWithObjectSchemaProp, other.DictionaryWithObjectArraySchemaProp, other.DictionaryWithUriKeyProp, other.DictionaryWithHintedValueProp);
}
ISNode ISNode.DeepClone()
@@ -1199,10 +1306,17 @@ private ISNode DeepCloneCore()
return new C(this);
}
- private void Init(int intProp, string stringProp, IEnumerable arrayProp, Uri uriProp, DateTime dateTimeProp, D referencedTypeProp, IEnumerable arrayOfRefProp, IEnumerable> arrayOfArrayProp, IDictionary dictionaryProp, IDictionary dictionaryWithPrimitiveSchemaProp, IDictionary dictionaryWithObjectSchemaProp, IDictionary> dictionaryWithObjectArraySchemaProp, IDictionary dictionaryWithUriKeyProp, IDictionary dictionaryWithHintedValueProp)
+ private void Init(int intProp, int intPropWithDefault, double numberProp, double numberPropWithDefault, string stringProp, string stringPropWithDefault, bool boolProp, bool boolPropWithTrueDefault, bool boolPropWithFalseDefault, IEnumerable arrayProp, Uri uriProp, DateTime dateTimeProp, D referencedTypeProp, IEnumerable arrayOfRefProp, IEnumerable> arrayOfArrayProp, IDictionary dictionaryProp, IDictionary dictionaryWithPrimitiveSchemaProp, IDictionary dictionaryWithObjectSchemaProp, IDictionary> dictionaryWithObjectArraySchemaProp, IDictionary dictionaryWithUriKeyProp, IDictionary dictionaryWithHintedValueProp)
{
IntProp = intProp;
+ IntPropWithDefault = intPropWithDefault;
+ NumberProp = numberProp;
+ NumberPropWithDefault = numberPropWithDefault;
StringProp = stringProp;
+ StringPropWithDefault = stringPropWithDefault;
+ BoolProp = boolProp;
+ BoolPropWithTrueDefault = boolPropWithTrueDefault;
+ BoolPropWithFalseDefault = boolPropWithFalseDefault;
if (arrayProp != null)
{
var destination_0 = new List();
@@ -2450,7 +2564,7 @@ public C()
/// Initializes a new instance of the class from the supplied values.
///
///
- /// An initialization value for the property.
+ /// An initialization value for the property.
///
public C(IEnumerable uriFormattedStrings)
{
diff --git a/src/Json.Schema.ToDotNet/ClassGenerator.cs b/src/Json.Schema.ToDotNet/ClassGenerator.cs
index 8d209405..e67590f3 100644
--- a/src/Json.Schema.ToDotNet/ClassGenerator.cs
+++ b/src/Json.Schema.ToDotNet/ClassGenerator.cs
@@ -27,6 +27,9 @@ public class ClassGenerator : ClassOrInterfaceGenerator
// Name used for the parameters of the copy ctor.
private const string OtherParameterName = "other";
+ private const string DefaultValueAttributeNamespaceName = "System.ComponentModel";
+ private const string DefaultValueAttributeName = "DefaultValue";
+
private const string DataContractAttributeName = "DataContract";
private const string DataMemberAttributeName = "DataMember";
private const string DataMemberNamePropertyName = "Name";
@@ -241,7 +244,7 @@ private MemberDeclarationSyntax GenerateValueGetHashCodeMethod()
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
}
- protected override AttributeSyntax[] GeneratePropertyAttributes(string propertyName, string serializedName, bool isRequired)
+ protected override AttributeSyntax[] GeneratePropertyAttributes(string propertyName, string serializedName, bool isRequired, object defaultValue)
{
var attributes = new List();
@@ -279,6 +282,24 @@ protected override AttributeSyntax[] GeneratePropertyAttributes(string propertyN
attributes.Add(dataMemberAttribute);
+ if (defaultValue != null)
+ {
+ AddUsing(DefaultValueAttributeNamespaceName);
+
+ var defaultValueArguments = new List
+ {
+ SyntaxFactory.AttributeArgument(GetLiteralExpressionForValue(defaultValue))
+ };
+
+ AttributeSyntax defaultValueAttribute =
+ SyntaxFactory.Attribute(
+ SyntaxFactory.IdentifierName(DefaultValueAttributeName),
+ SyntaxFactory.AttributeArgumentList(
+ SyntaxFactory.SeparatedList(defaultValueArguments)));
+
+ attributes.Add(defaultValueAttribute);
+ }
+
string hintDictionaryKey = MakeHintDictionaryKey(propertyName);
AttributeHint[] attributeHints = HintDictionary?.GetHints(hintDictionaryKey);
if (attributeHints != null)
@@ -372,7 +393,7 @@ private ConstructorDeclarationSyntax GenerateDefaultConstructor()
{
return SyntaxFactory.ConstructorDeclaration(SuffixedTypeName)
.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
- .AddBodyStatements()
+ .AddBodyStatements(GenerateDefaultInitializations())
.WithLeadingTrivia(
SyntaxHelper.MakeDocComment(
string.Format(
@@ -381,6 +402,95 @@ private ConstructorDeclarationSyntax GenerateDefaultConstructor()
SuffixedTypeName)));
}
+ ///
+ /// Generates an initialization statement for each property for which the
+ /// schema specifies a default value.
+ ///
+ ///
+ /// The resulting statements are inserted into the default constructor.
+ /// This ensures that the default values are set even if the object is
+ /// not the result of deserializing a JSON instance document.
+ ///
+ ///
+ /// An array containing one initialization statement for each property
+ /// for which the schema specifies a default value.
+ ///
+ private ExpressionStatementSyntax[] GenerateDefaultInitializations()
+ {
+ var initializations = new List();
+
+ foreach (string propertyName in PropInfoDictionary.GetPropertyNames())
+ {
+ if (IncludeProperty(propertyName))
+ {
+ PropertyInfo propInfo = PropInfoDictionary[propertyName];
+ object defaultValue = propInfo.DefaultValue;
+
+ ExpressionStatementSyntax initializationStatement = GenerateDefaultInitialization(propertyName, defaultValue);
+ if (initializationStatement != null)
+ {
+ initializations.Add(initializationStatement);
+ }
+ }
+ }
+
+ return initializations.ToArray();
+ }
+
+ private ExpressionStatementSyntax GenerateDefaultInitialization(
+ string propertyName,
+ object defaultValue)
+ {
+ LiteralExpressionSyntax defaultValueExpression = GetLiteralExpressionForValue(defaultValue);
+ if (defaultValueExpression == null) { return null; }
+
+ return SyntaxFactory.ExpressionStatement(
+ SyntaxFactory.AssignmentExpression(
+ SyntaxKind.SimpleAssignmentExpression,
+ SyntaxFactory.IdentifierName(propertyName),
+ defaultValueExpression));
+ }
+
+ private LiteralExpressionSyntax GetLiteralExpressionForValue(object value)
+ {
+ LiteralExpressionSyntax literalExpression = null;
+
+ if (value is bool)
+ {
+ SyntaxKind literalSyntaxKind = (bool)value == true
+ ? SyntaxKind.TrueLiteralExpression
+ : SyntaxKind.FalseLiteralExpression;
+
+ literalExpression = SyntaxFactory.LiteralExpression(literalSyntaxKind);
+ }
+ else if (value is long)
+ {
+ literalExpression = SyntaxFactory.LiteralExpression(
+ SyntaxKind.NumericLiteralExpression,
+ SyntaxFactory.Literal((int)(long)value));
+ // Note: the extra cast compensates for a mismatch between our code generation
+ // and Newtonsoft.Json's deserialization behavior. Newtonsoft deserializes
+ // integer properties as Int64 (long), but we generate integer properties
+ // with type int. The extra cast causes Roslyn to emit the literal 42,
+ // which can be assigned to an int, rather than 42L, which cannot. We should
+ // consider changing the code generation to emit longs for integer properties.
+ }
+ else if (value is double)
+ {
+ literalExpression = SyntaxFactory.LiteralExpression(
+ SyntaxKind.NumericLiteralExpression,
+ SyntaxFactory.Literal((double)value));
+ }
+ else if (value is string)
+ {
+ literalExpression = SyntaxFactory.LiteralExpression(
+ SyntaxKind.StringLiteralExpression,
+ SyntaxFactory.Literal((string)value));
+ }
+
+ return literalExpression;
+ }
+
private ConstructorDeclarationSyntax GeneratePropertyCtor()
{
// Generate the argument list that will be passed from the copy ctor to the
diff --git a/src/Json.Schema.ToDotNet/ClassOrInterfaceGenerator.cs b/src/Json.Schema.ToDotNet/ClassOrInterfaceGenerator.cs
index 43733be4..5312eee7 100644
--- a/src/Json.Schema.ToDotNet/ClassOrInterfaceGenerator.cs
+++ b/src/Json.Schema.ToDotNet/ClassOrInterfaceGenerator.cs
@@ -25,7 +25,7 @@ public ClassOrInterfaceGenerator(
PropInfoDictionary = propertyInfoDictionary;
}
- protected abstract AttributeSyntax[] GeneratePropertyAttributes(string propertyName, string serializedName, bool isRequired);
+ protected abstract AttributeSyntax[] GeneratePropertyAttributes(string propertyName, string serializedName, bool isRequired, object defaultValue);
protected abstract SyntaxToken[] GeneratePropertyModifiers(string propertyName);
@@ -103,7 +103,7 @@ private PropertyDeclarationSyntax CreatePropertyDeclaration(string propertyName)
.AddModifiers(GeneratePropertyModifiers(propertyName))
.AddAccessorListAccessors(GeneratePropertyAccessors());
- AttributeSyntax[] attributes = GeneratePropertyAttributes(propertyName, info.SerializedName, info.IsRequired);
+ AttributeSyntax[] attributes = GeneratePropertyAttributes(propertyName, info.SerializedName, info.IsRequired, info.DefaultValue);
if (attributes.Length > 0)
{
propDecl = propDecl.AddAttributeLists(attributes
diff --git a/src/Json.Schema.ToDotNet/EqualityComparerGenerator.cs b/src/Json.Schema.ToDotNet/EqualityComparerGenerator.cs
index 08253b43..842cb174 100644
--- a/src/Json.Schema.ToDotNet/EqualityComparerGenerator.cs
+++ b/src/Json.Schema.ToDotNet/EqualityComparerGenerator.cs
@@ -111,16 +111,20 @@ internal string Generate(string className, PropertyInfoDictionary propertyInfoDi
GenerateEqualsMethod(),
GenerateGetHashCodeMethod());
- var usings = new List
+ var usings = new HashSet
{
"System", // For Object.
"System.Collections.Generic" // For IEqualityComparer
};
- usings.AddRange(_propertyInfoDictionary
+ IEnumerable namespaceNames = _propertyInfoDictionary
.Values
.Select(propertyInfo => propertyInfo.NamespaceName)
- .Where(namespaceName => !string.IsNullOrWhiteSpace(namespaceName)));
+ .Where(namespaceName => !string.IsNullOrWhiteSpace(namespaceName));
+ foreach (string namespaceName in namespaceNames)
+ {
+ usings.Add(namespaceName);
+ }
return classDeclaration.Format(
_copyrightNotice,
diff --git a/src/Json.Schema.ToDotNet/InterfaceGenerator.cs b/src/Json.Schema.ToDotNet/InterfaceGenerator.cs
index 589ffbf4..7a3e5814 100644
--- a/src/Json.Schema.ToDotNet/InterfaceGenerator.cs
+++ b/src/Json.Schema.ToDotNet/InterfaceGenerator.cs
@@ -41,7 +41,7 @@ public override void AddMembers()
.AddMembers(GenerateProperties());
}
- protected override AttributeSyntax[] GeneratePropertyAttributes(string propertyName, string serializedName, bool isRequired)
+ protected override AttributeSyntax[] GeneratePropertyAttributes(string propertyName, string serializedName, bool isRequired, object defaultValue)
{
return new AttributeSyntax[0];
}
diff --git a/src/Json.Schema.ToDotNet/Json.Schema.ToDotNet.csproj b/src/Json.Schema.ToDotNet/Json.Schema.ToDotNet.csproj
index 0ff38bee..8d6dc6b8 100644
--- a/src/Json.Schema.ToDotNet/Json.Schema.ToDotNet.csproj
+++ b/src/Json.Schema.ToDotNet/Json.Schema.ToDotNet.csproj
@@ -16,6 +16,21 @@
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
diff --git a/src/Json.Schema.ToDotNet/PropertyInfo.cs b/src/Json.Schema.ToDotNet/PropertyInfo.cs
index 1ab0e617..e67ccb07 100644
--- a/src/Json.Schema.ToDotNet/PropertyInfo.cs
+++ b/src/Json.Schema.ToDotNet/PropertyInfo.cs
@@ -42,6 +42,9 @@ public class PropertyInfo
/// true
if this property is required by the schema;
/// otherwise false
.
///
+ ///
+ /// The default value, if any, specified by the schema; otherwise null
.
+ ///
///
/// true
if this property is of a type defined by the schema (or an;
/// array of a schema-defined type otherwise false
.
@@ -61,6 +64,7 @@ public PropertyInfo(
TypeSyntax type,
string namespaceName,
bool isRequired,
+ object defaultValue,
bool isOfSchemaDefinedType,
int arrayRank,
int declarationOrder)
@@ -74,6 +78,7 @@ public PropertyInfo(
TypeName = type.ToString();
NamespaceName = namespaceName;
IsRequired = isRequired;
+ DefaultValue = defaultValue;
IsOfSchemaDefinedType = isOfSchemaDefinedType;
ArrayRank = arrayRank;
DeclarationOrder = declarationOrder;
@@ -131,6 +136,11 @@ public PropertyInfo(
///
public bool IsRequired { get; }
+ ///
+ /// Gets this property's default value, if the schema specifies one; otherwise null
.
+ ///
+ public object DefaultValue;
+
///
/// Gets a value indicating whether this property is of a type defined by the schema.
///
diff --git a/src/Json.Schema.ToDotNet/PropertyInfoDictionary.cs b/src/Json.Schema.ToDotNet/PropertyInfoDictionary.cs
index aa98e83f..cf74dcf5 100644
--- a/src/Json.Schema.ToDotNet/PropertyInfoDictionary.cs
+++ b/src/Json.Schema.ToDotNet/PropertyInfoDictionary.cs
@@ -10,7 +10,6 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.Json.Schema.ToDotNet.Hints;
-using Newtonsoft.Json.Linq;
namespace Microsoft.Json.Schema.ToDotNet
{
@@ -57,8 +56,8 @@ public class PropertyInfoDictionary : IReadOnlyDictionary
///
public delegate void AdditionalTypeRequiredDelegate(AdditionalTypeRequiredInfo additionalTypeRequiredInfo);
- private AdditionalTypeRequiredDelegate _additionalTypeRequiredDelegate;
- private string _typeNameSuffix;
+ private readonly AdditionalTypeRequiredDelegate _additionalTypeRequiredDelegate;
+ private readonly string _typeNameSuffix;
///
/// Initializes a new instance of the class.
@@ -143,8 +142,7 @@ public static string MakeDictionaryItemKeyName(string propertyName)
public static SyntaxKind GetTypeKeywordFromSchemaType(SchemaType type)
{
- SyntaxKind typeKeyword;
- if (!s_SchemaTypeToSyntaxKindDictionary.TryGetValue(type, out typeKeyword))
+ if (!s_SchemaTypeToSyntaxKindDictionary.TryGetValue(type, out SyntaxKind typeKeyword))
{
typeKeyword = SyntaxKind.ObjectKeyword;
}
@@ -158,8 +156,7 @@ public PropertyInfo this[string key]
{
get
{
- PropertyInfo info;
- if (!TryGetValue(key, out info))
+ if (!TryGetValue(key, out PropertyInfo info))
{
throw new ApplicationException($"The schema does not contain information describing the property or element {key}.");
}
@@ -229,8 +226,6 @@ private void AddPropertyInfoFromPropertySchema(
string referencedEnumTypeName;
bool isOfSchemaDefinedType = false;
int arrayRank = 0;
- EnumHint enumHint;
- DictionaryHint dictionaryHint;
if (propertySchema.IsDateTime())
{
@@ -246,7 +241,7 @@ private void AddPropertyInfoFromPropertySchema(
initializationKind = InitializationKind.Uri;
type = MakeNamedType("System.Uri", out namespaceName);
}
- else if (propertySchema.ShouldBeDictionary(_typeName, schemaPropertyName, _hintDictionary, out dictionaryHint))
+ else if (propertySchema.ShouldBeDictionary(_typeName, schemaPropertyName, _hintDictionary, out DictionaryHint dictionaryHint))
{
comparisonKind = ComparisonKind.Dictionary;
hashKind = HashKind.Dictionary;
@@ -271,7 +266,7 @@ private void AddPropertyInfoFromPropertySchema(
initializationKind = InitializationKind.SimpleAssign;
type = MakeNamedType(referencedEnumTypeName, out namespaceName);
}
- else if (propertySchema.ShouldBeEnum(_typeName, schemaPropertyName, _hintDictionary, out enumHint))
+ else if (propertySchema.ShouldBeEnum(_typeName, schemaPropertyName, _hintDictionary, out EnumHint enumHint))
{
comparisonKind = ComparisonKind.OperatorEquals;
hashKind = HashKind.ScalarValueType;
@@ -284,7 +279,7 @@ private void AddPropertyInfoFromPropertySchema(
OnAdditionalTypeRequired(enumHint, propertySchema);
}
else
- {
+ {
SchemaType propertyType = propertySchema.SafeGetType();
switch (propertyType)
@@ -384,6 +379,7 @@ private void AddPropertyInfoFromPropertySchema(
type,
namespaceName,
isRequired,
+ propertySchema.Default,
isOfSchemaDefinedType,
arrayRank,
entries.Count)));
@@ -477,6 +473,7 @@ private TypeSyntax MakeDictionaryType(
type: valueType,
namespaceName: dictionaryHint.NamespaceName,
isRequired: true,
+ defaultValue: null,
isOfSchemaDefinedType: false,
arrayRank: 0,
declarationOrder: 0)));
diff --git a/src/Json.Schema.ToDotNet/Resources.Designer.cs b/src/Json.Schema.ToDotNet/Resources.Designer.cs
index f1f0643c..01bc443b 100644
--- a/src/Json.Schema.ToDotNet/Resources.Designer.cs
+++ b/src/Json.Schema.ToDotNet/Resources.Designer.cs
@@ -19,7 +19,7 @@ namespace Microsoft.Json.Schema.ToDotNet {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
@@ -214,7 +214,7 @@ internal static string KindEnumNoneDescription {
}
///
- /// Looks up a localized string similar to An initialization value for the <see cref="P: {0}" /> property..
+ /// Looks up a localized string similar to An initialization value for the <see cref="P:{0}" /> property..
///
internal static string PropertyCtorParamDescription {
get {
diff --git a/src/Json.Schema.ToDotNet/Resources.resx b/src/Json.Schema.ToDotNet/Resources.resx
index 44f5acbe..fffa6fac 100644
--- a/src/Json.Schema.ToDotNet/Resources.resx
+++ b/src/Json.Schema.ToDotNet/Resources.resx
@@ -169,7 +169,7 @@
An uninitialized kind.
- An initialization value for the <see cref="P: {0}" /> property.
+ An initialization value for the <see cref="P:{0}" /> property.
Initializes a new instance of the <see cref="{0}" /> class from the supplied values.
diff --git a/src/Json.Schema.ToDotNet/RewritingVisitorGenerator.cs b/src/Json.Schema.ToDotNet/RewritingVisitorGenerator.cs
index 99b73d2e..3eb94e56 100644
--- a/src/Json.Schema.ToDotNet/RewritingVisitorGenerator.cs
+++ b/src/Json.Schema.ToDotNet/RewritingVisitorGenerator.cs
@@ -79,7 +79,7 @@ internal string GenerateRewritingVisitor()
.AddMembers(
GenerateVisitClassMethods());
- var usings = new List { "System", "System.Collections.Generic", "System.Linq" };
+ var usings = new HashSet { "System", "System.Collections.Generic", "System.Linq" };
string summaryComment = string.Format(
CultureInfo.CurrentCulture,
@@ -356,9 +356,7 @@ private StatementSyntax[] GeneratePropertyVisits(string className)
continue;
}
- int arrayRank = 0;
- bool isDictionary = false;
- string propertyName = propertyNameWithRank.BasePropertyName(out arrayRank, out isDictionary);
+ string propertyName = propertyNameWithRank.BasePropertyName(out int arrayRank, out bool isDictionary);
TypeSyntax collectionType = propertyInfoDictionary.GetConcreteListType(propertyName);
TypeSyntax elementType = propertyInfoDictionary[propertyNameWithRank].Type;
diff --git a/src/Json.Schema.ToDotNet/SyntaxNodeExtensions.cs b/src/Json.Schema.ToDotNet/SyntaxNodeExtensions.cs
index 2176810d..f46481d6 100644
--- a/src/Json.Schema.ToDotNet/SyntaxNodeExtensions.cs
+++ b/src/Json.Schema.ToDotNet/SyntaxNodeExtensions.cs
@@ -54,7 +54,7 @@ internal static class SyntaxNodeExtensions
internal static string Format(
this BaseTypeDeclarationSyntax typeDecl,
string copyrightNotice,
- List usings,
+ HashSet usings,
string namespaceName,
string summaryComment)
{
@@ -74,15 +74,11 @@ internal static string Format(
CompilationUnitSyntax compilationUnit = SyntaxFactory.CompilationUnit()
.AddMembers(namespaceDecl);
- if (usings == null)
- {
- usings = new List();
- }
+ usings = usings ?? new HashSet();
usings.Add("System.CodeDom.Compiler"); // For GeneratedCodeAttribute
UsingDirectiveSyntax[] usingDirectives = usings
- .Distinct()
.OrderBy(u => u, UsingComparer.Instance)
.Select(u => SyntaxFactory.UsingDirective(MakeQualifiedName(u)))
.ToArray();
diff --git a/src/Json.Schema.ToDotNet/TypeGenerator.cs b/src/Json.Schema.ToDotNet/TypeGenerator.cs
index af93ece6..4522aff8 100644
--- a/src/Json.Schema.ToDotNet/TypeGenerator.cs
+++ b/src/Json.Schema.ToDotNet/TypeGenerator.cs
@@ -9,7 +9,7 @@ namespace Microsoft.Json.Schema.ToDotNet
{
public abstract class TypeGenerator
{
- private string _typeNameSuffix;
+ private readonly string _typeNameSuffix;
protected TypeGenerator(
JsonSchema schema,
@@ -37,7 +37,7 @@ public string SuffixedTypeName
///
protected BaseTypeDeclarationSyntax TypeDeclaration { get; set; }
- protected List Usings { get; private set; }
+ protected HashSet Usings { get; private set; }
public abstract BaseTypeDeclarationSyntax GenerateTypeDeclaration();
@@ -73,10 +73,7 @@ public string Generate(string namespaceName, string typeName, string copyrightNo
protected void AddUsing(string namespaceName)
{
- if (Usings == null)
- {
- Usings = new List();
- }
+ Usings = Usings ?? new HashSet();
Usings.Add(namespaceName);
}
diff --git a/src/Json.Schema.UnitTests/JsonSchemaTests.cs b/src/Json.Schema.UnitTests/JsonSchemaTests.cs
index 8e389934..72cb33de 100644
--- a/src/Json.Schema.UnitTests/JsonSchemaTests.cs
+++ b/src/Json.Schema.UnitTests/JsonSchemaTests.cs
@@ -73,7 +73,8 @@ public class JsonSchemaTests
""uniqueItems"": true,
""format"": ""date-time"",
""maximimum"": 2,
- ""exclusiveMaximum"": false
+ ""exclusiveMaximum"": false,
+ ""default"": 2,
}",
@"{
""id"": ""http://x/y#"",
@@ -128,7 +129,8 @@ public class JsonSchemaTests
""uniqueItems"": true,
""format"": ""date-time"",
""maximimum"": 2,
- ""exclusiveMaximum"": false
+ ""exclusiveMaximum"": false,
+ ""default"": 2
}",
true
),
@@ -773,6 +775,84 @@ public class JsonSchemaTests
}",
false
),
+
+ new EqualityTestCase(
+ "Same integer defaults",
+ @"{
+ ""default"": 2
+ }",
+ @"{
+ ""default"": 2
+ }",
+ true),
+
+ new EqualityTestCase(
+ "Different integer defaults",
+ @"{
+ ""default"": 2
+ }",
+ @"{
+ ""default"": 3
+ }",
+ false),
+
+ new EqualityTestCase(
+ "Same string defaults",
+ @"{
+ ""default"": ""2""
+ }",
+ @"{
+ ""default"": ""2""
+ }",
+ true),
+
+ new EqualityTestCase(
+ "Different string defaults",
+ @"{
+ ""default"": ""2""
+ }",
+ @"{
+ ""default"": ""3""
+ }",
+ false),
+
+ new EqualityTestCase(
+ "Same Boolean defaults",
+ @"{
+ ""default"": true
+ }",
+ @"{
+ ""default"": true
+ }",
+ true),
+
+ new EqualityTestCase(
+ "Different Boolean defaults",
+ @"{
+ ""default"": false
+ }",
+ @"{
+ ""default"": true
+ }",
+ false),
+
+ new EqualityTestCase(
+ "Different default types",
+ @"{
+ ""default"": 2
+ }",
+ @"{
+ ""default"": ""2""
+ }",
+ false),
+
+ new EqualityTestCase(
+ "Present and missing defaults",
+ @"{
+ ""default"": 2
+ }",
+ @"{}",
+ false)
};
[Theory(DisplayName = "JsonSchema equality")]
diff --git a/src/Json.Schema/JsonSchema.cs b/src/Json.Schema/JsonSchema.cs
index 392d9e55..1a47aa5b 100644
--- a/src/Json.Schema/JsonSchema.cs
+++ b/src/Json.Schema/JsonSchema.cs
@@ -102,6 +102,7 @@ public JsonSchema(JsonSchema other)
PatternProperties = new Dictionary(other.PatternProperties);
}
+ Default = other.Default;
Pattern = other.Pattern;
MaxLength = other.MaxLength;
MinLength = other.MinLength;
@@ -266,6 +267,12 @@ public JsonSchema(JsonSchema other)
///
public int? MinLength { get; set; }
+ ///
+ /// Gets or sets the value the property should be taken to have if it is absent
+ /// from an instance document.
+ ///
+ public object Default { get; set; }
+
///
/// Gets or sets a regular expression which a string schema instance must match.
///
@@ -520,8 +527,7 @@ private static JsonSchema Collapse(JsonSchema schema, JsonSchema rootSchema)
string definitionName = schema.Reference.GetDefinitionName();
- JsonSchema referencedSchema;
- if (rootSchema.Definitions == null || !rootSchema.Definitions.TryGetValue(definitionName, out referencedSchema))
+ if (rootSchema.Definitions == null || !rootSchema.Definitions.TryGetValue(definitionName, out JsonSchema referencedSchema))
{
throw Error.CreateException(
Resources.ErrorDefinitionDoesNotExist,
@@ -547,6 +553,7 @@ private static JsonSchema Collapse(JsonSchema schema, JsonSchema rootSchema)
collapsedSchema.Items.SingleSchema = referencedSchema.Items.SingleSchema;
}
+ collapsedSchema.Default = referencedSchema.Default;
collapsedSchema.Pattern = referencedSchema.Pattern;
collapsedSchema.MaxLength = referencedSchema.MaxLength;
collapsedSchema.MinLength = referencedSchema.MinLength;
@@ -583,6 +590,7 @@ public override int GetHashCode()
Required,
Definitions,
Reference,
+ Default,
Pattern,
MaxLength,
MinLength,
@@ -610,7 +618,7 @@ public override int GetHashCode()
public bool Equals(JsonSchema other)
{
- if ((object)other == null)
+ if (other is null)
{
return false;
}
@@ -646,6 +654,7 @@ public bool Equals(JsonSchema other)
&& (Reference == null
? other.Reference == null
: Reference.Equals(other.Reference))
+ && Object.Equals(Default, other.Default)
&& Pattern == other.Pattern
&& MaxLength == other.MaxLength
&& MinLength == other.MinLength
@@ -679,7 +688,7 @@ public bool Equals(JsonSchema other)
return true;
}
- if ((object)left == null)
+ if (left is null)
{
return false;
}