diff --git a/pkg/concepts/type.go b/pkg/concepts/type.go index f155455..e54dee6 100644 --- a/pkg/concepts/type.go +++ b/pkg/concepts/type.go @@ -17,7 +17,6 @@ limitations under the License. package concepts import ( - "log" "sort" "github.com/openshift-online/ocm-api-metamodel/pkg/names" @@ -186,19 +185,6 @@ func (t *Type) AddAttribute(attribute *Attribute) { } } -// Remove attribute removes an attribute with a given name. -func (t *Type) RemoveAttribute(name *names.Name) { - if name == nil { - return - } - for i, attribute := range t.attributes { - if attribute.Name().Equals(name) { - log.Printf("---------- Deleting attribute %s", name.String()) - t.attributes = append(t.attributes[:i], t.attributes[i+1:]...) - } - } -} - // FindAttribute returns the attribute with the given name, or nil if no such attribute exists. func (t *Type) FindAttribute(name *names.Name) *Attribute { for _, attribute := range t.attributes { diff --git a/pkg/concepts/version.go b/pkg/concepts/version.go index 603548d..63500c8 100644 --- a/pkg/concepts/version.go +++ b/pkg/concepts/version.go @@ -106,6 +106,15 @@ func (v *Version) AddType(typ *Type) { } } +// AddTypeWithoutOwner adds the given type to the version *without* changing +// its owner. This is crucial when were adding references to other types from different +// versions. +func (v *Version) AddTypeWithoutOwner(typ *Type) { + if typ != nil { + v.types[typ.Name().String()] = typ + } +} + // AddTypes adds the given types to the version. func (v *Version) AddTypes(types []*Type) { for _, typ := range types { diff --git a/pkg/generators/golang/builders_generator.go b/pkg/generators/golang/builders_generator.go index ebec888..91ef193 100644 --- a/pkg/generators/golang/builders_generator.go +++ b/pkg/generators/golang/builders_generator.go @@ -189,6 +189,7 @@ func (g *BuildersGenerator) generateStructBuilderFile(typ *concepts.Type) error Function("builderName", g.builderName). Function("fieldName", g.fieldName). Function("fieldType", g.fieldType). + Function("selectorType", g.selectorType). Function("objectName", g.objectName). Function("setterName", g.setterName). Function("setterType", g.setterType). @@ -274,6 +275,7 @@ func (g *BuildersGenerator) generateStructBuilderSource(typ *concepts.Type) { {{ $setterName := setterName . }} {{ $setterType := setterType . }} {{ $fieldMask := bitMask . }} + {{ $selectorType := selectorType . }} {{ if .Type.IsList }} // {{ $setterName }} sets the value of the '{{ .Name }}' attribute to the given values. @@ -296,8 +298,8 @@ func (g *BuildersGenerator) generateStructBuilderSource(typ *concepts.Type) { } {{ else }} {{ $elementBuilderName := builderName .Type.Element }} - func (b *{{ $builderName }}) {{ $setterName }}(values ...*{{ $elementBuilderName }}) *{{ $builderName }} { - b.{{ $fieldName }} = make([]*{{ $elementBuilderName }}, len(values)) + func (b *{{ $builderName }}) {{ $setterName }}(values ...*{{ selectorType . }}{{ $elementBuilderName }}) *{{ $builderName }} { + b.{{ $fieldName }} = make([]*{{ selectorType . }}{{ $elementBuilderName }}, len(values)) copy(b.{{ $fieldName }}, values) b.bitmap_ |= {{ $fieldMask }} return b @@ -337,26 +339,27 @@ func (g *BuildersGenerator) generateStructBuilderSource(typ *concepts.Type) { {{ range .Type.Attributes }} {{ $fieldName := fieldName . }} {{ $fieldType := fieldType . }} + {{ $selectorType := selectorType . }} {{ if .Type.IsScalar }} b.{{ $fieldName }} = object.{{ $fieldName }} {{ else if .Type.IsStruct }} if object.{{ $fieldName }} != nil { - b.{{ $fieldName }} = {{ builderCtor .Type }}().Copy(object.{{ $fieldName }}) + b.{{ $fieldName }} = {{ selectorType . }}{{ builderCtor .Type }}().Copy(object.{{ $fieldName }}) } else { b.{{ $fieldName }} = nil } {{ else if .Type.IsList }} if object.{{ $fieldName }} != nil { {{ if .Link }} - b.{{ $fieldName }} = {{ builderCtor .Type }}().Copy(object.{{ $fieldName }}) + b.{{ $fieldName }} = {{ selectorType . }}{{ builderCtor .Type }}().Copy(object.{{ $fieldName }}) {{ else }} {{ if .Type.Element.IsScalar }} b.{{ $fieldName }} = make({{ $fieldType }}, len(object.{{ $fieldName }})) copy(b.{{ $fieldName }}, object.{{ $fieldName }}) {{ else if .Type.Element.IsStruct }} - b.{{ $fieldName }} = make([]*{{ builderName .Type.Element }}, len(object.{{ $fieldName }})) + b.{{ $fieldName }} = make([]*{{ selectorType . }}{{ builderName .Type.Element }}, len(object.{{ $fieldName }})) for i, v := range object.{{ $fieldName }} { - b.{{ $fieldName }}[i] = {{ builderCtor .Type.Element }}().Copy(v) + b.{{ $fieldName }}[i] = {{ selectorType . }}{{ builderCtor .Type.Element }}().Copy(v) } {{ end }} {{ end }} @@ -371,9 +374,9 @@ func (g *BuildersGenerator) generateStructBuilderSource(typ *concepts.Type) { b.{{ $fieldName }}[k] = v } {{ else if .Type.Element.IsStruct }} - b.{{ $fieldName }} = map[string]*{{ builderName .Type.Element }}{} + b.{{ $fieldName }} = map[string]*{{ selectorType . }}{{ builderName .Type.Element }}{} for k, v := range object.{{ $fieldName }} { - b.{{ $fieldName }}[k] = {{ builderCtor .Type.Element }}().Copy(v) + b.{{ $fieldName }}[k] = {{ selectorType . }}{{ builderCtor .Type.Element }}().Copy(v) } {{ end }} } else { @@ -416,7 +419,7 @@ func (g *BuildersGenerator) generateStructBuilderSource(typ *concepts.Type) { object.{{ $fieldName }} = make({{ $fieldType }}, len(b.{{ $fieldName }})) copy(object.{{ $fieldName }}, b.{{ $fieldName }}) {{ else if .Type.Element.IsStruct }} - object.{{ $fieldName }} = make([]*{{ objectName .Type.Element }}, len(b.{{ $fieldName }})) + object.{{ $fieldName }} = make([]*{{ selectorType . }}{{ objectName .Type.Element }}, len(b.{{ $fieldName }})) for i, v := range b.{{ $fieldName }} { object.{{ $fieldName }}[i], err = v.Build() if err != nil { @@ -434,7 +437,7 @@ func (g *BuildersGenerator) generateStructBuilderSource(typ *concepts.Type) { object.{{ $fieldName }}[k] = v } {{ else if .Type.Element.IsStruct }} - object.{{ $fieldName }} = make(map[string]*{{ objectName .Type.Element }}) + object.{{ $fieldName }} = make(map[string]*{{ selectorType . }}{{ objectName .Type.Element }}) for k, v := range b.{{ $fieldName }} { object.{{ $fieldName }}[k], err = v.Build() if err != nil { @@ -685,6 +688,15 @@ func (g *BuildersGenerator) fieldType(attribute *concepts.Attribute) *TypeRefere return ref } +func (g *BuildersGenerator) selectorType(attribute *concepts.Attribute) string { + ref := g.fieldType(attribute) + pkgName := g.packages.VersionSelector(attribute.Owner().Owner()) + if pkgName != ref.selector { + return fmt.Sprintf("%s.", ref.selector) + } + return "" +} + func (g *BuildersGenerator) setterName(attribute *concepts.Attribute) string { name := annotations.GoName(attribute) if name == "" { diff --git a/pkg/generators/golang/json_generator.go b/pkg/generators/golang/json_generator.go index 018db16..d4fe919 100644 --- a/pkg/generators/golang/json_generator.go +++ b/pkg/generators/golang/json_generator.go @@ -167,14 +167,31 @@ func (g *JSONSupportGenerator) Run() error { } // Generate the code for the model types: + var importRefs []struct { + path string + selector string + } for _, typ := range version.Types() { + for _, att := range typ.Attributes() { + if att.Type().Owner().Name() != version.Name() || + (att.Type().IsList() && att.Type().Element().Owner().Name() != version.Name()) { + importRefs = append(importRefs, + struct { + path string + selector string + }{ + path: g.packages.VersionImport(att.Type().Owner()), + selector: g.packages.VersionSelector(att.Type().Owner()), + }) + } + } switch { case typ.IsStruct(): - err = g.generateStructTypeSupport(typ) + err = g.generateStructTypeSupport(typ, importRefs, version) case typ.IsList(): element := typ.Element() if element.IsScalar() || element.IsStruct() { - err = g.generateListTypeSupport(typ) + err = g.generateListTypeSupport(typ, importRefs, version) } } if err != nil { @@ -184,7 +201,7 @@ func (g *JSONSupportGenerator) Run() error { // Generate the code for the model methods: for _, resource := range version.Resources() { - err = g.generateResourceSupport(resource) + err = g.generateResourceSupport(resource, version) if err != nil { return err } @@ -432,7 +449,7 @@ func (g *JSONSupportGenerator) generateVersionMetadataSupport(version *concepts. Package(pkgName). File(fileName). Function("enumName", g.types.EnumName). - Function("structName", g.types.StructName). + Function("structName", g.types.StructReference). Function("generateReadValue", g.generateReadValue). Function("generateWriteValue", g.generateWriteValue). Function("readTypeFunc", g.readTypeFunc). @@ -511,7 +528,12 @@ func (g *JSONSupportGenerator) generateVersionMetadataSource(version *concepts.V ) } -func (g *JSONSupportGenerator) generateStructTypeSupport(typ *concepts.Type) error { +func (g *JSONSupportGenerator) generateStructTypeSupport(typ *concepts.Type, + importRefs []struct { + path string + selector string + }, + version *concepts.Version) error { var err error // Calculate the package and file name: @@ -533,7 +555,7 @@ func (g *JSONSupportGenerator) generateStructTypeSupport(typ *concepts.Type) err Function("generateWriteValue", g.generateWriteValue). Function("marshalTypeFunc", g.marshalTypeFunc). Function("readTypeFunc", g.readTypeFunc). - Function("structName", g.types.StructName). + Function("structName", g.types.StructReference). Function("unmarshalTypeFunc", g.unmarshalTypeFunc). Function("valueReference", g.types.ValueReference). Function("writeTypeFunc", g.writeTypeFunc). @@ -542,14 +564,19 @@ func (g *JSONSupportGenerator) generateStructTypeSupport(typ *concepts.Type) err return err } + for _, ref := range importRefs { + g.buffer.Import(ref.path, ref.selector) + } + // Generate the code: - g.generateStructTypeSource(typ) + g.generateStructTypeSource(typ, version) // Write the generated code: return g.buffer.Write() } -func (g *JSONSupportGenerator) generateStructTypeSource(typ *concepts.Type) { +func (g *JSONSupportGenerator) generateStructTypeSource(typ *concepts.Type, + version *concepts.Version) { g.buffer.Import("fmt", "") g.buffer.Import("io", "") g.buffer.Import("time", "") @@ -558,9 +585,10 @@ func (g *JSONSupportGenerator) generateStructTypeSource(typ *concepts.Type) { g.buffer.Emit(` {{ $structName := structName .Type }} {{ $marshalTypeFunc := marshalTypeFunc .Type }} - {{ $writeTypeFunc := writeTypeFunc .Type }} + {{ $writeTypeFunc := writeTypeFunc .Type .Version }} {{ $unmarshalTypeFunc := unmarshalTypeFunc .Type }} - {{ $readTypeFunc := readTypeFunc .Type }} + {{ $readTypeFunc := readTypeFunc .Type .Version }} + {{ $version := .Version }} // {{ $marshalTypeFunc }} writes a value of the '{{ .Type.Name }}' type to the given writer. func {{ $marshalTypeFunc }}(object *{{ $structName }}, writer io.Writer) error { @@ -621,7 +649,7 @@ func (g *JSONSupportGenerator) generateStructTypeSource(typ *concepts.Type) { stream.WriteMore() } stream.WriteObjectField("{{ $fieldTag }}") - {{ generateWriteValue (print "object." $fieldName) $v.Type $v.Link }} + {{ generateWriteValue (print "object." $fieldName) $version $v.Type $v.Link }} {{ if lt $i (sub $n 1) }} count++ {{ end }} @@ -670,7 +698,7 @@ func (g *JSONSupportGenerator) generateStructTypeSource(typ *concepts.Type) { {{ $fieldTag := fieldTag . }} {{ $fieldMask := bitMask . }} case "{{ $fieldTag }}": - {{ generateReadValue "value" .Type .Link }} + {{ generateReadValue "value" .Type $version .Link }} object.{{ $fieldName }} = value object.bitmap_ |= {{ $fieldMask }} {{ end }} @@ -682,10 +710,16 @@ func (g *JSONSupportGenerator) generateStructTypeSource(typ *concepts.Type) { } `, "Type", typ, + "Version", version, ) } -func (g *JSONSupportGenerator) generateListTypeSupport(typ *concepts.Type) error { +func (g *JSONSupportGenerator) generateListTypeSupport(typ *concepts.Type, + importRefs []struct { + path string + selector string + }, + version *concepts.Version) error { var err error // Calculate the package and file name: @@ -704,7 +738,7 @@ func (g *JSONSupportGenerator) generateListTypeSupport(typ *concepts.Type) error Function("generateWriteValue", g.generateWriteValue). Function("marshalTypeFunc", g.marshalTypeFunc). Function("readTypeFunc", g.readTypeFunc). - Function("structName", g.types.StructName). + Function("structName", g.types.StructReference). Function("unmarshalTypeFunc", g.unmarshalTypeFunc). Function("valueReference", g.types.ValueReference). Function("writeTypeFunc", g.writeTypeFunc). @@ -714,13 +748,16 @@ func (g *JSONSupportGenerator) generateListTypeSupport(typ *concepts.Type) error } // Generate the code: - g.generateListTypeSource(typ) + g.generateListTypeSource(typ, version) // Write the generated code: return g.buffer.Write() } -func (g *JSONSupportGenerator) generateListTypeSource(typ *concepts.Type) { +func (g *JSONSupportGenerator) generateListTypeSource( + typ *concepts.Type, + version *concepts.Version, +) { g.buffer.Import("fmt", "") g.buffer.Import(g.packages.HelpersImport(), "") g.buffer.Import("github.com/json-iterator/go", "jsoniter") @@ -728,9 +765,9 @@ func (g *JSONSupportGenerator) generateListTypeSource(typ *concepts.Type) { {{ $structName := structName .Type }} {{ $sliceType := valueReference .Type }} {{ $marshalTypeFunc := marshalTypeFunc .Type }} - {{ $writeTypeFunc := writeTypeFunc .Type }} + {{ $writeTypeFunc := writeTypeFunc .Type .Version }} {{ $unmarshalTypeFunc := unmarshalTypeFunc .Type }} - {{ $readTypeFunc := readTypeFunc .Type }} + {{ $readTypeFunc := readTypeFunc .Type .Version }} // {{ $marshalTypeFunc }} writes a list of values of the '{{ .Type.Element.Name }}' type to // the given writer. @@ -752,7 +789,7 @@ func (g *JSONSupportGenerator) generateListTypeSource(typ *concepts.Type) { if i > 0 { stream.WriteMore() } - {{ generateWriteValue "value" .Type.Element false }} + {{ generateWriteValue "value" .Version .Type.Element false }} } stream.WriteArrayEnd() } @@ -774,17 +811,19 @@ func (g *JSONSupportGenerator) generateListTypeSource(typ *concepts.Type) { func {{ $readTypeFunc }}(iterator *jsoniter.Iterator) {{ $sliceType }} { list := {{ valueReference .Type }}{} for iterator.ReadArray() { - {{ generateReadValue "item" .Type.Element false }} + {{ generateReadValue "item" .Type.Element .Version false }} list = append(list, item) } return list } `, "Type", typ, + "Version", version, ) } -func (g *JSONSupportGenerator) generateResourceSupport(resource *concepts.Resource) error { +func (g *JSONSupportGenerator) generateResourceSupport(resource *concepts.Resource, + version *concepts.Version) error { var err error // Calculate the package and file name: @@ -815,7 +854,7 @@ func (g *JSONSupportGenerator) generateResourceSupport(resource *concepts.Resour Function("requestBodyParameters", g.binding.RequestBodyParameters). Function("requestQueryParameters", g.binding.RequestQueryParameters). Function("responseBodyParameters", g.binding.ResponseParameters). - Function("structName", g.types.StructName). + Function("structName", g.types.StructReference). Function("unmarshalTypeFunc", g.unmarshalTypeFunc). Function("valueReference", g.types.ValueReference). Function("writeRequestFunc", g.writeRequestFunc). @@ -827,14 +866,14 @@ func (g *JSONSupportGenerator) generateResourceSupport(resource *concepts.Resour // Generate the code: for _, method := range resource.Methods() { - g.generateMethodSource(method) + g.generateMethodSource(method, version) } // Write the generated code: return g.buffer.Write() } -func (g *JSONSupportGenerator) generateMethodSource(method *concepts.Method) { +func (g *JSONSupportGenerator) generateMethodSource(method *concepts.Method, version *concepts.Version) { switch { case method.IsAdd(): g.generateAddMethodSource(method) @@ -851,7 +890,7 @@ func (g *JSONSupportGenerator) generateMethodSource(method *concepts.Method) { case method.IsUpdate(): g.generateUpdateMethodSource(method) case method.IsAction(): - g.generateActionMethodSource(method) + g.generateActionMethodSource(method, version) default: g.reporter.Errorf( "Don't know how to generate encoding/decoding code for method '%s'", @@ -965,21 +1004,21 @@ func (g *JSONSupportGenerator) generateListMethodSource(method *concepts.Method) } switch field { {{ if .Page }} - {{ generateReadBodyParameter "response" .Page }} + {{ generateReadBodyParameter "response" .Version .Page }} {{ end }} {{ if .Size }} - {{ generateReadBodyParameter "response" .Size }} + {{ generateReadBodyParameter "response" .Version .Size }} {{ end }} {{ if .Total }} - {{ generateReadBodyParameter "response" .Total }} + {{ generateReadBodyParameter "response" .Version .Total }} {{ end }} {{ range .Other }} {{ if .Out }} - {{ generateReadBodyParameter "response" . }} + {{ generateReadBodyParameter "response" .Version . }} {{ end }} {{ end }} case "items": - {{ generateReadValue "items" .Items.Type false }} + {{ generateReadValue "items" .Items.Type .Version false }} {{ if and .Items.Type.IsList .Items.Type.Element.IsScalar }} response.items = items {{ else }} @@ -1076,6 +1115,7 @@ func (g *JSONSupportGenerator) generateSearchMethodSource(method *concepts.Metho g.buffer.Import("net/http", "") g.buffer.Import(g.packages.HelpersImport(), "") g.buffer.Emit(` + {{ $version := .Version }} func {{ writeRequestFunc .Method }}(request *{{ clientRequestName .Method }}, writer io.Writer) error { {{ if .Body }} return {{ marshalTypeFunc .Body.Type }}(request.{{ parameterFieldName .Body }}, writer) @@ -1096,21 +1136,21 @@ func (g *JSONSupportGenerator) generateSearchMethodSource(method *concepts.Metho } switch field { {{ if .Page }} - {{ generateReadBodyParameter "response" .Page }} + {{ generateReadBodyParameter "response" $version .Page }} {{ end }} {{ if .Size }} - {{ generateReadBodyParameter "response" .Size }} + {{ generateReadBodyParameter "response" $version .Size }} {{ end }} {{ if .Total }} - {{ generateReadBodyParameter "response" .Total }} + {{ generateReadBodyParameter "response" $version .Total }} {{ end }} {{ range .Other }} {{ if .Out }} - {{ generateReadBodyParameter "response" . }} + {{ generateReadBodyParameter "response" $version . }} {{ end }} {{ end }} case "items": - {{ generateReadValue "items" .Items.Type false }} + {{ generateReadValue "items" .Items.Type $version false }} {{ if and .Items.Type.IsList .Items.Type.Element.IsScalar }} response.items = items {{ else }} @@ -1159,20 +1199,21 @@ func (g *JSONSupportGenerator) generateUpdateMethodSource(method *concepts.Metho ) } -func (g *JSONSupportGenerator) generateActionMethodSource(method *concepts.Method) { +func (g *JSONSupportGenerator) generateActionMethodSource(method *concepts.Method, + version *concepts.Version) { g.buffer.Import("net/http", "") g.buffer.Import(g.packages.HelpersImport(), "") g.buffer.Emit(` {{ $requestBodyParameters := requestBodyParameters .Method }} {{ $responseBodyParameters := responseBodyParameters .Method }} - + {{ $version := .Version }} func {{ writeRequestFunc .Method }}(request *{{ clientRequestName .Method }}, writer io.Writer) error { {{ if $requestBodyParameters }} count := 0 stream := helpers.NewStream(writer) stream.WriteObjectStart() {{ range $requestBodyParameters }} - {{ generateWriteBodyParameter "request" . }} + {{ generateWriteBodyParameter "request" $version . }} {{ end }} stream.WriteObjectEnd() err := stream.Flush() @@ -1198,7 +1239,7 @@ func (g *JSONSupportGenerator) generateActionMethodSource(method *concepts.Metho } switch field { {{ range $responseBodyParameters }} - {{ generateReadBodyParameter "response" . }} + {{ generateReadBodyParameter "response" $version . }} {{ end }} default: iterator.ReadAny() @@ -1211,6 +1252,7 @@ func (g *JSONSupportGenerator) generateActionMethodSource(method *concepts.Metho } `, "Method", method, + "Version", version, ) } @@ -1248,14 +1290,15 @@ func (g *JSONSupportGenerator) generateReadQueryParameter(parameter *concepts.Pa ) } -func (g *JSONSupportGenerator) generateReadBodyParameter(object string, parameter *concepts. - Parameter) string { +func (g *JSONSupportGenerator) generateReadBodyParameter(object string, + version *concepts.Version, + parameter *concepts.Parameter) string { field := g.parameterFieldName(parameter) tag := g.binding.BodyParameterName(parameter) typ := parameter.Type() return g.buffer.Eval(` case "{{ .Tag }}": - {{ generateReadValue "value" .Type false }} + {{ generateReadValue "value" .Type .Version false }} {{ if .Type.IsScalar }} {{ .Object }}.{{ .Field }} = &value {{ else }} @@ -1266,10 +1309,13 @@ func (g *JSONSupportGenerator) generateReadBodyParameter(object string, paramete "Field", field, "Tag", tag, "Type", typ, + "Version", version, ) } -func (g *JSONSupportGenerator) generateReadValue(variable string, typ *concepts.Type, link bool) string { +func (g *JSONSupportGenerator) generateReadValue(variable string, typ *concepts.Type, + version *concepts.Version, + link bool) string { g.buffer.Import("time", "") return g.buffer.Eval(` {{ if .Type.IsBoolean }} @@ -1295,7 +1341,7 @@ func (g *JSONSupportGenerator) generateReadValue(variable string, typ *concepts. text := iterator.ReadString() {{ .Variable }} := {{ enumName .Type }}(text) {{ else if .Type.IsStruct }} - {{ .Variable }} := {{ readTypeFunc .Type }}(iterator) + {{ .Variable }} := {{ readTypeFunc .Type .Version }}(iterator) {{ else if .Type.IsList }} {{ if .Link }} {{ $structName := structName .Type }} @@ -1308,17 +1354,17 @@ func (g *JSONSupportGenerator) generateReadValue(variable string, typ *concepts. switch field { case "kind": text := iterator.ReadString() - {{ .Variable }}.link = text == {{ $structName }}LinkKind + {{ .Variable }}.SetLink(text == {{ $structName }}LinkKind) case "href": - {{ .Variable }}.href = iterator.ReadString() + {{ .Variable }}.SetHREF(iterator.ReadString()) case "items": - {{ .Variable }}.items = {{ readTypeFunc .Type }}(iterator) + {{ .Variable }}.SetItems({{ readTypeFunc .Type .Version }}(iterator)) default: iterator.ReadAny() } } {{ else }} - {{ .Variable }} := {{ readTypeFunc .Type }}(iterator) + {{ .Variable }} := {{ readTypeFunc .Type .Version }}(iterator) {{ end }} {{ else if .Type.IsMap }} {{ .Variable }} := {{ valueReference .Type }}{} @@ -1327,7 +1373,7 @@ func (g *JSONSupportGenerator) generateReadValue(variable string, typ *concepts. if key == "" { break } - {{ generateReadValue "item" .Type.Element false }} + {{ generateReadValue "item" .Type.Element .Version false }} {{ .Variable }}[key] = item } {{ else }} @@ -1337,11 +1383,14 @@ func (g *JSONSupportGenerator) generateReadValue(variable string, typ *concepts. "Variable", variable, "Type", typ, "Link", link, + "Version", version, ) } func (g *JSONSupportGenerator) generateWriteBodyParameter(object string, - parameter *concepts.Parameter) string { + version *concepts.Version, + parameter *concepts.Parameter, +) string { typ := parameter.Type() field := g.parameterFieldName(parameter) tag := g.binding.BodyParameterName(parameter) @@ -1365,7 +1414,7 @@ func (g *JSONSupportGenerator) generateWriteBodyParameter(object string, stream.WriteMore() } stream.WriteObjectField("{{ .Tag }}") - {{ generateWriteValue .Value .Type false }} + {{ generateWriteValue .Value .Version .Type false }} count++ } `, @@ -1374,10 +1423,14 @@ func (g *JSONSupportGenerator) generateWriteBodyParameter(object string, "Tag", tag, "Value", value, "Type", typ, + "Version", version, ) } -func (g *JSONSupportGenerator) generateWriteValue(value string, typ *concepts.Type, link bool) string { +func (g *JSONSupportGenerator) generateWriteValue(value string, + version *concepts.Version, + typ *concepts.Type, + link bool) string { g.buffer.Import("sort", "") g.buffer.Import("time", "") return g.buffer.Eval(` @@ -1398,15 +1451,15 @@ func (g *JSONSupportGenerator) generateWriteValue(value string, typ *concepts.Ty {{ else if .Type.IsInterface }} stream.WriteVal({{ .Value }}) {{ else if .Type.IsStruct }} - {{ writeTypeFunc .Type }}({{ .Value }}, stream) + {{ writeTypeFunc .Type .Version }}({{ .Value }}, stream) {{ else if .Type.IsList }} {{ if .Link }} stream.WriteObjectStart() stream.WriteObjectField("items") - {{ writeTypeFunc .Type }}({{ .Value }}.items, stream) + {{ writeTypeFunc .Type .Version }}({{ .Value }}.Items(), stream) stream.WriteObjectEnd() {{ else }} - {{ writeTypeFunc .Type }}({{ .Value }}, stream) + {{ writeTypeFunc .Type .Version }}({{ .Value }}, stream) {{ end }} {{ else if .Type.IsMap }} if {{ .Value }} != nil { @@ -1424,7 +1477,7 @@ func (g *JSONSupportGenerator) generateWriteValue(value string, typ *concepts.Ty } item := {{ .Value }}[key] stream.WriteObjectField(key) - {{ generateWriteValue "item" .Type.Element false }} + {{ generateWriteValue "item" .Version .Type.Element false }} } stream.WriteObjectEnd() } else { @@ -1435,6 +1488,7 @@ func (g *JSONSupportGenerator) generateWriteValue(value string, typ *concepts.Ty "Value", value, "Type", typ, "Link", link, + "Version", version, ) } @@ -1463,9 +1517,13 @@ func (g *JSONSupportGenerator) marshalTypeFunc(typ *concepts.Type) string { return name } -func (g *JSONSupportGenerator) writeTypeFunc(typ *concepts.Type) string { +func (g *JSONSupportGenerator) writeTypeFunc(typ *concepts.Type, version *concepts.Version) string { + _, selector := g.types.Package(typ) name := names.Cat(nomenclator.Write, typ.Name()) - return g.names.Private(name) + if selector != g.types.packages.VersionSelector(version) { + return fmt.Sprintf("%s.%s", selector, g.names.Public(name)) + } + return g.names.Public(name) } func (g *JSONSupportGenerator) unmarshalTypeFunc(typ *concepts.Type) string { @@ -1477,9 +1535,13 @@ func (g *JSONSupportGenerator) unmarshalTypeFunc(typ *concepts.Type) string { return name } -func (g *JSONSupportGenerator) readTypeFunc(typ *concepts.Type) string { +func (g *JSONSupportGenerator) readTypeFunc(typ *concepts.Type, version *concepts.Version) string { + _, selector := g.types.Package(typ) name := names.Cat(nomenclator.Read, typ.Name()) - return g.names.Private(name) + if selector != g.types.packages.VersionSelector(version) { + return fmt.Sprintf("%s.%s", selector, g.names.Public(name)) + } + return g.names.Public(name) } func (g *JSONSupportGenerator) fieldName(attribute *concepts.Attribute) string { diff --git a/pkg/generators/golang/types_calculator.go b/pkg/generators/golang/types_calculator.go index 7b0fdcb..e5d9b91 100644 --- a/pkg/generators/golang/types_calculator.go +++ b/pkg/generators/golang/types_calculator.go @@ -143,7 +143,7 @@ func (c *TypesCalculator) StructReference(typ *concepts.Type) *TypeReference { ref.name = c.names.Public(element.Name()) } ref.name += "List" - ref.text = ref.name + ref.text = fmt.Sprintf("%s.%s", ref.selector, ref.name) case typ.IsStruct(): ref = &TypeReference{} ref.imprt, ref.selector = c.Package(typ) @@ -151,7 +151,7 @@ func (c *TypesCalculator) StructReference(typ *concepts.Type) *TypeReference { if ref.name == "" { ref.name = c.names.Public(typ.Name()) } - ref.text = ref.name + ref.text = fmt.Sprintf("%s.%s", ref.selector, ref.name) default: c.reporter.Errorf( "Don't know how to calculate struct type reference for type '%s'", @@ -213,7 +213,7 @@ func (c *TypesCalculator) ValueReference(typ *concepts.Type) *TypeReference { ref.text = fmt.Sprintf("[]%s", ref.text) case element.IsStruct(): ref = c.ValueReference(element) - ref.text = fmt.Sprintf("[]*%s", ref.text) + ref.text = fmt.Sprintf("[]*%s.%s", ref.selector, ref.text) } case typ.IsMap(): element := typ.Element() @@ -223,7 +223,7 @@ func (c *TypesCalculator) ValueReference(typ *concepts.Type) *TypeReference { ref.text = fmt.Sprintf("map[string]%s", ref.text) case element.IsStruct(): ref = c.ValueReference(element) - ref.text = fmt.Sprintf("map[string]*%s", ref.text) + ref.text = fmt.Sprintf("map[string]*%s.%s", ref.selector, ref.text) } case typ.IsStruct(): ref = &TypeReference{} @@ -248,10 +248,14 @@ func (c *TypesCalculator) ValueReference(typ *concepts.Type) *TypeReference { // the nil value. func (c *TypesCalculator) NullableReference(typ *concepts.Type) *TypeReference { switch { - case (typ.IsScalar() && !typ.IsInterface()) || typ.IsStruct(): + case (typ.IsScalar() && !typ.IsInterface()): ref := c.ValueReference(typ) ref.text = fmt.Sprintf("*%s", ref.text) return ref + case typ.IsStruct(): + ref := c.ValueReference(typ) + ref.text = fmt.Sprintf("*%s.%s", ref.selector, ref.name) + return ref default: return c.ValueReference(typ) } diff --git a/pkg/generators/golang/types_generator.go b/pkg/generators/golang/types_generator.go index f239fb1..27040b3 100644 --- a/pkg/generators/golang/types_generator.go +++ b/pkg/generators/golang/types_generator.go @@ -478,6 +478,7 @@ func (g *TypesGenerator) generateStructTypeSource(typ *concepts.Type) { return l != nil && l.link } + // HREF returns the link to the list. func (l *{{ $listName }}) HREF() string { if l != nil { @@ -505,6 +506,32 @@ func (g *TypesGenerator) generateStructTypeSource(typ *concepts.Type) { return len(l.items) } + // Items sets the items of the list. + func (l *{{ $listName }}) SetLink(link bool) { + l.link = link + return + } + + // Items sets the items of the list. + func (l *{{ $listName }}) SetHREF(href string) { + l.href = href + return + } + + // Items sets the items of the list. + func (l *{{ $listName }}) SetItems(items []*{{ $objectName }}) { + l.items = items + return + } + + // Items returns the items of the list. + func (l *{{ $listName }}) Items() []*{{ $objectName }} { + if l == nil { + return nil + } + return l.items + } + // Empty returns true if the list is empty. func (l *{{ $listName }}) Empty() bool { return l == nil || len(l.items) == 0 diff --git a/pkg/language/checks.go b/pkg/language/checks.go index e3cbe4b..31fc7f9 100644 --- a/pkg/language/checks.go +++ b/pkg/language/checks.go @@ -520,8 +520,8 @@ func (r *Reader) checkParameter(parameter *concepts.Parameter) { } if typ != nil && typ != parameter.Type() { r.reporter.Errorf( - "Type of default value of parameter '%s' should be '%s', instead it was %s", - parameter, parameter.Type(), typ.Name().String(), + "Type of default value of parameter '%s' should be '%s'", + parameter, parameter.Type(), ) } } diff --git a/pkg/language/reader.go b/pkg/language/reader.go index 8836f66..59809d6 100644 --- a/pkg/language/reader.go +++ b/pkg/language/reader.go @@ -22,6 +22,7 @@ package language import ( "fmt" "io/ioutil" + "log" "os" "path/filepath" "strconv" @@ -133,7 +134,7 @@ func (r *Reader) Read() (model *concepts.Model, err error) { for _, service := range r.model.Services() { for _, version := range service.Versions() { for _, typ := range version.Types() { - if typ.Kind() != concepts.ListType { + if typ.Kind() != concepts.ListType && typ.Owner().Name() == version.Name() { listName := names.Cat(typ.Name(), nomenclator.List) listType := version.FindType(listName) if listType == nil { @@ -440,12 +441,11 @@ func (r *Reader) ExitClassDecl(ctx *ClassDeclContext) { } input := r.inputs[0] - currVersion := r.service.Versions()[0] path = strings.TrimPrefix(path, "/") components := strings.Split(path, "/") referencedServiceName := components[0] referencedVersion := components[1] - referencedType := components[2] + referencedTypeName := components[2] // Create an ad-hoc reader and model for the specific referenced service. refReader := NewReader(). @@ -462,31 +462,35 @@ func (r *Reader) ExitClassDecl(ctx *ClassDeclContext) { refVersion := refReader.service.FindVersion(names.ParseUsingSeparator(referencedVersion, "_")) // Once loading the service, we find the reference type // then recursively iterate the type tree and add the types to the current version. - for _, currType := range refVersion.Types() { - if strings.Compare(currType.Name().String(), referencedType) == 0 { - r.recursivelyAddTypeToVersion(currVersion, currType) + for _, referencedType := range refVersion.Types() { + if strings.Compare(referencedType.Name().String(), referencedTypeName) == 0 { + r.recursivelyAddTypeToVersion(typ, referencedType) } } } } // A helper function to recursively add types to a version -func (r *Reader) recursivelyAddTypeToVersion(version *concepts.Version, typ *concepts.Type) { - var attributesToRemove concepts.AttributeSlice - for _, attribute := range typ.Attributes() { - // We wish to define links explicitly and not inherint them - // only the attribute fields. - if version.FindType(attribute.Type().Name()) == nil && !attribute.Link() { - r.recursivelyAddTypeToVersion(version, attribute.Type()) - } +func (r *Reader) recursivelyAddTypeToVersion(currType *concepts.Type, + referencedType *concepts.Type) { + log.Printf("Adding type %s from version %s to version %s", + referencedType.Name().String(), + referencedType.Owner().Name().String(), + r.version.Name().String(), + ) + for _, attribute := range referencedType.Attributes() { if attribute.Link() { - attributesToRemove = append(attributesToRemove, attribute) + r.version.AddTypeWithoutOwner(attribute.Type()) + } + if attribute.Type().IsList() || attribute.Type().IsMap() { + r.version.AddTypeWithoutOwner(attribute.Type()) + r.version.AddTypeWithoutOwner(attribute.Type().Element()) + } + if r.version.FindType(attribute.Type().Name()) == nil { + r.recursivelyAddTypeToVersion(currType, attribute.Type()) } } - for _, attribute := range attributesToRemove { - typ.RemoveAttribute(attribute.Name()) - } - version.AddType(typ) + r.version.AddType(referencedType) } func (r *Reader) ExitStructDecl(ctx *StructDeclContext) {