-
-
Notifications
You must be signed in to change notification settings - Fork 191
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add common presets for Java (#112)
- Loading branch information
1 parent
a36811a
commit 5798501
Showing
12 changed files
with
559 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from './JavaGenerator'; | ||
export { JAVA_DEFAULT_PRESET } from './JavaPreset'; | ||
export type { JavaPreset } from './JavaPreset'; | ||
export * from './presets'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import { JavaRenderer } from '../JavaRenderer'; | ||
import { JavaPreset } from '../JavaPreset'; | ||
|
||
import { FormatHelpers } from '../../../helpers'; | ||
import { CommonModel } from '../../../models'; | ||
|
||
export interface JavaCommonPresetOptions { | ||
equal: boolean; | ||
hash: boolean; | ||
classToString: boolean; | ||
} | ||
|
||
/** | ||
* Render `equal` function based on model's properties | ||
* | ||
* @returns {string} | ||
*/ | ||
function renderEqual({ renderer, model }: { | ||
renderer: JavaRenderer, | ||
model: CommonModel, | ||
}): string { | ||
const formattedModelName = model.$id && FormatHelpers.toPascalCase(model.$id); | ||
const properties = model.properties || {}; | ||
const equalProperties = Object.keys(properties).map(prop => { | ||
const camelCasedProp = FormatHelpers.toCamelCase(prop); | ||
return `Objects.equals(this.${camelCasedProp}, self.${camelCasedProp})`; | ||
}).join(' &&\n'); | ||
|
||
return `${renderer.renderAnnotation('Override')} | ||
public boolean equals(Object o) { | ||
if (this == o) { | ||
return true; | ||
} | ||
if (o == null || getClass() != o.getClass()) { | ||
return false; | ||
} | ||
${formattedModelName} self = (${formattedModelName}) o; | ||
return | ||
${renderer.indent(equalProperties, 6)}; | ||
}`; | ||
} | ||
|
||
/** | ||
* Render `hashCode` function based on model's properties | ||
* | ||
* @returns {string} | ||
*/ | ||
function renderHashCode({ renderer, model }: { | ||
renderer: JavaRenderer, | ||
model: CommonModel, | ||
}): string { | ||
const properties = model.properties || {}; | ||
const hashProperties = Object.keys(properties).map(prop => FormatHelpers.toCamelCase(prop)).join(', '); | ||
|
||
return `${renderer.renderAnnotation('Override')} | ||
public int hashCode() { | ||
return Objects.hash(${hashProperties}); | ||
}`; | ||
} | ||
|
||
/** | ||
* Render `toString` function based on model's properties | ||
* | ||
* @returns {string} | ||
*/ | ||
function renderToString({ renderer, model }: { | ||
renderer: JavaRenderer, | ||
model: CommonModel, | ||
}): string { | ||
const formattedModelName = model.$id && FormatHelpers.toPascalCase(model.$id); | ||
const properties = model.properties || {}; | ||
const toStringProperties = Object.keys(properties).map(prop => | ||
`" ${prop}: " + toIndentedString(${FormatHelpers.toCamelCase(prop)}) + "\\n" +` | ||
); | ||
|
||
return `${renderer.renderAnnotation('Override')} | ||
public String toString() { | ||
return "class ${formattedModelName} {\\n" + | ||
${renderer.indent(renderer.renderBlock(toStringProperties), 4)} | ||
"}"; | ||
} | ||
${renderer.renderComments(['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 "); | ||
}`; | ||
} | ||
|
||
/** | ||
* Preset which adds `equal`, `hashCode`, `toString` functions to class. | ||
* | ||
* @implements {JavaPreset} | ||
*/ | ||
export const JAVA_COMMON_PRESET: JavaPreset = { | ||
class: { | ||
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 })); | ||
|
||
return renderer.renderBlock([content, ...blocks], 2); | ||
}, | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { JavaPreset } from '../JavaPreset'; | ||
|
||
import { CommonModel } from '../../../models'; | ||
|
||
/** | ||
* Preset which extends class's getters with annotations from `javax.validation.constraints` package | ||
* | ||
* @implements {JavaPreset} | ||
*/ | ||
export const JAVA_CONSTRAINTS_PRESET: JavaPreset = { | ||
class: { | ||
getter({ renderer, model, propertyName, property, content }) { | ||
if (!(property instanceof CommonModel)) { | ||
return content; | ||
} | ||
const annotations: string[] = []; | ||
|
||
const isRequired = model.isRequired(propertyName); | ||
if (isRequired) { | ||
annotations.push(renderer.renderAnnotation('NotNull')); | ||
} | ||
|
||
// string | ||
const pattern = property.getFromSchema('pattern'); | ||
if (pattern !== undefined) { | ||
annotations.push(renderer.renderAnnotation('Pattern', { regexp: `"${pattern}"` })); | ||
} | ||
const minLength = property.getFromSchema('minLength'); | ||
const maxLength = property.getFromSchema('maxLength'); | ||
if (minLength !== undefined || maxLength !== undefined) { | ||
annotations.push(renderer.renderAnnotation('Size', { min: minLength, max: maxLength })); | ||
} | ||
|
||
// number/integer | ||
const minimum = property.getFromSchema('minimum'); | ||
if (minimum !== undefined) { | ||
annotations.push(renderer.renderAnnotation('Min', minimum)); | ||
} | ||
const exclusiveMinimum = property.getFromSchema('exclusiveMinimum'); | ||
if (exclusiveMinimum !== undefined) { | ||
annotations.push(renderer.renderAnnotation('Min', exclusiveMinimum + 1)); | ||
} | ||
const maximum = property.getFromSchema('maximum'); | ||
if (maximum !== undefined) { | ||
annotations.push(renderer.renderAnnotation('Max', maximum)); | ||
} | ||
const exclusiveMaximum = property.getFromSchema('exclusiveMaximum'); | ||
if (exclusiveMaximum !== undefined) { | ||
annotations.push(renderer.renderAnnotation('Max', exclusiveMaximum - 1)); | ||
} | ||
|
||
// array | ||
const minItems = property.getFromSchema('minItems'); | ||
const maxItems = property.getFromSchema('maxItems'); | ||
if (minItems !== undefined || maxItems !== undefined) { | ||
annotations.push(renderer.renderAnnotation('Size', { min: minItems, max: maxItems })); | ||
} | ||
|
||
return renderer.renderBlock([...annotations, content]); | ||
}, | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { JavaRenderer } from '../JavaRenderer'; | ||
import { JavaPreset } from '../JavaPreset'; | ||
|
||
import { FormatHelpers } from '../../../helpers'; | ||
import { CommonModel } from '../../../models'; | ||
|
||
function renderDescription({ renderer, content, item }: { | ||
renderer: JavaRenderer, | ||
content: string, | ||
item: CommonModel, | ||
}): string { | ||
if (!(item instanceof CommonModel)) { | ||
return content; | ||
} | ||
|
||
let desc = item.getFromSchema('description'); | ||
const examples = item.getFromSchema('examples'); | ||
|
||
if (Array.isArray(examples)) { | ||
const renderedExamples = FormatHelpers.renderJSONExamples(examples); | ||
const exampleDesc = `Examples: ${renderedExamples}`; | ||
desc = desc ? `${desc}\n${exampleDesc}` : exampleDesc; | ||
} | ||
|
||
if (desc) { | ||
const renderedDesc = renderer.renderComments(desc); | ||
return `${renderedDesc}\n${content}`; | ||
} | ||
return content; | ||
} | ||
|
||
/** | ||
* Preset which adds description to rendered model. | ||
* | ||
* @implements {JavaPreset} | ||
*/ | ||
export const JAVA_DESCRIPTION_PRESET: JavaPreset = { | ||
class: { | ||
self({ renderer, model, content }) { | ||
return renderDescription({ renderer, content, item: model }); | ||
}, | ||
getter({ renderer, property, content }) { | ||
return renderDescription({ renderer, content, item: property }); | ||
} | ||
}, | ||
enum: { | ||
self({ renderer, model, content }) { | ||
return renderDescription({ renderer, content, item: model }); | ||
}, | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { JavaPreset } from '../JavaPreset'; | ||
|
||
/** | ||
* Preset which adds `com.fasterxml.jackson` related annotations to class's getters. | ||
* | ||
* @implements {JavaPreset} | ||
*/ | ||
export const JAVA_JACKSON_PRESET: JavaPreset = { | ||
class: { | ||
getter({ renderer, propertyName, content }) { | ||
const annotation = renderer.renderAnnotation('JsonProperty', `"${propertyName}"`); | ||
return renderer.renderBlock([annotation, content]); | ||
}, | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export * from './CommonPreset'; | ||
export * from './DescriptioPreset'; | ||
export * from './JacksonPreset'; | ||
export * from './ConstraintsPreset'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import { JavaGenerator, JAVA_COMMON_PRESET } from '../../../../src/generators'; | ||
|
||
describe('JAVA_COMMON_PRESET', function() { | ||
test('should render common function in class by common preset', async function() { | ||
const doc = { | ||
$id: "Clazz", | ||
type: "object", | ||
properties: { | ||
stringProp: { type: "string" }, | ||
numberProp: { type: "number" }, | ||
}, | ||
}; | ||
const expected = `public class Clazz { | ||
private String stringProp; | ||
private Double numberProp; | ||
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; } | ||
@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); | ||
} | ||
@Override | ||
public int hashCode() { | ||
return Objects.hash(stringProp, numberProp); | ||
} | ||
@Override | ||
public String toString() { | ||
return "class Clazz {\\n" + | ||
" stringProp: " + toIndentedString(stringProp) + "\\n" + | ||
" numberProp: " + toIndentedString(numberProp) + "\\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"]; | ||
|
||
let classModel = await generator.renderClass(model, inputModel); | ||
expect(classModel).toEqual(expected); | ||
}); | ||
|
||
test('should skip rendering of disabled functions', async function() { | ||
const doc = { | ||
$id: "Clazz", | ||
type: "object", | ||
properties: { | ||
stringProp: { type: "string" }, | ||
numberProp: { type: "number" }, | ||
}, | ||
}; | ||
const expected = `public class Clazz { | ||
private String stringProp; | ||
private Double numberProp; | ||
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; } | ||
@Override | ||
public int hashCode() { | ||
return Objects.hash(stringProp, numberProp); | ||
} | ||
}`; | ||
|
||
const generator = new JavaGenerator({ presets: [{ | ||
preset: JAVA_COMMON_PRESET, | ||
options: { | ||
equal: false, | ||
classToString: false, | ||
} | ||
}] }); | ||
const inputModel = await generator.process(doc); | ||
const model = inputModel.models["Clazz"]; | ||
|
||
let classModel = await generator.renderClass(model, inputModel); | ||
expect(classModel).toEqual(expected); | ||
}); | ||
}); |
Oops, something went wrong.