/// <summary> /// Returns a code type references for the specified json schema. /// Generates the appropriate references. /// </summary> internal static CodeTypeReference GetCodeType(JsonSchema propertySchema, SchemaImplementationDetails details, INestedClassProvider internalClassProvider) { propertySchema.ThrowIfNull("propertySchema"); internalClassProvider.ThrowIfNull("internalClassProvider"); if (propertySchema.Type.HasValue == false) { throw new NotSupportedException("propertySchema has no Type. " + propertySchema); } switch (propertySchema.Type.Value) { case JsonSchemaType.String: return new CodeTypeReference(typeof(string)); case JsonSchemaType.Integer: return new CodeTypeReference(typeof(long?)); case JsonSchemaType.Boolean: return new CodeTypeReference(typeof(bool?)); case JsonSchemaType.Float: return new CodeTypeReference(typeof(double?)); case JsonSchemaType.Array: return GetArrayTypeReference(propertySchema, details, internalClassProvider); case JsonSchemaType.Object: return GetObjectTypeReference(propertySchema, details, internalClassProvider); case JsonSchemaType.Any: return new CodeTypeReference(typeof(string)); default: logger.Warning( "Found currently unsupported type {0} as part of {1}", propertySchema.Type.Value, propertySchema); return new CodeTypeReference(typeof(object)); } }
internal static void AddIsMethodResult(IDictionary <JsonSchema, SchemaImplementationDetails> details, IService service, IMethod method) { details.ThrowIfNull("details"); service.ThrowIfNull("service"); method.ThrowIfNull("method"); string id = method.ResponseType; if (string.IsNullOrEmpty(id)) { // Return if this method has no response type return; } // Check if this name is a valid schema if (!service.Schemas.ContainsKey(id)) { return; } ISchema schema = service.Schemas[id]; // If no implementation details have been added yet, create a new entry SchemaImplementationDetails implementationDetails = GetOrCreateDetails(details, schema.SchemaDetails); // Change the value implementationDetails.IsMethodResult = true; }
internal static CodeTypeReference GetArrayTypeReference(JsonSchema propertySchema, SchemaImplementationDetails details, INestedClassProvider internalClassProvider) { propertySchema.ThrowIfNull("propertySchema"); if (propertySchema.Type != JsonSchemaType.Array) { throw new ArgumentException("Must be of JsonSchemaType.Array", "propertySchema"); } var arrayItems = propertySchema.Items; if (arrayItems != null && arrayItems.Count == 1) { CodeTypeReference itemType = arrayItems[0].Id.IsNotNullOrEmpty() ? new CodeTypeReference(arrayItems[0].Id) : GetCodeType(arrayItems[0], details, internalClassProvider); logger.Debug("type for array {0}", itemType.BaseType); return new CodeTypeReference(typeof(IList<>)) { TypeArguments = { itemType } }; } logger.Warning("Found Array of unhandled type. {0}", propertySchema); return new CodeTypeReference(typeof(System.Collections.IList)); }
internal static void AddDetails(IDictionary <JsonSchema, SchemaImplementationDetails> dictionary, JsonSchema schema) { // Add details for this schema SchemaImplementationDetails details = GetOrCreateDetails(dictionary, schema); if (details.TraversedByGenerator) { // This scheme has already been fully generated return; } details.TraversedByGenerator = true; // Check for properties: if (schema.Properties != null) { foreach (KeyValuePair <string, JsonSchema> property in schema.Properties) { ProposeNameIfNecessary(dictionary, property.Key + PropertyClassSuffix, property.Value); AddDetails(dictionary, property.Value); } } // Generate a template name for subclasses. string proposedName = schema.Id.IsNotNullOrEmpty() ? schema.Id : details.ProposedName; // Check for items: if (schema.Items != null) { // Iterate through items and check if they require a name. foreach (JsonSchema item in schema.Items) { // Set the name if necessary and possible. if (!string.IsNullOrEmpty(proposedName)) { ProposeNameIfNecessary(dictionary, proposedName, item); } AddDetails(dictionary, item); } } // Check additional properties: if (schema.AdditionalProperties != null) { ProposeNameIfNecessary(dictionary, proposedName + "Properties", schema.AdditionalProperties); AddDetails(dictionary, schema.AdditionalProperties); } }
/// <summary> /// Gets a class name as a CodeTypeReference for the given schema of the form "IntenalClassN" where /// N is an integer. Given the same JsonSchema this will return the same classname. /// </summary> public CodeTypeReference GetClassName(JsonSchema definition, SchemaImplementationDetails details) { if (knownSubschemas.ContainsKey(definition)) { return(knownSubschemas[definition].Reference); } string name = null; // First, try to generate a name based upon the environment. if (typeDeclaration != null && details != null && !string.IsNullOrEmpty(details.ProposedName)) { string proposedName = details.ProposedName; IEnumerable <string> forbiddenWords = GeneratorUtils.GetWordContextListFromClass(typeDeclaration); forbiddenWords = forbiddenWords.Concat(from KnownSubschema k in knownSubschemas.Values select k.ClassName); string generatedName = GeneratorUtils.GetClassName(proposedName, forbiddenWords); if (generatedName.IsNotNullOrEmpty()) { // The generated name is valid -> take it. name = generatedName; } } // If this name collides with an existing type, generate a unique name. if (name == null) { name = GetSchemaName(knownSubschemas.Count + 1); } // If the current class is not null, set the prefix to the class name as it will be required for // addressing this nested type. string prefix = ""; if (typeDeclaration != null) { prefix = typeDeclaration.Name + "."; } var newSubschema = new KnownSubschema(); newSubschema.Reference = new CodeTypeReference(prefix + name); newSubschema.ClassName = name; knownSubschemas.Add(definition, newSubschema); return(newSubschema.Reference); }
internal static void ProposeNameIfNecessary(IDictionary <JsonSchema, SchemaImplementationDetails> dictionary, string name, JsonSchema schema) { schema.ThrowIfNull("schema"); name.ThrowIfNull("name"); dictionary.ThrowIfNull("name"); if (schema.Id.IsNotNullOrEmpty()) { // Already has a name -> return. return; } SchemaImplementationDetails details = GetOrCreateDetails(dictionary, schema); if (string.IsNullOrEmpty(details.ProposedName)) { details.ProposedName = name; } }
public void DecorateClassTest() { // Init required vars. var decorator = new ResponseInterfaceDecorator(); var declaration = new CodeTypeDeclaration(); var schema = new MockSchema { SchemaDetails = new JsonSchema() }; var internalClassProvider = new ObjectInternalClassProvider(); var implDetails = new Dictionary<JsonSchema, SchemaImplementationDetails>(); implDetails.Add(schema.SchemaDetails, new SchemaImplementationDetails()); // Test edge cases. Assert.Throws( typeof(ArgumentNullException), () => decorator.DecorateClass(null, schema, implDetails, internalClassProvider)); Assert.Throws( typeof(ArgumentNullException), () => decorator.DecorateClass(declaration, null, implDetails, internalClassProvider)); Assert.Throws( typeof(ArgumentNullException), () => decorator.DecorateClass(declaration, schema, null, internalClassProvider)); decorator.DecorateClass(declaration, schema, implDetails, internalClassProvider); Assert.AreEqual(0, declaration.BaseTypes.Count); Assert.AreEqual(0, declaration.Members.Count); // Test simple functionality. var details = new SchemaImplementationDetails { IsMethodResult = true }; implDetails = new Dictionary<JsonSchema, SchemaImplementationDetails> { { schema.SchemaDetails, details } }; decorator.DecorateClass(declaration, schema, implDetails, internalClassProvider); Assert.AreEqual(1, declaration.BaseTypes.Count); Assert.AreEqual(4, declaration.Members.Count); // 2 properties with a field each // Test with already existing e-tag field. declaration = new CodeTypeDeclaration(); declaration.Members.Add(new CodeMemberProperty() { Name = "ETag" }); decorator.DecorateClass(declaration, schema, implDetails, internalClassProvider); Assert.AreEqual(1, declaration.BaseTypes.Count); Assert.AreEqual(3, declaration.Members.Count); // one property with a field, and the previously added one. }
/// <summary> /// Resolves/generates an object type reference for a schema. /// </summary> internal static CodeTypeReference GetObjectTypeReference(JsonSchema propertySchema, SchemaImplementationDetails details, INestedClassProvider internalClassProvider) { propertySchema.ThrowIfNull("propertySchema"); if (propertySchema.Type != JsonSchemaType.Object) { throw new ArgumentException("Must be of JsonSchemaType.Array", "propertySchema"); } if (propertySchema.Id.IsNotNullOrEmpty()) { logger.Debug("Found Object with id using type {0}", propertySchema.Id); return new CodeTypeReference(propertySchema.Id); } return internalClassProvider.GetClassName(propertySchema, details); }
public CodeTypeReference GetClassName(JsonSchema definition, SchemaImplementationDetails details) { return new CodeTypeReference(typeof(object)); }
public void GenerateFieldTest() { var schema = new JsonSchema(); var decorator = new StandardPropertyFieldDecorator(); var implDetails = new SchemaImplementationDetails(); schema.Type = JsonSchemaType.String; CodeMemberField generatedField = decorator.GenerateField( "normalName", schema, implDetails, 1, internalClassProvider, Enumerable.Empty<string>()); Assert.NotNull(generatedField); Assert.AreEqual(typeof(string).FullName, generatedField.Type.BaseType); Assert.AreEqual("_normalName", generatedField.Name); Assert.AreEqual(MemberAttributes.Private, generatedField.Attributes); schema.Type = JsonSchemaType.Boolean; generatedField = decorator.GenerateField( "public", schema, implDetails, 2, internalClassProvider, Enumerable.Empty<string>()); Assert.NotNull(generatedField); Assert.AreEqual(typeof(Nullable<>).FullName, generatedField.Type.BaseType); Assert.AreEqual(typeof(bool).FullName, generatedField.Type.TypeArguments[0].BaseType); Assert.AreEqual("_public", generatedField.Name); Assert.AreEqual(MemberAttributes.Private, generatedField.Attributes); generatedField = decorator.GenerateField( "UPPERCASE", schema, implDetails, 2, internalClassProvider, Enumerable.Empty<string>()); Assert.NotNull(generatedField); Assert.AreEqual("_UPPERCASE", generatedField.Name); }
internal CodeMemberProperty GenerateProperty(string name, JsonSchema propertySchema, SchemaImplementationDetails details, int index, INestedClassProvider internalClassProvider, IEnumerable<string> disallowedNames) { name.ThrowIfNullOrEmpty("name"); propertySchema.ThrowIfNull("propertySchema"); var ret = new CodeMemberProperty(); ret.Name = SchemaDecoratorUtil.GetPropertyName(name, disallowedNames); ret.Type = SchemaDecoratorUtil.GetCodeType(propertySchema, details, internalClassProvider); ret.Attributes = MemberAttributes.Public; ret.HasGet = true; var fieldReference = new CodeFieldReferenceExpression( new CodeThisReferenceExpression(), SchemaDecoratorUtil.GetFieldName(name, disallowedNames)); ret.GetStatements.Add(new CodeMethodReturnStatement(fieldReference)); ret.HasSet = true; var parameterReference = new CodeVariableReferenceExpression("value"); ret.SetStatements.Add(new CodeAssignStatement(fieldReference, parameterReference)); return ret; }
public void GetClassNameWithDetailsTest() { var empty = new List<ISchemaDecorator>(0); var decl = new CodeTypeDeclaration() { Name = "Top" }; var gen = new SchemaGenerator.NestedClassGenerator(decl, empty, "1_"); var schema1 = new JsonSchema(); var details = new SchemaImplementationDetails() { ProposedName = "TestClass" }; Assert.AreEqual("Top.TestClass", gen.GetClassName(schema1, details).BaseType); Assert.AreEqual("Top.TestClass", gen.GetClassName(schema1, null).BaseType); Assert.AreEqual("Top.NestedClass1_2", gen.GetClassName(new JsonSchema(), null).BaseType); }
internal CodeMemberField GenerateField(string name, JsonSchema propertySchema, SchemaImplementationDetails details, int index, INestedClassProvider internalClassProvider, IEnumerable<string> otherFieldNames) { name.ThrowIfNullOrEmpty("name"); propertySchema.ThrowIfNull("propertySchema"); internalClassProvider.ThrowIfNull("internalClassProvider"); details.ThrowIfNull("details"); var ret = new CodeMemberField( SchemaDecoratorUtil.GetCodeType(propertySchema, details, internalClassProvider), SchemaDecoratorUtil.GetFieldName(name, otherFieldNames)); ret.Attributes = MemberAttributes.Private; return ret; }
/// <summary> /// Gets a class name as a CodeTypeReference for the given schema of the form "IntenalClassN" where /// N is an integer. Given the same JsonSchema this will return the same classname. /// </summary> public CodeTypeReference GetClassName(JsonSchema definition, SchemaImplementationDetails details) { if (knownSubschemas.ContainsKey(definition)) { return knownSubschemas[definition].Reference; } string name = null; // First, try to generate a name based upon the environment. if (typeDeclaration != null && details != null && !string.IsNullOrEmpty(details.ProposedName)) { string proposedName = details.ProposedName; IEnumerable<string> forbiddenWords = GeneratorUtils.GetWordContextListFromClass(typeDeclaration); forbiddenWords = forbiddenWords.Concat(from KnownSubschema k in knownSubschemas.Values select k.ClassName); string generatedName = GeneratorUtils.GetClassName(proposedName, forbiddenWords); if (generatedName.IsNotNullOrEmpty()) { // The generated name is valid -> take it. name = generatedName; } } // If this name collides with an existing type, generate a unique name. if (name == null) { name = GetSchemaName(knownSubschemas.Count+1); } // If the current class is not null, set the prefix to the class name as it will be required for // addressing this nested type. string prefix = ""; if (typeDeclaration != null) { prefix = typeDeclaration.Name + "."; } var newSubschema = new KnownSubschema(); newSubschema.Reference = new CodeTypeReference(prefix + name); newSubschema.ClassName = name; knownSubschemas.Add(definition, newSubschema); return newSubschema.Reference; }