From 61271d314e2fcc03d67d744ff7549348bb7638c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesse=20Wayde=20Brand=C3=A3o?= Date: Sun, 26 Jan 2025 09:48:26 +0100 Subject: [PATCH] feat: improved inheritance handling for the Java Generator (#2148) --- .../java/renderers/ClassRenderer.ts | 24 +- test/generators/java/JavaGenerator.spec.ts | 110 +++---- .../__snapshots__/JavaGenerator.spec.ts.snap | 288 ++---------------- 3 files changed, 81 insertions(+), 341 deletions(-) diff --git a/src/generators/java/renderers/ClassRenderer.ts b/src/generators/java/renderers/ClassRenderer.ts index 7f33076523..9724ae81db 100644 --- a/src/generators/java/renderers/ClassRenderer.ts +++ b/src/generators/java/renderers/ClassRenderer.ts @@ -32,31 +32,31 @@ export class ClassRenderer extends JavaRenderer { this.dependencyManager.addDependency('import java.util.Map;'); } - if (this.model.options.isExtended) { - return `public interface ${this.model.name} { -${this.indent(this.renderBlock(content, 2))} -}`; - } + const abstractType = this.model.options.isExtended ? 'interface' : 'class'; const parentUnions = this.getParentUnions(); const extend = this.model.options.extend?.filter( (extend) => extend.options.isExtended ); - const implement = [...(parentUnions ?? []), ...(extend ?? [])]; + const parents = [...(parentUnions ?? []), ...(extend ?? [])]; - if (implement.length) { - for (const i of implement) { + if (parents.length) { + for (const i of parents) { this.dependencyManager.addModelDependency(i); } - return `public class ${this.model.name} implements ${implement - .map((i) => i.name) - .join(', ')} { + const inheritanceKeyworkd = this.model.options.isExtended + ? 'extends' + : 'implements'; + + return `public ${abstractType} ${ + this.model.name + } ${inheritanceKeyworkd} ${parents.map((i) => i.name).join(', ')} { ${this.indent(this.renderBlock(content, 2))} }`; } - return `public class ${this.model.name} { + return `public ${abstractType} ${this.model.name} { ${this.indent(this.renderBlock(content, 2))} }`; } diff --git a/test/generators/java/JavaGenerator.spec.ts b/test/generators/java/JavaGenerator.spec.ts index ee88e35b71..42128947d7 100644 --- a/test/generators/java/JavaGenerator.spec.ts +++ b/test/generators/java/JavaGenerator.spec.ts @@ -1,9 +1,9 @@ import { - JavaGenerator, JAVA_COMMON_PRESET, JAVA_CONSTRAINTS_PRESET, JAVA_DESCRIPTION_PRESET, - JAVA_JACKSON_PRESET + JAVA_JACKSON_PRESET, + JavaGenerator } from '../../../src/generators'; describe('JavaGenerator', () => { @@ -282,7 +282,7 @@ describe('JavaGenerator', () => { }); describe('allowInheritance', () => { - test('should create interface for Pet and CloudEvent', async () => { + test('should create interface for Animal, Pet and Dog', async () => { const asyncapiDoc = { asyncapi: '2.5.0', info: { @@ -290,12 +290,12 @@ describe('JavaGenerator', () => { version: '1.0.0' }, channels: { - pet: { + animal: { publish: { message: { oneOf: [ { - $ref: '#/components/messages/Dog' + $ref: '#/components/messages/Boxer' }, { $ref: '#/components/messages/Cat' @@ -307,96 +307,58 @@ describe('JavaGenerator', () => { }, components: { messages: { - Dog: { + Boxer: { payload: { - title: 'Dog', - allOf: [ - { - $ref: '#/components/schemas/CloudEvent' - }, - { - type: 'object', - properties: { - type: { - const: 'Dog' - }, - data: { - type: 'string' - }, - test: { - $ref: '#/components/schemas/TestAllOf' - } - } - } - ] + $ref: '#/components/schemas/Boxer' } }, Cat: { payload: { - title: 'Cat', - allOf: [ - { - $ref: '#/components/schemas/CloudEvent' - }, - { - type: 'object', - properties: { - type: { - const: 'Cat' - }, - test: { - $ref: '#/components/schemas/Test' - } - } - } - ] + $ref: '#/components/schemas/Cat' } } }, schemas: { - CloudEvent: { - title: 'CloudEvent', + Pet: { + title: 'Pet', type: 'object', - discriminator: 'type', + discriminator: 'petType', properties: { - id: { + petType: { type: 'string' - }, - type: { - title: 'CloudEventType', - type: 'string', - description: 'test' - }, - sequencetype: { - title: 'CloudEvent.SequenceType', - type: 'string', - enum: ['Integer'] } }, - required: ['id', 'type'] + required: ['type'] }, - Test: { - title: 'Test', - type: 'object', - properties: { - testProp: { - type: 'string' + Cat: { + title: 'Cat', + allOf: [ + { + $ref: '#/components/schemas/Pet' } - } + ] }, - TestAllOf: { - title: 'TestAllOf', + Dog: { + title: 'Dog', allOf: [ - { $ref: '#/components/schemas/Test' }, { - type: 'object', - properties: { - testProp2: { - type: 'string' - } - } + $ref: '#/components/schemas/Pet' } ] + }, + Boxer: { + title: 'Boxer', + type: 'object', + allOf: [ + { + $ref: '#/components/schemas/Dog' + } + ], + properties: { + breed: { + const: 'Boxer' + } + } } } } diff --git a/test/generators/java/__snapshots__/JavaGenerator.spec.ts.snap b/test/generators/java/__snapshots__/JavaGenerator.spec.ts.snap index f031f078bf..2b0f4ddba8 100644 --- a/test/generators/java/__snapshots__/JavaGenerator.spec.ts.snap +++ b/test/generators/java/__snapshots__/JavaGenerator.spec.ts.snap @@ -1,177 +1,34 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`JavaGenerator allowInheritance should create interface for Pet and CloudEvent 1`] = ` +exports[`JavaGenerator allowInheritance should create interface for Animal, Pet and Dog 1`] = ` Array [ - "@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.EXISTING_PROPERTY, property=\\"type\\", visible=true) + "@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.EXISTING_PROPERTY, property=\\"petType\\", visible=true) @JsonSubTypes({ - @JsonSubTypes.Type(value = Dog.class, name = \\"Dog\\"), + @JsonSubTypes.Type(value = Boxer.class, name = \\"Boxer\\"), @JsonSubTypes.Type(value = Cat.class, name = \\"Cat\\") }) /** - * Pet represents a union of types: Dog, Cat + * Animal represents a union of types: Boxer, Cat */ -public interface Pet { - CloudEventType getType(); +public interface Animal { + String getPetType(); }", - "public class Dog implements Pet, CloudEvent { - @NotNull - @JsonProperty(\\"id\\") - private String id; - @NotNull - @JsonProperty(\\"type\\") - private final CloudEventType type = CloudEventType.DOG; - @JsonProperty(\\"sequencetype\\") - @JsonInclude(JsonInclude.Include.NON_NULL) - private CloudEventDotSequenceType sequencetype; - @JsonProperty(\\"data\\") + "public class Boxer implements Animal, Dog { + @JsonProperty(\\"breed\\") @JsonInclude(JsonInclude.Include.NON_NULL) - private String data; - @JsonProperty(\\"test\\") + private final String breed = \\"Boxer\\"; + @JsonProperty(\\"petType\\") @JsonInclude(JsonInclude.Include.NON_NULL) - private TestAllOf test; + private String petType; @JsonInclude(JsonInclude.Include.NON_NULL) private Map additionalProperties; - @Override - public String getId() { return this.id; } - @Override - public void setId(String id) { this.id = id; } - - public CloudEventType getType() { return this.type; } + public String getBreed() { return this.breed; } @Override - public CloudEventDotSequenceType getSequencetype() { return this.sequencetype; } - @Override - public void setSequencetype(CloudEventDotSequenceType sequencetype) { this.sequencetype = sequencetype; } - - public String getData() { return this.data; } - public void setData(String data) { this.data = data; } - - public TestAllOf getTest() { return this.test; } - public void setTest(TestAllOf test) { this.test = test; } - - public Map getAdditionalProperties() { return this.additionalProperties; } - public void setAdditionalProperties(Map additionalProperties) { this.additionalProperties = additionalProperties; } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Dog self = (Dog) o; - return - Objects.equals(this.id, self.id) && - Objects.equals(this.type, self.type) && - Objects.equals(this.sequencetype, self.sequencetype) && - Objects.equals(this.data, self.data) && - Objects.equals(this.test, self.test) && - Objects.equals(this.additionalProperties, self.additionalProperties); - } - - @Override - public int hashCode() { - return Objects.hash((Object)id, (Object)type, (Object)sequencetype, (Object)data, (Object)test, (Object)additionalProperties); - } - - @Override - public String toString() { - return \\"class Dog {\\\\n\\" + - \\" id: \\" + toIndentedString(id) + \\"\\\\n\\" + - \\" type: \\" + toIndentedString(type) + \\"\\\\n\\" + - \\" sequencetype: \\" + toIndentedString(sequencetype) + \\"\\\\n\\" + - \\" data: \\" + toIndentedString(data) + \\"\\\\n\\" + - \\" test: \\" + toIndentedString(test) + \\"\\\\n\\" + - \\" additionalProperties: \\" + toIndentedString(additionalProperties) + \\"\\\\n\\" + - \\"}\\"; - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return \\"null\\"; - } - return o.toString().replace(\\"\\\\n\\", \\"\\\\n \\"); - } -}", - "public enum CloudEventType { - DOG((String)\\"Dog\\"), CAT((String)\\"Cat\\"); - - private String value; - - CloudEventType(String value) { - this.value = value; - } - - @JsonValue - public String getValue() { - return value; - } - - @JsonCreator - public static CloudEventType fromValue(String value) { - for (CloudEventType e : CloudEventType.values()) { - if (e.value.equals(value)) { - return e; - } - } - throw new IllegalArgumentException(\\"Unexpected value '\\" + value + \\"'\\"); - } - - @Override - public String toString() { - return String.valueOf(value); - } -}", - "public enum CloudEventDotSequenceType { - INTEGER((String)\\"Integer\\"); - - private String value; - - CloudEventDotSequenceType(String value) { - this.value = value; - } - - @JsonValue - public String getValue() { - return value; - } - - @JsonCreator - public static CloudEventDotSequenceType fromValue(String value) { - for (CloudEventDotSequenceType e : CloudEventDotSequenceType.values()) { - if (e.value.equals(value)) { - return e; - } - } - throw new IllegalArgumentException(\\"Unexpected value '\\" + value + \\"'\\"); - } - + public String getPetType() { return this.petType; } @Override - public String toString() { - return String.valueOf(value); - } -}", - "public class TestAllOf { - @JsonProperty(\\"testProp\\") - @JsonInclude(JsonInclude.Include.NON_NULL) - private String testProp; - @JsonProperty(\\"testProp2\\") - @JsonInclude(JsonInclude.Include.NON_NULL) - private String testProp2; - @JsonInclude(JsonInclude.Include.NON_NULL) - private Map additionalProperties; - - public String getTestProp() { return this.testProp; } - public void setTestProp(String testProp) { this.testProp = testProp; } - - public String getTestProp2() { return this.testProp2; } - public void setTestProp2(String testProp2) { this.testProp2 = testProp2; } + public void setPetType(String petType) { this.petType = petType; } public Map getAdditionalProperties() { return this.additionalProperties; } public void setAdditionalProperties(Map additionalProperties) { this.additionalProperties = additionalProperties; } @@ -184,23 +41,23 @@ public interface Pet { if (o == null || getClass() != o.getClass()) { return false; } - TestAllOf self = (TestAllOf) o; + Boxer self = (Boxer) o; return - Objects.equals(this.testProp, self.testProp) && - Objects.equals(this.testProp2, self.testProp2) && + Objects.equals(this.breed, self.breed) && + Objects.equals(this.petType, self.petType) && Objects.equals(this.additionalProperties, self.additionalProperties); } @Override public int hashCode() { - return Objects.hash((Object)testProp, (Object)testProp2, (Object)additionalProperties); + return Objects.hash((Object)breed, (Object)petType, (Object)additionalProperties); } @Override public String toString() { - return \\"class TestAllOf {\\\\n\\" + - \\" testProp: \\" + toIndentedString(testProp) + \\"\\\\n\\" + - \\" testProp2: \\" + toIndentedString(testProp2) + \\"\\\\n\\" + + return \\"class Boxer {\\\\n\\" + + \\" breed: \\" + toIndentedString(breed) + \\"\\\\n\\" + + \\" petType: \\" + toIndentedString(petType) + \\"\\\\n\\" + \\" additionalProperties: \\" + toIndentedString(additionalProperties) + \\"\\\\n\\" + \\"}\\"; } @@ -216,94 +73,21 @@ public interface Pet { return o.toString().replace(\\"\\\\n\\", \\"\\\\n \\"); } }", - "public class Test { - @JsonProperty(\\"testProp\\") - @JsonInclude(JsonInclude.Include.NON_NULL) - private String testProp; - @JsonInclude(JsonInclude.Include.NON_NULL) - private Map additionalProperties; - - public String getTestProp() { return this.testProp; } - public void setTestProp(String testProp) { this.testProp = testProp; } - - public Map getAdditionalProperties() { return this.additionalProperties; } - public void setAdditionalProperties(Map additionalProperties) { this.additionalProperties = additionalProperties; } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Test self = (Test) o; - return - Objects.equals(this.testProp, self.testProp) && - Objects.equals(this.additionalProperties, self.additionalProperties); - } - - @Override - public int hashCode() { - return Objects.hash((Object)testProp, (Object)additionalProperties); - } - - @Override - public String toString() { - return \\"class Test {\\\\n\\" + - \\" testProp: \\" + toIndentedString(testProp) + \\"\\\\n\\" + - \\" additionalProperties: \\" + toIndentedString(additionalProperties) + \\"\\\\n\\" + - \\"}\\"; - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return \\"null\\"; - } - return o.toString().replace(\\"\\\\n\\", \\"\\\\n \\"); - } + "public interface Dog extends Pet { + }", - "public interface CloudEvent { - public String getId(); - public void setId(String id); - - public CloudEventDotSequenceType getSequencetype(); - public void setSequencetype(CloudEventDotSequenceType sequencetype); + "public interface Pet { + }", - "public class Cat implements Pet, CloudEvent { - @NotNull - @JsonProperty(\\"id\\") - private String id; - @NotNull - @JsonProperty(\\"type\\") - private final CloudEventType type = CloudEventType.CAT; - @JsonProperty(\\"sequencetype\\") - @JsonInclude(JsonInclude.Include.NON_NULL) - private CloudEventDotSequenceType sequencetype; - @JsonProperty(\\"test\\") + "public class Cat implements Animal, Pet { + @JsonProperty(\\"petType\\") @JsonInclude(JsonInclude.Include.NON_NULL) - private Test test; + private String petType; @JsonInclude(JsonInclude.Include.NON_NULL) private Map additionalProperties; - @Override - public String getId() { return this.id; } - @Override - public void setId(String id) { this.id = id; } - - public CloudEventType getType() { return this.type; } - - @Override - public CloudEventDotSequenceType getSequencetype() { return this.sequencetype; } - @Override - public void setSequencetype(CloudEventDotSequenceType sequencetype) { this.sequencetype = sequencetype; } - - public Test getTest() { return this.test; } - public void setTest(Test test) { this.test = test; } + public String getPetType() { return this.petType; } + public void setPetType(String petType) { this.petType = petType; } public Map getAdditionalProperties() { return this.additionalProperties; } public void setAdditionalProperties(Map additionalProperties) { this.additionalProperties = additionalProperties; } @@ -318,25 +102,19 @@ public interface Pet { } Cat self = (Cat) o; return - Objects.equals(this.id, self.id) && - Objects.equals(this.type, self.type) && - Objects.equals(this.sequencetype, self.sequencetype) && - Objects.equals(this.test, self.test) && + Objects.equals(this.petType, self.petType) && Objects.equals(this.additionalProperties, self.additionalProperties); } @Override public int hashCode() { - return Objects.hash((Object)id, (Object)type, (Object)sequencetype, (Object)test, (Object)additionalProperties); + return Objects.hash((Object)petType, (Object)additionalProperties); } @Override public String toString() { return \\"class Cat {\\\\n\\" + - \\" id: \\" + toIndentedString(id) + \\"\\\\n\\" + - \\" type: \\" + toIndentedString(type) + \\"\\\\n\\" + - \\" sequencetype: \\" + toIndentedString(sequencetype) + \\"\\\\n\\" + - \\" test: \\" + toIndentedString(test) + \\"\\\\n\\" + + \\" petType: \\" + toIndentedString(petType) + \\"\\\\n\\" + \\" additionalProperties: \\" + toIndentedString(additionalProperties) + \\"\\\\n\\" + \\"}\\"; }