Skip to content

JS client: allOf mishandled, composition impossible #2161

Closed
@demonfiddler

Description

@demonfiddler

From what I can tell, when an API specification contains a type definition A that composes by reference to two or more other type definitions (allOf B, C, ...), the model code generated for A only knows about the properties of the last such composed type (C in this case). For an instance of A, a.constructFromObject() will only populate the properties defined by C; the other composed properties (of B in the case) will not be populated. There may be other issues with composition besides this.

Also, I've seen assertions in the Swagger docs that allOf entails type composition not inheritance. Yet based on the presence of a boolean io.swagger.codegen.DefaultCodegen.supportsInheritance field (default: false) there seems to be at least the intention of supporting inheritance yet the Java template does not set this to field to true but does in fact emit the appropriate extends <first-superclass> construct.

Anyhow, It would seem churlish not to exploit JavaScript's extension mechanism even if it is only single inheritance. Also, the JavaScript model.mustache emits a comment to the effect that the class extends the {{parent}} model, although right now I'm trying to understand why the declared JavaScript instance variables are sometimes those of the last listed super type yet in other cases those locally defined within the YAML for the template's current context definition. The following code at io.swagger.parser.util.SwaggerDeserializer lines 821-822 strikes me as suspect:

                    if (allComponents.size() >= 2) {
                        model.setChild(allComponents.get(allComponents.size() - 1)); // <== 822
                        List<RefModel> interfaces = new ArrayList<RefModel>();
                        int size = allComponents.size();
                        for (Model m : allComponents.subList(1, size - 1)) { // <== 825
                            if (m instanceof RefModel) {
                                RefModel ref = (RefModel) m;
                                interfaces.add(ref);
                            }
                        }

It seems to me that the above line 822 incorrectly assumes that the last component is always an anonymous local type defining the owned properties of the current type definition. If the type in question only inherits super-type properties but declares no owned properties, model.child will incorrectly be set to the last allOf super type!

Similarly, line 825 incorrectly excludes the last composed super type, based on the same erroneous assumption that it must necessarily be a local definition. Again, if the definition in question merely composes other definitions by reference, the last such definition needs to be included in the interfaces list.

The above two problems are separately reported as swagger-parser Issue #204.

Note: additionally, I'm unable to comment on the status where A extends B by the inclusion of additional locally defined properties, as I haven't found any examples of this pattern in the system I'm working on (and I don't own the schema or the server).

Finally, I'm not yet in a position to comment on the status with polymorphism (single inheritance) via allOf but I see there's a separate Issue #2041 open for that anyway.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions