diff --git a/pkg/concepts/type.go b/pkg/concepts/type.go index f155455..2679619 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" @@ -193,7 +192,6 @@ func (t *Type) RemoveAttribute(name *names.Name) { } 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:]...) } } diff --git a/pkg/concepts/version.go b/pkg/concepts/version.go index 603548d..3681c45 100644 --- a/pkg/concepts/version.go +++ b/pkg/concepts/version.go @@ -106,6 +106,13 @@ func (v *Version) AddType(typ *Type) { } } +// AddType adds the given type to the version. +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..9b97d4a 100644 --- a/pkg/generators/golang/json_generator.go +++ b/pkg/generators/golang/json_generator.go @@ -170,11 +170,11 @@ func (g *JSONSupportGenerator) Run() error { for _, typ := range version.Types() { switch { case typ.IsStruct(): - err = g.generateStructTypeSupport(typ) + err = g.generateStructTypeSupport(typ, version) case typ.IsList(): element := typ.Element() if element.IsScalar() || element.IsStruct() { - err = g.generateListTypeSupport(typ) + err = g.generateListTypeSupport(typ, version) } } if err != nil { @@ -184,7 +184,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 } @@ -511,7 +511,7 @@ func (g *JSONSupportGenerator) generateVersionMetadataSource(version *concepts.V ) } -func (g *JSONSupportGenerator) generateStructTypeSupport(typ *concepts.Type) error { +func (g *JSONSupportGenerator) generateStructTypeSupport(typ *concepts.Type, version *concepts.Version) error { var err error // Calculate the package and file name: @@ -543,13 +543,14 @@ func (g *JSONSupportGenerator) generateStructTypeSupport(typ *concepts.Type) err } // 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 +559,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 }} + {{ $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 +623,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 }} @@ -682,10 +684,11 @@ 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, version *concepts.Version) error { var err error // Calculate the package and file name: @@ -714,13 +717,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,7 +734,7 @@ 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 }} @@ -752,7 +758,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() } @@ -781,10 +787,12 @@ func (g *JSONSupportGenerator) generateListTypeSource(typ *concepts.Type) { } `, "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: @@ -827,14 +835,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 +859,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'", @@ -1159,20 +1167,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() @@ -1211,6 +1220,7 @@ func (g *JSONSupportGenerator) generateActionMethodSource(method *concepts.Metho } `, "Method", method, + "Version", version, ) } @@ -1341,7 +1351,9 @@ func (g *JSONSupportGenerator) generateReadValue(variable string, typ *concepts. } 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 +1377,7 @@ func (g *JSONSupportGenerator) generateWriteBodyParameter(object string, stream.WriteMore() } stream.WriteObjectField("{{ .Tag }}") - {{ generateWriteValue .Value .Type false }} + {{ generateWriteValue .Value .Version .Type false }} count++ } `, @@ -1374,10 +1386,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 +1414,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 +1440,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 +1451,7 @@ func (g *JSONSupportGenerator) generateWriteValue(value string, typ *concepts.Ty "Value", value, "Type", typ, "Link", link, + "Version", version, ) } @@ -1463,9 +1480,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 { @@ -1479,7 +1500,7 @@ func (g *JSONSupportGenerator) unmarshalTypeFunc(typ *concepts.Type) string { func (g *JSONSupportGenerator) readTypeFunc(typ *concepts.Type) string { name := names.Cat(nomenclator.Read, typ.Name()) - return g.names.Private(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..53b10eb 100644 --- a/pkg/generators/golang/types_calculator.go +++ b/pkg/generators/golang/types_calculator.go @@ -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/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) {