openapi-generator: [BUG] [Spring] [4.3.0] allOf forces inheritance
Bug Report Checklist
- Have you provided a full/minimal spec to reproduce the issue?
- Have you validated the input using an OpenAPI validator (example)?
- What’s the version of OpenAPI Generator used?
- Have you search for related issues/PRs?
- What’s the actual output vs expected output?
- [Optional] Bounty to sponsor the fix (example)
Description
When trying to switch from 4.2.3 to 4.3.0 in our existing project, I’ve noticed different behavior when it comes to allOf. I’m not even sure it’s a bug, maybe it’s intentional but quickly going through release notes of 4.3.0, I didn’t see it mentioned and for me it’s even a breaking change (though the fix in our project shouldn’t be too hard).
To be brief: when having a structure Foo with a few attributes and a structure Bar referencing allOf Foo and then having additional attributes of its own, with version 4.2.3, attributes of Foo would be just “copied” (or mixed-in) into the Bar class but otherwise Bar would have nothing to do with Foo. With version 4.3.0, Bar extends Foo.
Besides this being slightly unexpected (the specification of Swagger 2.0, which we’re currently using, states that “[composition] does not imply a hierarchy between the models”, it is a bit inconvenient when using fluent syntax to build objects because methods of Foo return Foo (of course).
If Foo has attributes foo1 and foo2 and Bar has attributes bar1 and bar2, previously it was possible to write
return new Bar().bar1("a").bar2("b").foo1("c").foo2("d");
Now something like this must be done:
Bar bar = new Bar().bar1("a").bar2("b");
bar.setFoo1("c");
bar.setFoo2("d");
return bar;
openapi-generator version
4.3.0
OpenAPI declaration file content or url
swagger: "2.0"
info:
title: Regression test
version: "1.0"
paths:
/bars:
get:
responses:
200:
description: Success
schema:
type: array
items:
$ref: '#/definitions/Bar'
definitions:
Foo:
type: object
properties:
foo1:
type: string
foo2:
type: string
Bar:
allOf:
-
$ref: '#/definitions/Foo'
-
type: object
properties:
bar1:
type: string
bar2:
type: string
With 4.3.0, three model classes are created: Bar, BarAllOf, and Foo. Interesting parts of the files are:
Bar.java:
public class Bar extends Foo {
@JsonProperty("bar1")
private String bar1;
@JsonProperty("bar2")
private String bar2;
public Bar bar1(String bar1) {
this.bar1 = bar1;
return this;
}
/**
* Get bar1
* @return bar1
*/
@ApiModelProperty(value = "")
public String getBar1() {
return bar1;
}
public void setBar1(String bar1) {
this.bar1 = bar1;
}
public Bar bar2(String bar2) {
this.bar2 = bar2;
return this;
}
/**
* Get bar2
* @return bar2
*/
@ApiModelProperty(value = "")
public String getBar2() {
return bar2;
}
public void setBar2(String bar2) {
this.bar2 = bar2;
}
...
}
BarAllOf.java:
public class BarAllOf {
@JsonProperty("bar1")
private String bar1;
@JsonProperty("bar2")
private String bar2;
public BarAllOf bar1(String bar1) {
this.bar1 = bar1;
return this;
}
/**
* Get bar1
* @return bar1
*/
@ApiModelProperty(value = "")
public String getBar1() {
return bar1;
}
public void setBar1(String bar1) {
this.bar1 = bar1;
}
public BarAllOf bar2(String bar2) {
this.bar2 = bar2;
return this;
}
/**
* Get bar2
* @return bar2
*/
@ApiModelProperty(value = "")
public String getBar2() {
return bar2;
}
public void setBar2(String bar2) {
this.bar2 = bar2;
}
...
}
Foo.java:
public class Foo {
@JsonProperty("foo1")
private String foo1;
@JsonProperty("foo2")
private String foo2;
public Foo foo1(String foo1) {
this.foo1 = foo1;
return this;
}
/**
* Get foo1
* @return foo1
*/
@ApiModelProperty(value = "")
public String getFoo1() {
return foo1;
}
public void setFoo1(String foo1) {
this.foo1 = foo1;
}
public Foo foo2(String foo2) {
this.foo2 = foo2;
return this;
}
/**
* Get foo2
* @return foo2
*/
@ApiModelProperty(value = "")
public String getFoo2() {
return foo2;
}
public void setFoo2(String foo2) {
this.foo2 = foo2;
}
...
}
With version 4.2.3, the same three model classes are generated. Foo and BarAllOf have pretty much the same contents (as with version 4.3.0) but this is how Bar.java looks like:
public class Bar {
@JsonProperty("foo1")
private String foo1;
@JsonProperty("foo2")
private String foo2;
@JsonProperty("bar1")
private String bar1;
@JsonProperty("bar2")
private String bar2;
public Bar foo1(String foo1) {
this.foo1 = foo1;
return this;
}
/**
* Get foo1
* @return foo1
*/
@ApiModelProperty(value = "")
public String getFoo1() {
return foo1;
}
public void setFoo1(String foo1) {
this.foo1 = foo1;
}
public Bar foo2(String foo2) {
this.foo2 = foo2;
return this;
}
/**
* Get foo2
* @return foo2
*/
@ApiModelProperty(value = "")
public String getFoo2() {
return foo2;
}
public void setFoo2(String foo2) {
this.foo2 = foo2;
}
public Bar bar1(String bar1) {
this.bar1 = bar1;
return this;
}
/**
* Get bar1
* @return bar1
*/
@ApiModelProperty(value = "")
public String getBar1() {
return bar1;
}
public void setBar1(String bar1) {
this.bar1 = bar1;
}
public Bar bar2(String bar2) {
this.bar2 = bar2;
return this;
}
/**
* Get bar2
* @return bar2
*/
@ApiModelProperty(value = "")
public String getBar2() {
return bar2;
}
public void setBar2(String bar2) {
this.bar2 = bar2;
}
...
}
Command line used for generation
java -jar openapi-generator-cli.jar generate -g spring
Steps to reproduce
Related issues/PRs
Suggest a fix
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 6
- Comments: 20 (14 by maintainers)
@ondrakucera the fix has been merged into master. Please give it another try.
@jimschubert I’ll try to submit a fix for missing “type: object” affecting the output (composition vs inheritance)
@jimschubert tried removing “type: object” one by one in the spec provided in https://github.com/OpenAPITools/openapi-generator/issues/5876#issuecomment-613314387 but no luck restoring the behavior (composition without inheritance)
4.3.0 was a minor release with breaking changes w/fallback. Are we saying there’s not fallback here?
In #4906 (not yet merged), there’s been a lot of discussion around this behavior. The commit linked here was supposed to introduce only a test helper which I’d proposed in the above PR, and I must not have noticed the additional for loop logic should have remained in #4906.
While looking at #4096, we found the behavior you’ve experienced before 4.3.0 could be achieved by removing
type: objectfrom Foo. Would you be willing to evaluate that before reverting the change?The logic explained above (automagically inferring inheritance) has existed since 3.x for some cases. I think there’s a condition in your spec which has prevented it from working as designed (probably our composition improvements in 4.3.0).
Since there’s a change in behavior (to me it’s a bug), I consider this a regression. I’ll try to file a PR to fix it in the next days when I can find the time