diff --git a/generator.go b/generator.go index 9b9e421..32aad41 100644 --- a/generator.go +++ b/generator.go @@ -98,7 +98,7 @@ func (g *Generator) processSchema(schemaName string, schema *Schema) (typ string schema.FixMissingTypeValue() // if we have multiple schema types, the golang type will be interface{} typ = "interface{}" - types, isMultiType := schema.MultiType() + types, isMultiType, pointer := schema.MultiType() if len(types) > 0 { for _, schemaType := range types { name := schemaName @@ -123,7 +123,7 @@ func (g *Generator) processSchema(schemaName string, schema *Schema) (typ string return rv, nil } default: - rv, err := getPrimitiveTypeName(schemaType, "", false) + rv, err := getPrimitiveTypeName(schemaType, "", pointer) if err != nil { return "", err } @@ -238,7 +238,7 @@ func (g *Generator) processObject(name string, schema *Schema) (typ string, err } // additionalProperties as either true (everything) or false (nothing) if schema.AdditionalProperties != nil && schema.AdditionalProperties.AdditionalPropertiesBool != nil { - if *schema.AdditionalProperties.AdditionalPropertiesBool == true { + if *schema.AdditionalProperties.AdditionalPropertiesBool { // everything is valid additional subTyp := "map[string]interface{}" f := Field{ @@ -258,7 +258,12 @@ func (g *Generator) processObject(name string, schema *Schema) (typ string, err strct.AdditionalType = "false" } } + if len(strct.Fields) == 0 { + return "map[string]interface{}", nil + } + g.Structs[strct.Name] = strct + // objects are always a pointer return getPrimitiveTypeName("object", name, true) } @@ -280,10 +285,19 @@ func getPrimitiveTypeName(schemaType string, subType string, pointer bool) (name } return "[]" + subType, nil case "boolean": + if pointer { + return "*bool", nil + } return "bool", nil case "integer": + if pointer { + return "*int", nil + } return "int", nil case "number": + if pointer { + return "*float64", nil + } return "float64", nil case "null": return "nil", nil @@ -296,6 +310,9 @@ func getPrimitiveTypeName(schemaType string, subType string, pointer bool) (name } return subType, nil case "string": + if pointer { + return "*string", nil + } return "string", nil } diff --git a/jsonschema.go b/jsonschema.go index 5c0616a..52600bb 100644 --- a/jsonschema.go +++ b/jsonschema.go @@ -150,10 +150,25 @@ func (schema *Schema) Type() (firstOrDefault string, multiple bool) { } // MultiType returns "type" as an array -func (schema *Schema) MultiType() ([]string, bool) { +func (schema *Schema) MultiType() (types []string, isMultiType bool, pointer bool) { // We've got a single value, e.g. { "type": "object" } if ts, ok := schema.TypeValue.(string); ok { - return []string{ts}, false + return []string{ts}, false, false + } + + if len(schema.OneOf) > 0 { + rv := []string{} + optional := false + for _, t := range schema.OneOf { + if t.TypeValue == "null" { + optional = true + } else { + if s, ok := t.TypeValue.(string); ok { + rv = append(rv, s) + } + } + } + return rv, len(rv) > 1, optional } // We could have multiple types in the type value, e.g. { "type": [ "object", "array" ] } @@ -164,10 +179,10 @@ func (schema *Schema) MultiType() ([]string, bool) { rv = append(rv, s) } } - return rv, len(rv) > 1 + return rv, len(rv) > 1, false } - return nil, false + return nil, false, false } // GetRoot returns the root schema. diff --git a/test/oneofnull.json b/test/oneofnull.json new file mode 100644 index 0000000..6b35c06 --- /dev/null +++ b/test/oneofnull.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Simple", + "type": "object", + "properties": { + "optional_name": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + } +} \ No newline at end of file diff --git a/test/oneofnull_test.go b/test/oneofnull_test.go new file mode 100644 index 0000000..1e07941 --- /dev/null +++ b/test/oneofnull_test.go @@ -0,0 +1,60 @@ +package test + +import ( + "encoding/json" + "testing" + + gen "github.com/a-h/generate/test/oneofnull_gen" +) + +func TestOneOfNullParsingValue(t *testing.T) { + + noPropData := `{"optional_name": "v"}` + + s := gen.Simple{} + err := json.Unmarshal([]byte(noPropData), &s) + if err != nil { + t.Fatal(err) + } + + if s.OptionalName == nil { + t.Fatal("Field option_name should be initialized") + } + + if *s.OptionalName != "v" { + t.Fatal("Field option_name should be `v`") + } + +} + +func TestOneOfNullParsingNull(t *testing.T) { + + noPropData := `{"optional_name": null}` + + s := gen.Simple{} + err := json.Unmarshal([]byte(noPropData), &s) + if err != nil { + t.Fatal(err) + } + + if s.OptionalName != nil { + t.Fatal("Field option_name should be nil") + } + +} + +func TestOneOfNullParsingAbsent(t *testing.T) { + + noPropData := `{}` + + s := gen.Simple{} + err := json.Unmarshal([]byte(noPropData), &s) + if err != nil { + t.Fatal(err) + } + + if s.OptionalName != nil { + t.Fatal("Field option_name should be nil") + } + +}