Skip to content

Commit

Permalink
fix: java generator could generate illegal package names (#1084)
Browse files Browse the repository at this point in the history
  • Loading branch information
LouisXhaferi authored Jan 19, 2023
1 parent 683c912 commit d5f7f5d
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 44 deletions.
52 changes: 30 additions & 22 deletions src/generators/java/JavaGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
AbstractGenerator,
import {
AbstractGenerator,
CommonGeneratorOptions,
defaultGeneratorOptions
} from '../AbstractGenerator';
Expand All @@ -10,9 +10,9 @@ import { ClassRenderer } from './renderers/ClassRenderer';
import { EnumRenderer } from './renderers/EnumRenderer';
import { isReservedJavaKeyword } from './Constants';
import { Logger } from '../../';
import { constrainMetaModel, Constraints } from '../../helpers/ConstrainHelpers';
import { constrainMetaModel, Constraints } from '../../helpers';
import { JavaDefaultConstraints, JavaDefaultTypeMapping } from './JavaConstrainer';
import { DeepPartial, mergePartialAndDefault } from '../../utils/Partials';
import { DeepPartial, mergePartialAndDefault } from '../../utils';

export interface JavaOptions extends CommonGeneratorOptions<JavaPreset> {
collectionType: 'List' | 'Array';
Expand All @@ -25,7 +25,7 @@ export interface JavaRenderCompleteModelOptions {
export class JavaGenerator extends AbstractGenerator<JavaOptions, JavaRenderCompleteModelOptions> {
static defaultOptions: JavaOptions = {
...defaultGeneratorOptions,
defaultPreset: JAVA_DEFAULT_PRESET,
defaultPreset: JAVA_DEFAULT_PRESET,
collectionType: 'Array',
typeMapping: JavaDefaultTypeMapping,
constraints: JavaDefaultConstraints
Expand All @@ -37,20 +37,20 @@ export class JavaGenerator extends AbstractGenerator<JavaOptions, JavaRenderComp
const realizedOptions = mergePartialAndDefault(JavaGenerator.defaultOptions, options) as JavaOptions;
super('Java', realizedOptions);
}

splitMetaModel(model: MetaModel): MetaModel[] {
//These are the models that we have separate renderers for
const metaModelsToSplit = {
splitEnum: true,
splitEnum: true,
splitObject: true
};
return split(model, metaModelsToSplit);
}

constrainToMetaModel(model: MetaModel): ConstrainedMetaModel {
return constrainMetaModel<JavaOptions>(
this.options.typeMapping,
this.options.constraints,
this.options.typeMapping,
this.options.constraints,
{
metaModel: model,
options: this.options,
Expand All @@ -61,33 +61,31 @@ export class JavaGenerator extends AbstractGenerator<JavaOptions, JavaRenderComp

/**
* Render a scattered model, where the source code and library and model dependencies are separated.
*
* @param model
* @param inputModel
*
* @param model
* @param inputModel
*/
render(model: ConstrainedMetaModel, inputModel: InputMetaModel): Promise<RenderOutput> {
if (model instanceof ConstrainedObjectModel) {
return this.renderClass(model, inputModel);
} else if (model instanceof ConstrainedEnumModel) {
return this.renderEnum(model, inputModel);
}
}
Logger.warn(`Java generator, cannot generate this type of model, ${model.name}`);
return Promise.resolve(RenderOutput.toRenderOutput({ result: '', renderedName: '', dependencies: [] }));
}

/**
* Render a complete model result where the model code, library and model dependencies are all bundled appropriately.
*
*
* For Java you need to specify which package the model is placed under.
*
* @param model
* @param inputModel
*
* @param model
* @param inputModel
* @param options used to render the full output
*/
async renderCompleteModel(model: ConstrainedMetaModel, inputModel: InputMetaModel, options: JavaRenderCompleteModelOptions): Promise<RenderOutput> {
if (isReservedJavaKeyword(options.packageName)) {
throw new Error(`You cannot use reserved Java keyword (${options.packageName}) as package name, please use another.`);
}
this.assertPackageIsValid(options);

const outputModel = await this.render(model, inputModel);
const modelDependencies = model.getNearestDependencies().map((dependencyModel) => {
Expand All @@ -96,10 +94,20 @@ export class JavaGenerator extends AbstractGenerator<JavaOptions, JavaRenderComp
const outputContent = `package ${options.packageName};
${modelDependencies.join('\n')}
${outputModel.dependencies.join('\n')}
${outputModel.result}`;
${outputModel.result}`;
return RenderOutput.toRenderOutput({result: outputContent, renderedName: outputModel.renderedName, dependencies: outputModel.dependencies});
}

private assertPackageIsValid(options: JavaRenderCompleteModelOptions) {
const reservedWords = options.packageName
.split('.')
.filter(subpackage => isReservedJavaKeyword(subpackage, true));

if (reservedWords.length > 0) {
throw new Error(`You cannot use '${options.packageName}' as a package name, contains reserved keywords: [${reservedWords.join(', ')}]`);
}
}

async renderClass(model: ConstrainedObjectModel, inputModel: InputMetaModel): Promise<RenderOutput> {
const presets = this.getPresets('class');
const renderer = new ClassRenderer(this.options, this, presets, model, inputModel);
Expand All @@ -108,7 +116,7 @@ ${outputModel.result}`;
}

async renderEnum(model: ConstrainedEnumModel, inputModel: InputMetaModel): Promise<RenderOutput> {
const presets = this.getPresets('enum');
const presets = this.getPresets('enum');
const renderer = new EnumRenderer(this.options, this, presets, model, inputModel);
const result = await renderer.runSelfPreset();
return RenderOutput.toRenderOutput({result, renderedName: model.name, dependencies: renderer.dependencies});
Expand Down
33 changes: 14 additions & 19 deletions test/generators/java/JavaGenerator.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { JavaGenerator } from '../../../src/generators';
import { JavaGenerator } from '../../../src/generators';

describe('JavaGenerator', () => {
let generator: JavaGenerator;
Expand Down Expand Up @@ -91,12 +91,11 @@ describe('JavaGenerator', () => {
type: 'string',
enum: ['Texas', 'Alabama', 'California', 'New York'],
};
const expectedDependencies = [];

const models = await generator.generate(doc);
expect(models).toHaveLength(1);
expect(models[0].result).toMatchSnapshot();
expect(models[0].dependencies).toEqual(expectedDependencies);
expect(models[0].dependencies).toEqual([]);
});

test('should render `enum` type (integer type)', async () => {
Expand All @@ -105,12 +104,11 @@ describe('JavaGenerator', () => {
type: 'integer',
enum: [0, 1, 2, 3],
};
const expectedDependencies = [];


const models = await generator.generate(doc);
expect(models).toHaveLength(1);
expect(models[0].result).toMatchSnapshot();
expect(models[0].dependencies).toEqual(expectedDependencies);
expect(models[0].dependencies).toEqual([]);
});

test('should render `enum` type (union type)', async () => {
Expand All @@ -119,12 +117,11 @@ describe('JavaGenerator', () => {
type: ['string', 'integer', 'boolean'],
enum: ['Texas', 'Alabama', 0, 1, '1', true, {test: 'test'}],
};
const expectedDependencies = [];


const models = await generator.generate(doc);
expect(models).toHaveLength(1);
expect(models[0].result).toMatchSnapshot();
expect(models[0].dependencies).toEqual(expectedDependencies);
expect(models[0].dependencies).toEqual([]);
});

test('should render custom preset for `enum` type', async () => {
Expand All @@ -144,25 +141,23 @@ describe('JavaGenerator', () => {
}
}
] });
const expectedDependencies = [];


const models = await generator.generate(doc);
expect(models).toHaveLength(1);
expect(models[0].result).toMatchSnapshot();
expect(models[0].dependencies).toEqual(expectedDependencies);
expect(models[0].dependencies).toEqual([]);
});

test('should render enums with translated special characters', async () => {
const doc = {
$id: 'States',
enum: ['test+', 'test', 'test-', 'test?!', '*test']
};
const expectedDependencies = [];


const models = await generator.generate(doc);
expect(models).toHaveLength(1);
expect(models[0].result).toMatchSnapshot();
expect(models[0].dependencies).toEqual(expectedDependencies);
expect(models[0].dependencies).toEqual([]);
});

test('should render List type for collections', async () => {
Expand Down Expand Up @@ -205,13 +200,13 @@ describe('JavaGenerator', () => {
},
required: ['street_name', 'city', 'state', 'house_number', 'array_type'],
};
const config = {packageName: 'test.package'};
const config = {packageName: 'test.packageName'};
const models = await generator.generateCompleteModels(doc, config);
expect(models).toHaveLength(2);
expect(models[0].result).toMatchSnapshot();
expect(models[1].result).toMatchSnapshot();
});
test('should throw error when reserved keyword is used for package name', async () => {
test('should throw error when reserved keyword is used in any part of the package name', async () => {
const doc = {
$id: 'Address',
type: 'object',
Expand All @@ -231,8 +226,8 @@ describe('JavaGenerator', () => {
},
required: ['street_name', 'city', 'state', 'house_number', 'array_type'],
};
const config = {packageName: 'package'};
const expectedError = new Error('You cannot use reserved Java keyword (package) as package name, please use another.');
const config = {packageName: 'valid.package.correct.class'};
const expectedError = new Error('You cannot use \'valid.package.correct.class\' as a package name, contains reserved keywords: [package, class]');
await expect(generator.generateCompleteModels(doc, config)).rejects.toEqual(expectedError);
});
});
6 changes: 3 additions & 3 deletions test/generators/java/__snapshots__/JavaGenerator.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,8 @@ exports[`JavaGenerator should render enums with translated special characters 1`
`;
exports[`JavaGenerator should render models and their dependencies 1`] = `
"package test.package;
import test.package.OtherModel;
"package test.packageName;
import test.packageName.OtherModel;
import java.util.Map;
public class Address {
private String streetName;
Expand Down Expand Up @@ -255,7 +255,7 @@ public class Address {
`;
exports[`JavaGenerator should render models and their dependencies 2`] = `
"package test.package;
"package test.packageName;
import java.util.Map;
public class OtherModel {
Expand Down

0 comments on commit d5f7f5d

Please sign in to comment.