Repository: asyncapi/modelina (ts)

Issue:
Java generator always adds @Json annotations for enums
@micro-jumbo commented on [Thu Jul 14 2022](https://github.com/asyncapi/spec/issues/822)

### Describe the bug
Java generator always adds @Json annotations for enums

### To Reproduce
For document:
```json
{
  "asyncapi": "2.3.0",
  "id": "urn:my:service",
  "defaultContentType": "application/json",
  "info": {
    "title": "My services",
    "version": "1.0.0"
  },
  "channels": {
    "accepted": {
      "subscribe": {
        "message": {
          "name": "SuccessMessage",
          "title": "SuccessMessage",
          "payload": {
            "type": "object",
            "title": "SuccessMessage",
            "properties": {
              "result": {
                "title": "SuccessMessageResult",
                "type": "string",
                "const": "SUCCESS"
              },
              "message": {
                "type": "string",
                "title": "SuccessMessageMessage"
              }
            },
            "required": [
              "result"
            ],
            "additionalProperties": false
          }
        }
      }
    }
  }
}
```

and generator:
```javascript
const generator = new JavaGenerator({
  collectionType: "List",
});
```

generated `SuccessMessageMessage` `enum` contains Jackson annotations (`@JsonValue` and `@JsonCreator`), but it shouldn't:
```java
import com.fasterxml.jackson.annotation.*;

public enum SuccessMessageResult {
  SUCCESS("SUCCESS");

  private String value;

  SuccessMessageResult(String value) {
    this.value = value;
  }
    
  @JsonValue
  public String getValue() {
    return value;
  }

  @Override
  public String toString() {
    return String.valueOf(value);
  }

  @JsonCreator
  public static SuccessMessageResult fromValue(String value) {
    for (SuccessMessageResult e : SuccessMessageResult.values()) {
      if (e.value.equals(value)) {
        return e;
      }
    }
    throw new IllegalArgumentException("Unexpected value '" + value + "'");
  }
}
```

These should be generated only when Jackson annotations are enabled.


---

@github-actions[bot] commented on [Thu Jul 14 2022](https://github.com/asyncapi/spec/issues/822#issuecomment-1184728142)

Welcome to AsyncAPI. Thanks a lot for reporting your first issue. Please check out our [contributors guide](https://github.com/asyncapi/community/blob/master/CONTRIBUTING.md) and the instructions about a [basic recommended setup](https://github.com/asyncapi/.github/blob/master/git-workflow.md) useful for opening a pull request.<br />Keep in mind there are also other channels you can use to interact with AsyncAPI community. For more details check out [this issue](https://github.com/asyncapi/asyncapi/issues/115).



Pull request description:
fix: generate Jackson annotations for Java enums only with Jackson Preset
**Description**

- generate Jackson annotations for Java enums only with Jackson Preset
- update all relevant tests

**Related issue(s)**
Fixes #812

Patch:
diff --git a/src/generators/java/JavaPreset.ts b/src/generators/java/JavaPreset.ts
index b2de02b2..b91be091 100644
--- a/src/generators/java/JavaPreset.ts
+++ b/src/generators/java/JavaPreset.ts
@@ -1,11 +1,17 @@
 /* eslint-disable @typescript-eslint/ban-types */
-import { Preset, ClassPreset, EnumPreset } from '../../models';
+import { Preset, ClassPreset, EnumPreset, PresetArgs, EnumArgs } from '../../models';
 import { ClassRenderer, JAVA_DEFAULT_CLASS_PRESET } from './renderers/ClassRenderer';
 import { EnumRenderer, JAVA_DEFAULT_ENUM_PRESET } from './renderers/EnumRenderer';
 
+export interface JavaEnumPreset<O extends object = any> extends EnumPreset<EnumRenderer, O> {
+  ctor?: (args: PresetArgs<EnumRenderer, O> & EnumArgs) => string;
+  getValue?: (args: PresetArgs<EnumRenderer, O> & EnumArgs) => string;
+  fromValue?: (args: PresetArgs<EnumRenderer, O> & EnumArgs) => string;
+}
+
 export type JavaPreset<O extends object = any> = Preset<{
   class: ClassPreset<ClassRenderer, O>;
-  enum: EnumPreset<EnumRenderer, O>;
+  enum: JavaEnumPreset<O>;
 }>;
 
 export const JAVA_DEFAULT_PRESET: JavaPreset = {
diff --git a/src/generators/java/presets/JacksonPreset.ts b/src/generators/java/presets/JacksonPreset.ts
index 2038ef6a..1e480e40 100644
--- a/src/generators/java/presets/JacksonPreset.ts
+++ b/src/generators/java/presets/JacksonPreset.ts
@@ -3,7 +3,7 @@ import { JavaPreset } from '../JavaPreset';
 
 /**
  * Preset which adds `com.fasterxml.jackson` related annotations to class's property getters.
- * 
+ *
  * @implements {JavaPreset}
  */
 export const JAVA_JACKSON_PRESET: JavaPreset = {
@@ -12,12 +12,26 @@ export const JAVA_JACKSON_PRESET: JavaPreset = {
       renderer.addDependency('import com.fasterxml.jackson.annotation.*;');
       return content;
     },
-    getter({ renderer, propertyName, content, type }) {
+    getter({renderer, propertyName, content, type}) {
       if (type === PropertyType.property) {
         const annotation = renderer.renderAnnotation('JsonProperty', `"${propertyName}"`);
         return renderer.renderBlock([annotation, content]);
       }
       return renderer.renderBlock([content]);
     },
+  },
+  enum: {
+    self({renderer, content}) {
+      renderer.addDependency('import com.fasterxml.jackson.annotation.*;');
+      return content;
+    },
+    getValue({content}) {
+      return `@JsonValue
+${content}`;
+    },
+    fromValue({content}) {
+      return `@JsonCreator
+${content}`;
+    },
   }
 };
diff --git a/src/generators/java/renderers/EnumRenderer.ts b/src/generators/java/renderers/EnumRenderer.ts
index 858fd776..20b59e66 100644
--- a/src/generators/java/renderers/EnumRenderer.ts
+++ b/src/generators/java/renderers/EnumRenderer.ts
@@ -1,16 +1,19 @@
 import { JavaRenderer } from '../JavaRenderer';
-import { EnumPreset } from '../../../models';
 import { FormatHelpers } from '../../../helpers';
+import { JavaEnumPreset } from '../JavaPreset';
 
 /**
  * Renderer for Java's `enum` type
- * 
+ *
  * @extends JavaRenderer
  */
 export class EnumRenderer extends JavaRenderer {
   async defaultSelf(): Promise<string> {
     const content = [
       await this.renderItems(),
+      await this.runCtorPreset(),
+      await this.runGetValuePreset(),
+      await this.runFromValuePreset(),
       await this.runAdditionalContentPreset()
     ];
     const formattedName = this.nameType(this.model.$id);
@@ -49,7 +52,7 @@ ${this.indent(this.renderBlock(content, 2))}
       break;
     }
     default: {
-      key = FormatHelpers.replaceSpecialCharacters(String(value), { exclude: [' ', '_'], separator: '_' });
+      key = FormatHelpers.replaceSpecialCharacters(String(value), {exclude: [' ', '_'], separator: '_'});
       //Ensure no special char can be the beginning letter 
       if (!(/^[a-zA-Z]+$/).test(key.charAt(0))) {
         key = `string_${key}`;
@@ -70,43 +73,53 @@ ${this.indent(this.renderBlock(content, 2))}
   }
 
   runItemPreset(item: any): Promise<string> {
-    return this.runPreset('item', { item });
+    return this.runPreset('item', {item});
+  }
+
+  runCtorPreset(): Promise<string> {
+    return this.runPreset('ctor');
+  }
+
+  runGetValuePreset(): Promise<string> {
+    return this.runPreset('getValue');
+  }
+
+  runFromValuePreset(): Promise<string> {
+    return this.runPreset('fromValue');
   }
 }
 
-export const JAVA_DEFAULT_ENUM_PRESET: EnumPreset<EnumRenderer> = {
-  self({ renderer }) {
-    renderer.addDependency('import com.fasterxml.jackson.annotation.*;');
+export const JAVA_DEFAULT_ENUM_PRESET: JavaEnumPreset = {
+  self({renderer}) {
     return renderer.defaultSelf();
   },
-  item({ renderer, item }) {
+  item({renderer, item}) {
     const key = renderer.normalizeKey(item);
     const value = renderer.normalizeValue(item);
     return `${key}(${value})`;
   },
-  additionalContent({ renderer, model }) {
+  ctor({renderer, model}) {
     const enumName = renderer.nameType(model.$id);
     const type = Array.isArray(model.type) ? 'Object' : model.type;
     const classType = renderer.toClassType(renderer.toJavaType(type, model));
-
     return `private ${classType} value;
 
 ${enumName}(${classType} value) {
   this.value = value;
-}
-    
-@JsonValue
-public ${classType} getValue() {
+}`;
+  },
+  getValue({renderer, model}) {
+    const type = Array.isArray(model.type) ? 'Object' : model.type;
+    const classType = renderer.toClassType(renderer.toJavaType(type, model));
+    return `public ${classType} getValue() {
   return value;
-}
-
-@Override
-public String toString() {
-  return String.valueOf(value);
-}
-
-@JsonCreator
-public static ${enumName} fromValue(${classType} value) {
+}`;
+  },
+  fromValue({renderer, model}) {
+    const enumName = renderer.nameType(model.$id);
+    const type = Array.isArray(model.type) ? 'Object' : model.type;
+    const classType = renderer.toClassType(renderer.toJavaType(type, model));
+    return `public static ${enumName} fromValue(${classType} value) {
   for (${enumName} e : ${enumName}.values()) {
     if (e.value.equals(value)) {
       return e;
@@ -115,4 +128,10 @@ public static ${enumName} fromValue(${classType} value) {
   throw new IllegalArgumentException("Unexpected value '" + value + "'");
 }`;
   },
+  additionalContent() {
+    return `@Override
+public String toString() {
+  return String.valueOf(value);
+}`;
+  }
 };


Test patch:
diff --git a/test/generators/java/JavaGenerator.spec.ts b/test/generators/java/JavaGenerator.spec.ts
index fab74de8..14dfa887 100644
--- a/test/generators/java/JavaGenerator.spec.ts
+++ b/test/generators/java/JavaGenerator.spec.ts
@@ -182,18 +182,11 @@ describe('JavaGenerator', () => {
   States(String value) {
     this.value = value;
   }
-    
-  @JsonValue
+
   public String getValue() {
     return value;
   }
 
-  @Override
-  public String toString() {
-    return String.valueOf(value);
-  }
-
-  @JsonCreator
   public static States fromValue(String value) {
     for (States e : States.values()) {
       if (e.value.equals(value)) {
@@ -202,19 +195,23 @@ describe('JavaGenerator', () => {
     }
     throw new IllegalArgumentException("Unexpected value '" + value + "'");
   }
+
+  @Override
+  public String toString() {
+    return String.valueOf(value);
+  }
 }`;
 
     const inputModel = await generator.process(doc);
     const model = inputModel.models['States'];
 
     let enumModel = await generator.renderEnum(model, inputModel);
-    const expectedDependencies = ['import com.fasterxml.jackson.annotation.*;'];
     expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual(expectedDependencies);
+    expect(enumModel.dependencies.length).toEqual(0);
 
     enumModel = await generator.render(model, inputModel);
     expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual(expectedDependencies);
+    expect(enumModel.dependencies.length).toEqual(0);
   });
 
   test('should render `enum` type (integer type)', async () => {
@@ -231,18 +228,11 @@ describe('JavaGenerator', () => {
   Numbers(Integer value) {
     this.value = value;
   }
-    
-  @JsonValue
+
   public Integer getValue() {
     return value;
   }
 
-  @Override
-  public String toString() {
-    return String.valueOf(value);
-  }
-
-  @JsonCreator
   public static Numbers fromValue(Integer value) {
     for (Numbers e : Numbers.values()) {
       if (e.value.equals(value)) {
@@ -251,19 +241,23 @@ describe('JavaGenerator', () => {
     }
     throw new IllegalArgumentException("Unexpected value '" + value + "'");
   }
+
+  @Override
+  public String toString() {
+    return String.valueOf(value);
+  }
 }`;
 
     const inputModel = await generator.process(doc);
     const model = inputModel.models['Numbers'];
 
     let enumModel = await generator.renderEnum(model, inputModel);
-    const expectedDependencies = ['import com.fasterxml.jackson.annotation.*;'];
     expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual(expectedDependencies);
+    expect(enumModel.dependencies.length).toEqual(0);
 
     enumModel = await generator.render(model, inputModel);
     expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual(expectedDependencies);
+    expect(enumModel.dependencies.length).toEqual(0);
   });
 
   test('should render `enum` type (union type)', async () => {
@@ -280,18 +274,11 @@ describe('JavaGenerator', () => {
   Union(Object value) {
     this.value = value;
   }
-    
-  @JsonValue
+
   public Object getValue() {
     return value;
   }
 
-  @Override
-  public String toString() {
-    return String.valueOf(value);
-  }
-
-  @JsonCreator
   public static Union fromValue(Object value) {
     for (Union e : Union.values()) {
       if (e.value.equals(value)) {
@@ -300,19 +287,23 @@ describe('JavaGenerator', () => {
     }
     throw new IllegalArgumentException("Unexpected value '" + value + "'");
   }
+
+  @Override
+  public String toString() {
+    return String.valueOf(value);
+  }
 }`;
 
     const inputModel = await generator.process(doc);
     const model = inputModel.models['Union'];
 
     let enumModel = await generator.renderEnum(model, inputModel);
-    const expectedDependencies = ['import com.fasterxml.jackson.annotation.*;'];
     expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual(expectedDependencies);
+    expect(enumModel.dependencies.length).toEqual(0);
 
     enumModel = await generator.render(model, inputModel);
     expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual(expectedDependencies);
+    expect(enumModel.dependencies.length).toEqual(0);
   });
 
   test('should render custom preset for `enum` type', async () => {
@@ -330,18 +321,11 @@ public enum CustomEnum {
   CustomEnum(String value) {
     this.value = value;
   }
-    
-  @JsonValue
+
   public String getValue() {
     return value;
   }
 
-  @Override
-  public String toString() {
-    return String.valueOf(value);
-  }
-
-  @JsonCreator
   public static CustomEnum fromValue(String value) {
     for (CustomEnum e : CustomEnum.values()) {
       if (e.value.equals(value)) {
@@ -350,6 +334,11 @@ public enum CustomEnum {
     }
     throw new IllegalArgumentException("Unexpected value '" + value + "'");
   }
+
+  @Override
+  public String toString() {
+    return String.valueOf(value);
+  }
 }`;
 
     generator = new JavaGenerator({ presets: [
@@ -367,13 +356,12 @@ public enum CustomEnum {
     const model = inputModel.models['CustomEnum'];
     
     let enumModel = await generator.render(model, inputModel);
-    const expectedDependencies = ['import com.fasterxml.jackson.annotation.*;'];
     expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual(expectedDependencies);
+    expect(enumModel.dependencies.length).toEqual(0);
     
     enumModel = await generator.renderEnum(model, inputModel);
     expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual(expectedDependencies);
+    expect(enumModel.dependencies.length).toEqual(0);
   });
 
   test('should render enums with translated special characters', async () => {
@@ -389,18 +377,11 @@ public enum CustomEnum {
   States(String value) {
     this.value = value;
   }
-    
-  @JsonValue
+
   public String getValue() {
     return value;
   }
 
-  @Override
-  public String toString() {
-    return String.valueOf(value);
-  }
-
-  @JsonCreator
   public static States fromValue(String value) {
     for (States e : States.values()) {
       if (e.value.equals(value)) {
@@ -409,19 +390,23 @@ public enum CustomEnum {
     }
     throw new IllegalArgumentException("Unexpected value '" + value + "'");
   }
+
+  @Override
+  public String toString() {
+    return String.valueOf(value);
+  }
 }`;
 
     const inputModel = await generator.process(doc);
     const model = inputModel.models['States'];
 
     let enumModel = await generator.renderEnum(model, inputModel);
-    const expectedDependencies = ['import com.fasterxml.jackson.annotation.*;'];
     expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual(expectedDependencies);
+    expect(enumModel.dependencies.length).toEqual(0);
 
     enumModel = await generator.render(model, inputModel);
     expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual(expectedDependencies);
+    expect(enumModel.dependencies.length).toEqual(0);
   });
 
   test('should render List type for collections', async () => {
diff --git a/test/generators/java/presets/DescriptionPreset.spec.ts b/test/generators/java/presets/DescriptionPreset.spec.ts
index df59929f..5c3e7c81 100644
--- a/test/generators/java/presets/DescriptionPreset.spec.ts
+++ b/test/generators/java/presets/DescriptionPreset.spec.ts
@@ -67,18 +67,11 @@ public enum Enum {
   Enum(String value) {
     this.value = value;
   }
-    
-  @JsonValue
+
   public String getValue() {
     return value;
   }
 
-  @Override
-  public String toString() {
-    return String.valueOf(value);
-  }
-
-  @JsonCreator
   public static Enum fromValue(String value) {
     for (Enum e : Enum.values()) {
       if (e.value.equals(value)) {
@@ -87,6 +80,11 @@ public enum Enum {
     }
     throw new IllegalArgumentException("Unexpected value '" + value + "'");
   }
+
+  @Override
+  public String toString() {
+    return String.valueOf(value);
+  }
 }`;
 
     const inputModel = await generator.process(doc);
@@ -94,6 +92,6 @@ public enum Enum {
 
     const enumModel = await generator.renderEnum(model, inputModel);
     expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual(['import com.fasterxml.jackson.annotation.*;']);
+    expect(enumModel.dependencies).toEqual([]);
   });
 });
diff --git a/test/generators/java/presets/JacksonPreset.spec.ts b/test/generators/java/presets/JacksonPreset.spec.ts
index fdf13838..a22768e1 100644
--- a/test/generators/java/presets/JacksonPreset.spec.ts
+++ b/test/generators/java/presets/JacksonPreset.spec.ts
@@ -6,7 +6,7 @@ describe('JAVA_JACKSON_PRESET', () => {
     generator = new JavaGenerator({ presets: [JAVA_JACKSON_PRESET] });
   });
 
-  test('should render Jackson annotations', async () => {
+  test('should render Jackson annotations for class', async () => {
     const doc = {
       $id: 'Clazz',
       type: 'object',
@@ -40,4 +40,53 @@ describe('JAVA_JACKSON_PRESET', () => {
     expect(classModel.result).toEqual(expected);
     expect(classModel.dependencies).toEqual(expectedDependencies);
   });
+
+  test('should render Jackson annotations for enum', async () => {
+    const doc = {
+      $id: 'Enum',
+      type: 'string',
+      description: 'Description for enum',
+      examples: ['value'],
+      enum: [
+        'on',
+        'off',
+      ]
+    };
+    const expected = `public enum Enum {
+  ON("on"), OFF("off");
+
+  private String value;
+
+  Enum(String value) {
+    this.value = value;
+  }
+
+  @JsonValue
+  public String getValue() {
+    return value;
+  }
+
+  @JsonCreator
+  public static Enum fromValue(String value) {
+    for (Enum e : Enum.values()) {
+      if (e.value.equals(value)) {
+        return e;
+      }
+    }
+    throw new IllegalArgumentException("Unexpected value '" + value + "'");
+  }
+
+  @Override
+  public String toString() {
+    return String.valueOf(value);
+  }
+}`;
+
+    const inputModel = await generator.process(doc);
+    const model = inputModel.models['Enum'];
+
+    const enumModel = await generator.renderEnum(model, inputModel);
+    expect(enumModel.result).toEqual(expected);
+    expect(enumModel.dependencies).toEqual(['import com.fasterxml.jackson.annotation.*;']);
+  });
 });