private CodeTypeDeclaration GenerateClass() { if (!context.ContainsKey(schema)) { context.Add(schema, new GenerationResult() { TypeName = targetClass.Name, Type = MyTypeBuilder.CreateType(targetClass.Name), ClassGenerator = this }); } if (schema.Enum?.Count > 0) { return(GenerateClassFromEnumSchema()); } if (schema.Type?.Value is SimpleType && (schema.Type.Value as SimpleType).Value != SimpleType.Object) { var schemaType = schema.Type.Value as SimpleType; if (schemaType.Value == SimpleType.Integer) { return(GenerateClassFromIntegerSchema()); } if (schemaType.Value == SimpleType.Number) { return(GenerateClassFromNumberSchema()); } if (schemaType.Value == SimpleType.String) { return(GenerateClassFromStringSchema()); } if (schemaType.Value == SimpleType.Array) { return(GenerateClassFromArraySchema()); } } var definitions = schema.Definitions; if (definitions != null) { foreach (string definitionName in schema.Definitions.Keys) { var definition = definitions[definitionName]; if (!context.ContainsKey(definition)) { var nestedClassGenerator = new ClassGeneratorFromJsonSchema(definition, context); context[definition] = new GenerationResult() { Type = MyTypeBuilder.CreateType(nestedClassGenerator.targetClass.Name), TypeName = nestedClassGenerator.targetClass.Name, ClassGenerator = nestedClassGenerator }; nestedClassGenerator.GenerateClass(); } //context.Add(definition, new GenerationResult() { TypeName = nestedClassGenerator.targetClass.Name }); } } var properties = schema.Properties; var additionalProperties = schema.AdditionalProperties; //Oneof/AnyOf/AllOf are only supported when there are no properties or additionalProperties and when the schema type is not a primitive type or array type if (properties == null && additionalProperties == null) { if (schema.OneOf != null && schema.OneOf.Count > 0) { return(GenerateClassFromOneOfAnyOfSchema(true)); } if (schema.AnyOf != null && schema.AnyOf.Count > 0) { return(GenerateClassFromOneOfAnyOfSchema(false)); } if (schema.AllOf != null && schema.AllOf.Count > 0) { var mergedSchema = JSONSchema.MergeSchemas(schema.AllOf); var mergedClassGenerator = new ClassGeneratorFromJsonSchema(mergedSchema, this.targetClass.Name); targetClass = mergedClassGenerator.GenerateClass(); context[schema] = mergedClassGenerator.context[mergedSchema]; foreach (var jsonSchema in mergedClassGenerator.context.Keys) { if (jsonSchema != mergedSchema) { context[jsonSchema] = mergedClassGenerator.context[jsonSchema]; } } return(targetClass); } } if (properties != null) { foreach (string propertyName in properties.Keys) { var cleanPropertyName = Clean(propertyName); if (propertyNames.Contains(cleanPropertyName)) { //to avoid property names that would collide continue; } propertyNames.Add(cleanPropertyName); var property = properties[propertyName]; if (context.ContainsKey(property)) { targetClass.AddProperty(cleanPropertyName, context[property].TypeName); } else if (property.Type?.GetUnderlyingType() == typeof(SimpleType) && (property.Type.Value as SimpleType).Value != SimpleType.Object && (property.Type.Value as SimpleType).Value != SimpleType.Array && (property.Enum == null || property.Enum.Count < 1) ) { targetClass.AddProperty(cleanPropertyName, ComputeType((SimpleType)property.Type.GetValue())); } else { var nestedClassGenerator = new ClassGeneratorFromJsonSchema(property, context, cleanPropertyName); context[property] = new GenerationResult() { Type = MyTypeBuilder.CreateType(nestedClassGenerator.targetClass.Name), TypeName = nestedClassGenerator.targetClass.Name, ClassGenerator = nestedClassGenerator }; nestedClassGenerator.GenerateClass(); targetClass.AddProperty(cleanPropertyName, context[property].Type); } } } if (additionalProperties != null) { if (additionalProperties.Value is bool) { if ((bool)additionalProperties.Value == true) { targetClass.BaseTypes.Add(new CodeTypeReference(typeof(Dictionary <string, object>))); } } else { var additionalPropertiesSchema = additionalProperties.Value as JSONSchema; if (!context.ContainsKey(additionalPropertiesSchema)) { var nestedClassGenerator = new ClassGeneratorFromJsonSchema(additionalPropertiesSchema, context, context[schema].TypeName + "AdditionalProperties"); context[additionalPropertiesSchema] = new GenerationResult() { Type = MyTypeBuilder.CreateType(nestedClassGenerator.targetClass.Name), TypeName = nestedClassGenerator.targetClass.Name, ClassGenerator = nestedClassGenerator }; nestedClassGenerator.GenerateClass(); } targetClass.BaseTypes.Add(new CodeTypeReference("Dictionary", new CodeTypeReference(typeof(string)), new CodeTypeReference(context[additionalPropertiesSchema].Type))); context[schema].Imports.Add("System.Collections.Generic"); } } return(targetClass); }
private CodeTypeDeclaration GenerateClassFromOneOfAnyOfSchema(bool handleOneOf) { ISet <string> subSchemasSet = new HashSet <string>(); int index = 0; var schemaArray = handleOneOf ? schema.OneOf : schema.AnyOf; foreach (JSONSchema subSchema in schemaArray) { if (context.ContainsKey(subSchema)) { subSchemasSet.Add(context[subSchema].TypeName); } else if (subSchema.Type?.GetUnderlyingType() == typeof(SimpleType) && (subSchema.Type.Value as SimpleType).Value != SimpleType.Object && (subSchema.Type.Value as SimpleType).Value != SimpleType.Array ) { subSchemasSet.Add(ComputeType((SimpleType)subSchema.Type.GetValue()).Name); } else { var nestedClassGenerator = new ClassGeneratorFromJsonSchema(subSchema, context, string.Concat(targetClass.Name, handleOneOf?"OneOf":"AnyOf", index)); context[subSchema] = new GenerationResult() { Type = MyTypeBuilder.CreateType(nestedClassGenerator.targetClass.Name), TypeName = nestedClassGenerator.targetClass.Name, ClassGenerator = nestedClassGenerator }; nestedClassGenerator.GenerateClass(); subSchemasSet.Add(nestedClassGenerator.targetClass.Name); } index++; } targetClass = new CodeTypeDeclaration(targetClass.Name) { IsClass = true, TypeAttributes = TypeAttributes.Public }; var field = new CodeMemberField() { Attributes = MemberAttributes.Private | MemberAttributes.Final, Name = "Value", Type = new CodeTypeReference(typeof(object)) }; targetClass.Members.Add(field); CodeConstructor constructor = new CodeConstructor { Attributes = MemberAttributes.Private }; constructor.Comments.Add(new CodeCommentStatement("Hiding visiblity of default constructor")); targetClass.Members.Add(constructor); CodeStatement[] codeStatements = new CodeStatement[subSchemasSet.Count + 1]; index = 0; foreach (string subSchemaName in subSchemasSet) { codeStatements[index] = If(NewSnippet("value is " + subSchemaName), new CodeAssignStatement(new CodeVariableReferenceExpression("Value"), new CodeVariableReferenceExpression("value"))); index++; } codeStatements[index] = Throw(typeof(ArgumentException), "Value's type is not correct"); CodeConstructor publicConstructor = NewPublicConstructor( Array(NewParameter(typeof(object), "value")), codeStatements ); targetClass.Members.Add(publicConstructor); foreach (string subSchemaName in subSchemasSet) { var implicitOperator = new CodeSnippetTypeMember(string.Format("\t\tpublic static implicit operator {0}({1} d) => ({0})d.Value;", subSchemaName, targetClass.Name)); targetClass.Members.Add(implicitOperator); var explicitOperator = new CodeSnippetTypeMember(string.Format("\t\tpublic static explicit operator {0}({1} v) => new {0}(v);", targetClass.Name, subSchemaName)); targetClass.Members.Add(explicitOperator); } return(targetClass); }