Repository: asyncapi/modelina (ts)

Issue:
Java equals and hashcode breaks compilation
When generating a java model including equals and hashcode settings, the resulting files break compilation.

The reason is that equals is generated using `Objects.equals` util method, but the relative `import java.util.Objects` is omitted.

Sample repo: https://github.com/ThanksForAllTheFish/modelinabug

How to reproduce once cloned:

- `npm ci`
- `npm run generate`
- check files in `java/org/t4atf/asyncapi`, equals and hashcode are properly implemented, but the import is missing

Verified against latest modelina npm package (0.39.4)

Pull request:
fix: ensure JavaCommonPreset can be compiled 
**Description**
This PR cleans up the JavaCommonPreset a bit and fixes a couple of bugs.

- Fixed that we always assumed `additionalProperties` where needed.
- Fixed that if no properties are present it renders accurately.
- Fixed properties with type array did not work.
- Added BlackBox tests for different generator options, which now tests the preset.

**Related issue(s)**
Fixes #510 

Patch:
diff --git a/examples/java-generate-tostring/__snapshots__/index.spec.ts.snap b/examples/java-generate-tostring/__snapshots__/index.spec.ts.snap
index 6d6d3d9e..b31b9907 100644
--- a/examples/java-generate-tostring/__snapshots__/index.spec.ts.snap
+++ b/examples/java-generate-tostring/__snapshots__/index.spec.ts.snap
@@ -12,7 +12,6 @@ Array [
   public String toString() {
     return \\"class Root {\\\\n\\" +   
       \\"    email: \\" + toIndentedString(email) + \\"\\\\n\\" +
-      \\"    additionalProperties: \\" + toIndentedString(additionalProperties) + \\"\\\\n\\" +
     \\"}\\";
   }
 
diff --git a/src/generators/java/presets/CommonPreset.ts b/src/generators/java/presets/CommonPreset.ts
index 376393ca..cca41449 100644
--- a/src/generators/java/presets/CommonPreset.ts
+++ b/src/generators/java/presets/CommonPreset.ts
@@ -1,7 +1,7 @@
 import { JavaRenderer } from '../JavaRenderer';
 import { JavaPreset } from '../JavaPreset';
 
-import { getUniquePropertyName, FormatHelpers, DefaultPropertyNames } from '../../../helpers';
+import { getUniquePropertyName, DefaultPropertyNames } from '../../../helpers';
 import { CommonModel } from '../../../models';
 
 export interface JavaCommonPresetOptions {
@@ -19,9 +19,12 @@ function renderEqual({ renderer, model }: {
 }): string {
   const formattedModelName = renderer.nameType(model.$id);
   const properties = model.properties || {};
-  const propertyKeys = [...Object.keys(properties), getUniquePropertyName(model, DefaultPropertyNames.additionalProperties)];
+  const propertyKeys = [...Object.keys(properties)];
+  if (model.additionalProperties !== undefined) {
+    propertyKeys.push(getUniquePropertyName(model, DefaultPropertyNames.additionalProperties));
+  }
   const equalProperties = propertyKeys.map(prop => {
-    const camelCasedProp = FormatHelpers.toCamelCase(prop);
+    const camelCasedProp = renderer.nameProperty(prop);
     return `Objects.equals(this.${camelCasedProp}, self.${camelCasedProp})`;
   }).join(' &&\n');
 
@@ -35,7 +38,7 @@ public boolean equals(Object o) {
   }
   ${formattedModelName} self = (${formattedModelName}) o;
     return 
-${renderer.indent(equalProperties, 6)};
+${equalProperties.length > 0 ? renderer.indent(equalProperties, 6) : 'true'};
 }`;
 } 
 
@@ -47,8 +50,12 @@ function renderHashCode({ renderer, model }: {
   model: CommonModel,
 }): string {
   const properties = model.properties || {};
-  const propertyKeys = [...Object.keys(properties), getUniquePropertyName(model, DefaultPropertyNames.additionalProperties)];
-  const hashProperties = propertyKeys.map(prop => FormatHelpers.toCamelCase(prop)).join(', ');
+  const propertyKeys = [...Object.keys(properties)];
+  if (model.additionalProperties !== undefined) {
+    propertyKeys.push(getUniquePropertyName(model, DefaultPropertyNames.additionalProperties));
+  }
+  //Object casting needed because otherwise properties with arrays fails to be compiled.
+  const hashProperties = propertyKeys.map(prop => `(Object)${renderer.nameProperty(prop)}`).join(', ');
 
   return `${renderer.renderAnnotation('Override')}
 public int hashCode() {
@@ -65,15 +72,19 @@ function renderToString({ renderer, model }: {
 }): string {
   const formattedModelName = renderer.nameType(model.$id);
   const properties = model.properties || {};
-  const propertyKeys = [...Object.keys(properties), getUniquePropertyName(model, DefaultPropertyNames.additionalProperties)];
-  const toStringProperties = propertyKeys.map(prop => 
-    `"    ${renderer.nameProperty(prop)}: " + toIndentedString(${FormatHelpers.toCamelCase(prop)}) + "\\n" +`
-  );
+  const propertyKeys = [...Object.keys(properties)];
+  if (model.additionalProperties !== undefined) {
+    propertyKeys.push(getUniquePropertyName(model, DefaultPropertyNames.additionalProperties));
+  }
+  const toStringProperties = propertyKeys.map(prop => { 
+    const renderedPropertyName = renderer.nameProperty(prop);
+    return `"    ${renderedPropertyName}: " + toIndentedString(${renderedPropertyName}) + "\\n" +`;
+  });
 
   return `${renderer.renderAnnotation('Override')}
 public String toString() {
   return "class ${formattedModelName} {\\n" +   
-${renderer.indent(renderer.renderBlock(toStringProperties), 4)}
+${toStringProperties.length > 0 ? renderer.indent(renderer.renderBlock(toStringProperties), 4) : ''}
   "}";
 }
 
@@ -96,10 +107,17 @@ export const JAVA_COMMON_PRESET: JavaPreset = {
     additionalContent({ renderer, model, content, options }) {
       options = options || {};
       const blocks: string[] = [];
-      
-      if (options.equal === undefined || options.equal === true) {blocks.push(renderEqual({ renderer, model }));}
-      if (options.hashCode === undefined || options.hashCode === true) {blocks.push(renderHashCode({ renderer, model }));}
-      if (options.classToString === undefined || options.classToString === true) {blocks.push(renderToString({ renderer, model }));}
+      const shouldContainEqual = options.equal === undefined || options.equal === true;
+      const shouldContainHashCode = options.hashCode === undefined || options.hashCode === true;
+      const shouldContainToString = options.classToString === undefined || options.classToString === true;
+
+      if (shouldContainEqual === true || shouldContainHashCode === true) {
+        renderer.addDependency('import java.util.Objects;');
+      }
+
+      if (shouldContainEqual) {blocks.push(renderEqual({ renderer, model }));}
+      if (shouldContainHashCode) {blocks.push(renderHashCode({ renderer, model }));}
+      if (shouldContainToString) {blocks.push(renderToString({ renderer, model }));}
 
       return renderer.renderBlock([content, ...blocks], 2);
     },


Test patch:
diff --git a/test/blackbox/blackbox.spec.ts b/test/blackbox/blackbox.spec.ts
index 39ba0044..6454f6bc 100644
--- a/test/blackbox/blackbox.spec.ts
+++ b/test/blackbox/blackbox.spec.ts
@@ -7,7 +7,7 @@
 
 import * as path from 'path';
 import * as fs from 'fs';
-import { TypeScriptGenerator, JavaScriptGenerator, GoGenerator, CSharpGenerator, JavaFileGenerator } from '../../src';
+import { TypeScriptGenerator, JavaScriptGenerator, GoGenerator, CSharpGenerator, JavaFileGenerator, JAVA_COMMON_PRESET } from '../../src';
 import { execCommand, generateModels, renderModels, renderModelsToSeparateFiles } from './utils/Utils';
 
 /**
@@ -88,9 +88,23 @@ describe.each(filesToTest)('Should be able to generate with inputs', ({file, out
     }
   });
   describe(file, () => {
-    describe('should be able to generate and compile Java', () => {
+    const javaGeneratorOptions = [
+      { 
+        generatorOption: { },
+        description: 'default generator'
+      },
+      { 
+        generatorOption: {
+          presets: [
+            JAVA_COMMON_PRESET
+          ]
+        },
+        description: 'all common presets'
+      }
+    ]; 
+    describe.each(javaGeneratorOptions)('should be able to generate and compile Java', ({generatorOption, description}) => {
       test('class', async () => {
-        const generator = new JavaFileGenerator();
+        const generator = new JavaFileGenerator(generatorOption);
         const inputFileContent = await fs.promises.readFile(fileToGenerateFor);
         const input = JSON.parse(String(inputFileContent));
         const renderOutputPath = path.resolve(outputDirectoryPath, './java/class');
diff --git a/test/generators/java/presets/CommonPreset.spec.ts b/test/generators/java/presets/CommonPreset.spec.ts
index 54a3f6a9..a27bda35 100644
--- a/test/generators/java/presets/CommonPreset.spec.ts
+++ b/test/generators/java/presets/CommonPreset.spec.ts
@@ -1,122 +1,113 @@
 import { JavaGenerator, JAVA_COMMON_PRESET } from '../../../../src/generators'; 
 
 describe('JAVA_COMMON_PRESET', () => {
+  const doc = {
+    $id: 'Clazz',
+    type: 'object',
+    required: ['requiredProp'],
+    properties: {
+      requiredProp: { type: 'boolean' },
+      stringProp: { type: 'string' },
+      numberProp: { type: 'number' },
+      booleanProp: { type: 'boolean' },
+      arrayProp: { type: 'array', items: { type: 'string' } },
+    },
+  };
   test('should render common function in class by common preset', async () => {
-    const doc = {
-      $id: 'Clazz',
-      type: 'object',
-      properties: {
-        stringProp: { type: 'string' },
-        numberProp: { type: 'number' },
-      },
-    };
-    const expected = `public class Clazz {
-  private String stringProp;
-  private Double numberProp;
-  private Map<String, Object> additionalProperties;
-
-  public String getStringProp() { return this.stringProp; }
-  public void setStringProp(String stringProp) { this.stringProp = stringProp; }
-
-  public Double getNumberProp() { return this.numberProp; }
-  public void setNumberProp(Double numberProp) { this.numberProp = numberProp; }
-
-  public Map<String, Object> getAdditionalProperties() { return this.additionalProperties; }
-  public void setAdditionalProperties(Map<String, Object> additionalProperties) { this.additionalProperties = additionalProperties; }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) {
-      return true;
-    }
-    if (o == null || getClass() != o.getClass()) {
-      return false;
-    }
-    Clazz self = (Clazz) o;
-      return 
-        Objects.equals(this.stringProp, self.stringProp) &&
-        Objects.equals(this.numberProp, self.numberProp) &&
-        Objects.equals(this.additionalProperties, self.additionalProperties);
-  }
-
-  @Override
-  public int hashCode() {
-    return Objects.hash(stringProp, numberProp, additionalProperties);
-  }
-
-  @Override
-  public String toString() {
-    return "class Clazz {\\n" +   
-      "    stringProp: " + toIndentedString(stringProp) + "\\n" +
-      "    numberProp: " + toIndentedString(numberProp) + "\\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    ");
-  }
-}`;
-
     const generator = new JavaGenerator({ presets: [JAVA_COMMON_PRESET] });
     const inputModel = await generator.process(doc);
     const model = inputModel.models['Clazz'];
 
     const classModel = await generator.renderClass(model, inputModel);
-    const expectedDependencies = ['import java.util.Map;'];
-    expect(classModel.result).toEqual(expected);
-    expect(classModel.dependencies).toEqual(expectedDependencies);
+    expect(classModel.result).toMatchSnapshot();
   });
-
-  test('should skip rendering of disabled functions', async () => {
-    const doc = {
-      $id: 'Clazz',
-      type: 'object',
-      properties: {
-        stringProp: { type: 'string' },
-        numberProp: { type: 'number' },
-      },
-    };
-    const expected = `public class Clazz {
-  private String stringProp;
-  private Double numberProp;
-  private Map<String, Object> additionalProperties;
-
-  public String getStringProp() { return this.stringProp; }
-  public void setStringProp(String stringProp) { this.stringProp = stringProp; }
-
-  public Double getNumberProp() { return this.numberProp; }
-  public void setNumberProp(Double numberProp) { this.numberProp = numberProp; }
-
-  public Map<String, Object> getAdditionalProperties() { return this.additionalProperties; }
-  public void setAdditionalProperties(Map<String, Object> additionalProperties) { this.additionalProperties = additionalProperties; }
-
-  @Override
-  public int hashCode() {
-    return Objects.hash(stringProp, numberProp, additionalProperties);
-  }
-}`;
-
-    const generator = new JavaGenerator({ presets: [{
-      preset: JAVA_COMMON_PRESET,
-      options: {
-        equal: false,
-        classToString: false,
-      }
-    }] });
-    const inputModel = await generator.process(doc);
+  test('should render accurately when there is no additional properties', async () => {
+    const generator = new JavaGenerator({ presets: [JAVA_COMMON_PRESET] });
+    const inputModel = await generator.process({...doc, additionalProperties: false});
     const model = inputModel.models['Clazz'];
 
     const classModel = await generator.renderClass(model, inputModel);
-    const expectedDependencies = ['import java.util.Map;'];
-    expect(classModel.result).toEqual(expected);
-    expect(classModel.dependencies).toEqual(expectedDependencies);
+    expect(classModel.result).toMatchSnapshot();
+  });
+  describe('with option', () => {
+    test('should render all functions', async () => {
+      const generator = new JavaGenerator(
+        { 
+          presets: [{
+            preset: JAVA_COMMON_PRESET,
+            options: {
+              equal: true,
+              hashCode: true,
+              classToString: true,
+            }
+          }] 
+        }
+      );
+      const inputModel = await generator.process(doc);
+      const model = inputModel.models['Clazz'];
+  
+      const classModel = await generator.renderClass(model, inputModel);
+      expect(classModel.result).toMatchSnapshot();
+      expect(classModel.dependencies.includes('import java.util.Objects;')).toEqual(true);
+    });
+    test('should render equals', async () => {
+      const generator = new JavaGenerator(
+        { 
+          presets: [{
+            preset: JAVA_COMMON_PRESET,
+            options: {
+              equal: true,
+              hashCode: false,
+              classToString: false,
+            }
+          }] 
+        }
+      );
+      const inputModel = await generator.process(doc);
+      const model = inputModel.models['Clazz'];
+  
+      const classModel = await generator.renderClass(model, inputModel);
+      expect(classModel.result).toMatchSnapshot();
+      expect(classModel.dependencies.includes('import java.util.Objects;')).toEqual(true);
+    });
+    test('should render hashCode', async () => {
+      const generator = new JavaGenerator(
+        { 
+          presets: [{
+            preset: JAVA_COMMON_PRESET,
+            options: {
+              equal: false,
+              hashCode: true,
+              classToString: false,
+            }
+          }] 
+        }
+      );
+      const inputModel = await generator.process(doc);
+      const model = inputModel.models['Clazz'];
+  
+      const classModel = await generator.renderClass(model, inputModel);
+      expect(classModel.result).toMatchSnapshot();
+      expect(classModel.dependencies.includes('import java.util.Objects;')).toEqual(true);
+    });
+    test('should render classToString', async () => {
+      const generator = new JavaGenerator(
+        { 
+          presets: [{
+            preset: JAVA_COMMON_PRESET,
+            options: {
+              equal: false,
+              hashCode: false,
+              classToString: true,
+            }
+          }] 
+        }
+      );
+      const inputModel = await generator.process(doc);
+      const model = inputModel.models['Clazz'];
+  
+      const classModel = await generator.renderClass(model, inputModel);
+      expect(classModel.result).toMatchSnapshot();
+    });
   });
 });
diff --git a/test/generators/java/presets/__snapshots__/CommonPreset.spec.ts.snap b/test/generators/java/presets/__snapshots__/CommonPreset.spec.ts.snap
new file mode 100644
index 00000000..345da494
--- /dev/null
+++ b/test/generators/java/presets/__snapshots__/CommonPreset.spec.ts.snap
@@ -0,0 +1,353 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`JAVA_COMMON_PRESET should render accurately when there is no additional properties 1`] = `
+"public class Clazz {
+  private Boolean requiredProp;
+  private String stringProp;
+  private Double numberProp;
+  private Boolean booleanProp;
+  private String[] arrayProp;
+
+  public Boolean getRequiredProp() { return this.requiredProp; }
+  public void setRequiredProp(Boolean requiredProp) { this.requiredProp = requiredProp; }
+
+  public String getStringProp() { return this.stringProp; }
+  public void setStringProp(String stringProp) { this.stringProp = stringProp; }
+
+  public Double getNumberProp() { return this.numberProp; }
+  public void setNumberProp(Double numberProp) { this.numberProp = numberProp; }
+
+  public Boolean getBooleanProp() { return this.booleanProp; }
+  public void setBooleanProp(Boolean booleanProp) { this.booleanProp = booleanProp; }
+
+  public String[] getArrayProp() { return this.arrayProp; }
+  public void setArrayProp(String[] arrayProp) { this.arrayProp = arrayProp; }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    Clazz self = (Clazz) o;
+      return 
+        Objects.equals(this.requiredProp, self.requiredProp) &&
+        Objects.equals(this.stringProp, self.stringProp) &&
+        Objects.equals(this.numberProp, self.numberProp) &&
+        Objects.equals(this.booleanProp, self.booleanProp) &&
+        Objects.equals(this.arrayProp, self.arrayProp);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash((Object)requiredProp, (Object)stringProp, (Object)numberProp, (Object)booleanProp, (Object)arrayProp);
+  }
+
+  @Override
+  public String toString() {
+    return \\"class Clazz {\\\\n\\" +   
+      \\"    requiredProp: \\" + toIndentedString(requiredProp) + \\"\\\\n\\" +
+      \\"    stringProp: \\" + toIndentedString(stringProp) + \\"\\\\n\\" +
+      \\"    numberProp: \\" + toIndentedString(numberProp) + \\"\\\\n\\" +
+      \\"    booleanProp: \\" + toIndentedString(booleanProp) + \\"\\\\n\\" +
+      \\"    arrayProp: \\" + toIndentedString(arrayProp) + \\"\\\\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    \\");
+  }
+}"
+`;
+
+exports[`JAVA_COMMON_PRESET should render common function in class by common preset 1`] = `
+"public class Clazz {
+  private Boolean requiredProp;
+  private String stringProp;
+  private Double numberProp;
+  private Boolean booleanProp;
+  private String[] arrayProp;
+  private Map<String, Object> additionalProperties;
+
+  public Boolean getRequiredProp() { return this.requiredProp; }
+  public void setRequiredProp(Boolean requiredProp) { this.requiredProp = requiredProp; }
+
+  public String getStringProp() { return this.stringProp; }
+  public void setStringProp(String stringProp) { this.stringProp = stringProp; }
+
+  public Double getNumberProp() { return this.numberProp; }
+  public void setNumberProp(Double numberProp) { this.numberProp = numberProp; }
+
+  public Boolean getBooleanProp() { return this.booleanProp; }
+  public void setBooleanProp(Boolean booleanProp) { this.booleanProp = booleanProp; }
+
+  public String[] getArrayProp() { return this.arrayProp; }
+  public void setArrayProp(String[] arrayProp) { this.arrayProp = arrayProp; }
+
+  public Map<String, Object> getAdditionalProperties() { return this.additionalProperties; }
+  public void setAdditionalProperties(Map<String, Object> additionalProperties) { this.additionalProperties = additionalProperties; }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    Clazz self = (Clazz) o;
+      return 
+        Objects.equals(this.requiredProp, self.requiredProp) &&
+        Objects.equals(this.stringProp, self.stringProp) &&
+        Objects.equals(this.numberProp, self.numberProp) &&
+        Objects.equals(this.booleanProp, self.booleanProp) &&
+        Objects.equals(this.arrayProp, self.arrayProp) &&
+        Objects.equals(this.additionalProperties, self.additionalProperties);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash((Object)requiredProp, (Object)stringProp, (Object)numberProp, (Object)booleanProp, (Object)arrayProp, (Object)additionalProperties);
+  }
+
+  @Override
+  public String toString() {
+    return \\"class Clazz {\\\\n\\" +   
+      \\"    requiredProp: \\" + toIndentedString(requiredProp) + \\"\\\\n\\" +
+      \\"    stringProp: \\" + toIndentedString(stringProp) + \\"\\\\n\\" +
+      \\"    numberProp: \\" + toIndentedString(numberProp) + \\"\\\\n\\" +
+      \\"    booleanProp: \\" + toIndentedString(booleanProp) + \\"\\\\n\\" +
+      \\"    arrayProp: \\" + toIndentedString(arrayProp) + \\"\\\\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    \\");
+  }
+}"
+`;
+
+exports[`JAVA_COMMON_PRESET with option should render all functions 1`] = `
+"public class Clazz {
+  private Boolean requiredProp;
+  private String stringProp;
+  private Double numberProp;
+  private Boolean booleanProp;
+  private String[] arrayProp;
+  private Map<String, Object> additionalProperties;
+
+  public Boolean getRequiredProp() { return this.requiredProp; }
+  public void setRequiredProp(Boolean requiredProp) { this.requiredProp = requiredProp; }
+
+  public String getStringProp() { return this.stringProp; }
+  public void setStringProp(String stringProp) { this.stringProp = stringProp; }
+
+  public Double getNumberProp() { return this.numberProp; }
+  public void setNumberProp(Double numberProp) { this.numberProp = numberProp; }
+
+  public Boolean getBooleanProp() { return this.booleanProp; }
+  public void setBooleanProp(Boolean booleanProp) { this.booleanProp = booleanProp; }
+
+  public String[] getArrayProp() { return this.arrayProp; }
+  public void setArrayProp(String[] arrayProp) { this.arrayProp = arrayProp; }
+
+  public Map<String, Object> getAdditionalProperties() { return this.additionalProperties; }
+  public void setAdditionalProperties(Map<String, Object> additionalProperties) { this.additionalProperties = additionalProperties; }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    Clazz self = (Clazz) o;
+      return 
+        Objects.equals(this.requiredProp, self.requiredProp) &&
+        Objects.equals(this.stringProp, self.stringProp) &&
+        Objects.equals(this.numberProp, self.numberProp) &&
+        Objects.equals(this.booleanProp, self.booleanProp) &&
+        Objects.equals(this.arrayProp, self.arrayProp) &&
+        Objects.equals(this.additionalProperties, self.additionalProperties);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash((Object)requiredProp, (Object)stringProp, (Object)numberProp, (Object)booleanProp, (Object)arrayProp, (Object)additionalProperties);
+  }
+
+  @Override
+  public String toString() {
+    return \\"class Clazz {\\\\n\\" +   
+      \\"    requiredProp: \\" + toIndentedString(requiredProp) + \\"\\\\n\\" +
+      \\"    stringProp: \\" + toIndentedString(stringProp) + \\"\\\\n\\" +
+      \\"    numberProp: \\" + toIndentedString(numberProp) + \\"\\\\n\\" +
+      \\"    booleanProp: \\" + toIndentedString(booleanProp) + \\"\\\\n\\" +
+      \\"    arrayProp: \\" + toIndentedString(arrayProp) + \\"\\\\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    \\");
+  }
+}"
+`;
+
+exports[`JAVA_COMMON_PRESET with option should render classToString 1`] = `
+"public class Clazz {
+  private Boolean requiredProp;
+  private String stringProp;
+  private Double numberProp;
+  private Boolean booleanProp;
+  private String[] arrayProp;
+  private Map<String, Object> additionalProperties;
+
+  public Boolean getRequiredProp() { return this.requiredProp; }
+  public void setRequiredProp(Boolean requiredProp) { this.requiredProp = requiredProp; }
+
+  public String getStringProp() { return this.stringProp; }
+  public void setStringProp(String stringProp) { this.stringProp = stringProp; }
+
+  public Double getNumberProp() { return this.numberProp; }
+  public void setNumberProp(Double numberProp) { this.numberProp = numberProp; }
+
+  public Boolean getBooleanProp() { return this.booleanProp; }
+  public void setBooleanProp(Boolean booleanProp) { this.booleanProp = booleanProp; }
+
+  public String[] getArrayProp() { return this.arrayProp; }
+  public void setArrayProp(String[] arrayProp) { this.arrayProp = arrayProp; }
+
+  public Map<String, Object> getAdditionalProperties() { return this.additionalProperties; }
+  public void setAdditionalProperties(Map<String, Object> additionalProperties) { this.additionalProperties = additionalProperties; }
+
+  @Override
+  public String toString() {
+    return \\"class Clazz {\\\\n\\" +   
+      \\"    requiredProp: \\" + toIndentedString(requiredProp) + \\"\\\\n\\" +
+      \\"    stringProp: \\" + toIndentedString(stringProp) + \\"\\\\n\\" +
+      \\"    numberProp: \\" + toIndentedString(numberProp) + \\"\\\\n\\" +
+      \\"    booleanProp: \\" + toIndentedString(booleanProp) + \\"\\\\n\\" +
+      \\"    arrayProp: \\" + toIndentedString(arrayProp) + \\"\\\\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    \\");
+  }
+}"
+`;
+
+exports[`JAVA_COMMON_PRESET with option should render equals 1`] = `
+"public class Clazz {
+  private Boolean requiredProp;
+  private String stringProp;
+  private Double numberProp;
+  private Boolean booleanProp;
+  private String[] arrayProp;
+  private Map<String, Object> additionalProperties;
+
+  public Boolean getRequiredProp() { return this.requiredProp; }
+  public void setRequiredProp(Boolean requiredProp) { this.requiredProp = requiredProp; }
+
+  public String getStringProp() { return this.stringProp; }
+  public void setStringProp(String stringProp) { this.stringProp = stringProp; }
+
+  public Double getNumberProp() { return this.numberProp; }
+  public void setNumberProp(Double numberProp) { this.numberProp = numberProp; }
+
+  public Boolean getBooleanProp() { return this.booleanProp; }
+  public void setBooleanProp(Boolean booleanProp) { this.booleanProp = booleanProp; }
+
+  public String[] getArrayProp() { return this.arrayProp; }
+  public void setArrayProp(String[] arrayProp) { this.arrayProp = arrayProp; }
+
+  public Map<String, Object> getAdditionalProperties() { return this.additionalProperties; }
+  public void setAdditionalProperties(Map<String, Object> additionalProperties) { this.additionalProperties = additionalProperties; }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    Clazz self = (Clazz) o;
+      return 
+        Objects.equals(this.requiredProp, self.requiredProp) &&
+        Objects.equals(this.stringProp, self.stringProp) &&
+        Objects.equals(this.numberProp, self.numberProp) &&
+        Objects.equals(this.booleanProp, self.booleanProp) &&
+        Objects.equals(this.arrayProp, self.arrayProp) &&
+        Objects.equals(this.additionalProperties, self.additionalProperties);
+  }
+}"
+`;
+
+exports[`JAVA_COMMON_PRESET with option should render hashCode 1`] = `
+"public class Clazz {
+  private Boolean requiredProp;
+  private String stringProp;
+  private Double numberProp;
+  private Boolean booleanProp;
+  private String[] arrayProp;
+  private Map<String, Object> additionalProperties;
+
+  public Boolean getRequiredProp() { return this.requiredProp; }
+  public void setRequiredProp(Boolean requiredProp) { this.requiredProp = requiredProp; }
+
+  public String getStringProp() { return this.stringProp; }
+  public void setStringProp(String stringProp) { this.stringProp = stringProp; }
+
+  public Double getNumberProp() { return this.numberProp; }
+  public void setNumberProp(Double numberProp) { this.numberProp = numberProp; }
+
+  public Boolean getBooleanProp() { return this.booleanProp; }
+  public void setBooleanProp(Boolean booleanProp) { this.booleanProp = booleanProp; }
+
+  public String[] getArrayProp() { return this.arrayProp; }
+  public void setArrayProp(String[] arrayProp) { this.arrayProp = arrayProp; }
+
+  public Map<String, Object> getAdditionalProperties() { return this.additionalProperties; }
+  public void setAdditionalProperties(Map<String, Object> additionalProperties) { this.additionalProperties = additionalProperties; }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash((Object)requiredProp, (Object)stringProp, (Object)numberProp, (Object)booleanProp, (Object)arrayProp, (Object)additionalProperties);
+  }
+}"
+`;