UNPKG

@openapi-generator-plus/java-jaxrs-generator-common

Version:
655 lines (651 loc) 39.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.options = exports.packageToPath = void 0; const types_1 = require("@openapi-generator-plus/types"); const path_1 = __importDefault(require("path")); const handlebars_1 = __importDefault(require("handlebars")); const handlebars_templates_1 = require("@openapi-generator-plus/handlebars-templates"); const java_like_generator_helper_1 = require("@openapi-generator-plus/java-like-generator-helper"); const generator_common_1 = require("@openapi-generator-plus/generator-common"); const idx = __importStar(require("@openapi-generator-plus/indexed-type")); function escapeString(value) { if (typeof value !== 'string' && typeof value !== 'number' && typeof value !== 'boolean') { throw new Error(`escapeString called with unsupported type: ${typeof value} (${value})`); } value = String(value); value = value.replace(/\\/g, '\\\\'); value = value.replace(/"/g, '\\"'); value = value.replace(/\r/g, '\\r'); value = value.replace(/\n/g, '\\n'); return value; } /** * Turns a Java package name into a path * @param packageName Java package name */ function packageToPath(packageName) { return packageName.replace(/\./g, path_1.default.sep); } exports.packageToPath = packageToPath; function computeCustomTemplatesPath(configPath, customTemplatesPath) { if (configPath) { return path_1.default.resolve(path_1.default.dirname(configPath), customTemplatesPath); } else { return customTemplatesPath; } } function computeRelativeSourceOutputPath(config) { const maven = config.maven; const defaultPath = maven ? path_1.default.join('src', 'main', 'java') : ''; return (0, generator_common_1.configString)(config, 'relativeSourceOutputPath', defaultPath); } function computeRelativeResourcesOutputPath(config) { const maven = config.maven; const defaultPath = maven ? path_1.default.join('src', 'main', 'resources') : undefined; return (0, generator_common_1.configString)(config, 'relativeResourcesOutputPath', defaultPath); } function computeRelativeTestOutputPath(config) { const maven = config.maven; const defaultPath = maven ? path_1.default.join('src', 'test', 'java') : ''; return (0, generator_common_1.configString)(config, 'relativeTestOutputPath', defaultPath); } function computeRelativeTestResourcesOutputPath(config) { const maven = config.maven; const defaultPath = maven ? path_1.default.join('src', 'test', 'resources') : undefined; return (0, generator_common_1.configString)(config, 'relativeTestResourcesOutputPath', defaultPath); } const RESERVED_WORDS = [ 'abstract', 'assert', 'boolean', 'break', 'byte', 'case', 'catch', 'char', 'class', 'const', 'continue', 'default', 'double', 'do', 'else', 'enum', 'extends', 'false', 'final', 'finally', 'float', 'for', 'goto', 'if', 'implements', 'import', 'instanceof', 'int', 'interface', 'long', 'native', 'new', 'null', 'package', 'private', 'protected', 'public', 'return', 'short', 'static', 'strictfp', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws', 'transient', 'true', 'try', 'void', 'volatile', 'while', ]; function options(config, context) { const packageName = (0, generator_common_1.configString)(config, 'package', 'com.example'); const apiPackage = (0, generator_common_1.configString)(config, 'apiPackage', packageName); const maven = (0, generator_common_1.configObject)(config, 'maven', undefined); const customizations = (0, generator_common_1.configObject)(config, 'customizations', undefined); const customTemplates = (0, generator_common_1.configString)(config, 'customTemplates', undefined); const relativeSourceOutputPath = computeRelativeSourceOutputPath(config); const options = Object.assign(Object.assign({}, (0, java_like_generator_helper_1.options)(config, createJavaLikeContext(context))), { apiPackage, apiImplPackage: (0, generator_common_1.configString)(config, 'apiImplPackage', `${apiPackage}.impl`), apiParamsPackage: (0, generator_common_1.nullableConfigString)(config, 'apiParamsPackage', `${apiPackage}.params`), modelPackage: (0, generator_common_1.configString)(config, 'modelPackage', `${packageName}.model`), useBeanValidation: (0, generator_common_1.configBoolean)(config, 'useBeanValidation', true), validationPackage: (0, generator_common_1.configString)(config, 'validationPackage', `${packageName}.validation`), includeTests: (0, generator_common_1.configBoolean)(config, 'includeTests', false), junitVersion: (0, generator_common_1.configNumber)(config, 'junitVersion', 5), dateImplementation: (0, generator_common_1.configString)(config, 'dateImplementation', 'java.time.LocalDate'), timeImplementation: (0, generator_common_1.configString)(config, 'timeImplementation', 'java.time.LocalTime'), dateTimeImplementation: (0, generator_common_1.configString)(config, 'dateTimeImplementation', 'java.time.OffsetDateTime'), binaryRepresentation: (0, generator_common_1.configString)(config, 'binaryRepresentation', 'byte[]'), fileRepresentation: (0, generator_common_1.configString)(config, 'fileRepresentation', (0, generator_common_1.configString)(config, 'binaryRepresentation', 'byte[]')), hideGenerationTimestamp: (0, generator_common_1.configBoolean)(config, 'hideGenerationTimestamp', true), imports: (0, generator_common_1.configStringArray)(config, 'imports', null), maven: maven ? { groupId: (0, generator_common_1.configString)(maven, 'groupId', 'com.example', 'maven.'), artifactId: (0, generator_common_1.configString)(maven, 'artifactId', 'api', 'maven.'), version: (0, generator_common_1.configString)(maven, 'version', '0.0.1', 'maven.'), versions: (0, generator_common_1.configObject)(maven, 'versions', {}, 'maven.'), } : null, relativeSourceOutputPath, relativeApiSourceOutputPath: (0, generator_common_1.configString)(config, 'relativeApiSourceOutputPath', relativeSourceOutputPath), relativeApiImplSourceOutputPath: (0, generator_common_1.configString)(config, 'relativeApiImplSourceOutputPath', relativeSourceOutputPath), relativeResourcesOutputPath: computeRelativeResourcesOutputPath(config), relativeTestOutputPath: computeRelativeTestOutputPath(config), relativeTestResourcesOutputPath: computeRelativeTestResourcesOutputPath(config), customTemplatesPath: customTemplates && computeCustomTemplatesPath(config.configPath, customTemplates), useJakarta: (0, generator_common_1.configBoolean)(config, 'useJakarta', false), useLombok: (0, generator_common_1.configBoolean)(config, 'useLombok', false), customizations: { classes: (0, generator_common_1.configObject)(customizations || {}, 'classes', {}, 'customizations.'), } }); return options; } exports.options = options; function createJavaLikeContext(context) { const javaLikeContext = Object.assign(Object.assign({}, context), { reservedWords: () => RESERVED_WORDS, defaultConstantStyle: "snake" /* ConstantStyle.allCapsSnake */, defaultEnumMemberStyle: "contant" /* EnumMemberStyle.constant */ }); return javaLikeContext; } function createGenerator(config, context) { const generatorOptions = options(config, context); const baseGenerator = context.baseGenerator(config, context); const aCommonGenerator = (0, generator_common_1.commonGenerator)(config, context); return Object.assign(Object.assign(Object.assign(Object.assign({}, baseGenerator), aCommonGenerator), (0, java_like_generator_helper_1.javaLikeGenerator)(config, createJavaLikeContext(context))), { toLiteral: (value, options) => { if (value === undefined) { const defaultValue = context.generator().defaultValue(options); if (defaultValue === null) { return null; } return defaultValue.literalValue; } const { type, format, required, nullable, schemaType } = options; if (value === null) { if (nullable) { return 'null'; } const defaultValue = context.generator().defaultValue(options); if (defaultValue === null) { return null; } return defaultValue.literalValue; } if (schemaType === types_1.CodegenSchemaType.ENUM) { return `${options.nativeType.concreteType}.${context.generator().toEnumMemberName(String(value))}`; } /* We use the same logic as in nativeTypeUsageTransformer */ const primitive = required && !nullable; switch (type) { case 'integer': { if (typeof value === 'string') { const parsedValue = parseInt(value); if (isNaN(parsedValue)) { throw new Error(`toLiteral with type integer called with non-number: ${typeof value} (${value})`); } value = parsedValue; } if (typeof value !== 'number') { throw new Error(`toLiteral with type integer called with non-number: ${typeof value} (${value})`); } if (format === 'int32' || !format) { return !primitive ? `java.lang.Integer.valueOf(${value})` : `${value}`; } else if (format === 'int64') { return !primitive ? `java.lang.Long.valueOf(${value}L)` : `${value}l`; } else { throw new Error(`Unsupported ${type} format: ${format}`); } } case 'number': { if (typeof value === 'string') { const parsedValue = parseFloat(value); if (isNaN(parsedValue)) { throw new Error(`toLiteral with type number called with non-number: ${typeof value} (${value})`); } value = parsedValue; } if (typeof value !== 'number') { throw new Error(`toLiteral with type number called with non-number: ${typeof value} (${value})`); } if (!format) { return `new java.math.BigDecimal("${value}")`; } else if (format === 'float') { return !primitive ? `java.lang.Float.valueOf(${value}f)` : `${value}f`; } else if (format === 'double') { return !primitive ? `java.lang.Double.valueOf(${value}d)` : `${value}d`; } else { throw new Error(`Unsupported ${type} format: ${format}`); } } case 'string': { if (typeof value !== 'string' && typeof value !== 'number' && typeof value !== 'boolean') { throw new Error(`toLiteral with type string called with unsupported type: ${typeof value} (${value})`); } if (format === 'byte') { return `"${escapeString(value)}"`; } else if (format === 'binary') { return `"${escapeString(value)}".getBytes(java.nio.charset.StandardCharsets.UTF_8)`; } else if (format === 'date') { return `${generatorOptions.dateImplementation}.parse("${escapeString(value)}")`; } else if (format === 'time') { return `${generatorOptions.timeImplementation}.parse("${escapeString(value)}")`; } else if (format === 'date-time') { return `${generatorOptions.dateTimeImplementation}.parse("${escapeString(value)}")`; } else if (format === 'uuid') { return `java.util.UUID.fromString("${escapeString(value)}")`; } else { return `"${escapeString(value)}"`; } } case 'boolean': if (typeof value === 'string') { value = value.toLowerCase() === 'true'; } if (typeof value === 'number') { value = value !== 0; } if (typeof value !== 'boolean') { throw new Error(`toLiteral with type boolean called with non-boolean: ${typeof value} (${value})`); } return !primitive ? `java.lang.Boolean.valueOf(${value})` : `${value}`; case 'object': if (typeof value === 'string') { if (value) { return value; } else { return 'null'; } } else { context.log(types_1.CodegenLogLevel.WARN, `Literal is unsupported for schema type object: ${(0, generator_common_1.debugStringify)(value)}`); return 'null'; } break; case 'file': throw new Error(`Cannot format literal for type ${type}`); case 'array': { const arrayValue = Array.isArray(value) ? value : [value]; const component = options.component; if (!component) { throw new Error(`toLiteral cannot format array literal without a component type: ${value}`); } return `java.util.Arrays.asList(${arrayValue.map(v => context.generator().toLiteral(v, Object.assign(Object.assign({}, component.schema), component))).join(', ')})`; } } throw new Error(`Unsupported literal type name "${type}" in options: ${(0, generator_common_1.debugStringify)(options)}`); }, toNativeType: (options) => { const { format, schemaType, vendorExtensions } = options; /* Note that we return separate componentTypes in this function in case the type is transformed, using nativeTypeTransformer, and the native type becomes primitive as the component type must still be non-primitive. */ if (vendorExtensions && vendorExtensions['x-java-type']) { return new context.NativeType(String(vendorExtensions['x-java-type'])); } /* See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types */ switch (schemaType) { case types_1.CodegenSchemaType.INTEGER: { if (format === 'int32' || !format) { return new context.NativeType('java.lang.Integer'); } else if (format === 'int64') { return new context.NativeType('java.lang.Long'); } else { throw new Error(`Unsupported integer format: ${format}`); } } case types_1.CodegenSchemaType.NUMBER: { if (!format) { return new context.NativeType('java.math.BigDecimal'); } else if (format === 'float') { return new context.NativeType('java.lang.Float'); } else if (format === 'double') { return new context.NativeType('java.lang.Double'); } else { throw new Error(`Unsupported number format: ${format}`); } } case types_1.CodegenSchemaType.DATE: return new context.NativeType(generatorOptions.dateImplementation, { serializedType: 'java.lang.String', }); case types_1.CodegenSchemaType.TIME: return new context.NativeType(generatorOptions.timeImplementation, { serializedType: 'java.lang.String', }); case types_1.CodegenSchemaType.DATETIME: return new context.NativeType(generatorOptions.dateTimeImplementation, { serializedType: 'java.lang.String', }); case types_1.CodegenSchemaType.STRING: { if (format === 'byte') { /* base64 encoded characters */ return new context.NativeType('java.lang.String'); } else if (format === 'uuid') { return new context.NativeType('java.util.UUID', { serializedType: 'java.lang.String', }); } else if (format === 'url') { return new context.NativeType('java.net.URL', { serializedType: 'java.lang.String', }); } else { return new context.NativeType('java.lang.String'); } } case types_1.CodegenSchemaType.BOOLEAN: { return new context.NativeType('java.lang.Boolean'); } case types_1.CodegenSchemaType.BINARY: { return new context.NativeType(generatorOptions.binaryRepresentation); } case types_1.CodegenSchemaType.FILE: { return new context.NativeType(generatorOptions.fileRepresentation); } case types_1.CodegenSchemaType.ANY: { return new context.NativeType('java.lang.Object'); } } throw new Error(`Unsupported schema type: ${schemaType}`); }, toNativeObjectType: function (options) { const { scopedName } = options; let modelName = `${generatorOptions.modelPackage}`; for (const name of scopedName) { modelName += `.${context.generator().toClassName(name)}`; } return new context.NativeType(modelName); }, toNativeArrayType: (options) => { const { componentNativeType, uniqueItems } = options; if (uniqueItems) { if (options.purpose !== types_1.CodegenSchemaPurpose.PARAMETER) { return new context.TransformingNativeType(componentNativeType, { /* We use LinkedHashSet everywhere to make it clear to all users of the API that it's ordered and unique. This also means we don't need to tell Jackson to use LinkedHashSet when deserializing. NOTE: CXF doesn't support LinkedHashSet for parameters (see InjectionUtils.getCollectionType()) so we exclude parameters. */ default: (nativeType) => `java.util.LinkedHashSet<${(nativeType.componentType || nativeType).nativeType}>`, literalType: () => 'java.util.LinkedHashSet', concreteType: (nativeType) => `java.util.LinkedHashSet<${(nativeType.componentType || nativeType).nativeType}>`, }); } else { return new context.TransformingNativeType(componentNativeType, { default: (nativeType) => `java.util.Set<${(nativeType.componentType || nativeType).nativeType}>`, literalType: () => 'java.util.Set', concreteType: (nativeType) => `java.util.HashSet<${(nativeType.componentType || nativeType).nativeType}>`, }); } } else { return new context.TransformingNativeType(componentNativeType, { default: (nativeType) => `java.util.List<${(nativeType.componentType || nativeType).nativeType}>`, literalType: () => 'java.util.List', concreteType: (nativeType) => `java.util.ArrayList<${(nativeType.componentType || nativeType).nativeType}>`, }); } }, toNativeMapType: (options) => { const { keyNativeType, componentNativeType } = options; return new context.ComposingNativeType([keyNativeType, componentNativeType], { default: ([keyNativeType, componentNativeType]) => `java.util.Map<${(keyNativeType.componentType || keyNativeType).nativeType}, ${(componentNativeType.componentType || componentNativeType).nativeType}>`, literalType: () => 'java.util.Map', concreteType: ([keyNativeType, componentNativeType]) => `java.util.HashMap<${(keyNativeType.componentType || keyNativeType).nativeType}, ${(componentNativeType.componentType || componentNativeType).nativeType}>`, }); }, nativeTypeUsageTransformer: ({ required, nullable }) => ({ nativeType: function (nativeType, nativeTypeString) { const primitive = required && !nullable; if (primitive) { if (nativeTypeString === 'java.lang.Integer') { return 'int'; } else if (nativeTypeString === 'java.lang.Boolean') { return 'boolean'; } else if (nativeTypeString === 'java.lang.Long') { return 'long'; } else if (nativeTypeString === 'java.lang.Float') { return 'float'; } else if (nativeTypeString === 'java.lang.Double') { return 'double'; } else if (nativeTypeString === 'java.lang.Byte') { return 'byte'; } } return nativeTypeString; }, componentType: { default: function (nativeType, nativeTypeString) { /* Return the original type so none of our transformations above apply to the type when used as a component. Particularly, we mustn't use our primitive transformations as primitives can't be components, e.g. java.util.List<int> */ return nativeTypeString; }, }, }), defaultValue: (options) => { const { schemaType } = options; switch (schemaType) { case types_1.CodegenSchemaType.ENUM: case types_1.CodegenSchemaType.DATE: case types_1.CodegenSchemaType.TIME: case types_1.CodegenSchemaType.DATETIME: case types_1.CodegenSchemaType.BINARY: case types_1.CodegenSchemaType.FILE: case types_1.CodegenSchemaType.OBJECT: case types_1.CodegenSchemaType.STRING: case types_1.CodegenSchemaType.ARRAY: case types_1.CodegenSchemaType.MAP: case types_1.CodegenSchemaType.INTERFACE: return { value: null, literalValue: 'null' }; case types_1.CodegenSchemaType.NUMBER: { const literalValue = context.generator().toLiteral(0.0, options); if (literalValue === null) { return null; } return { value: 0.0, literalValue }; } case types_1.CodegenSchemaType.INTEGER: { const literalValue = context.generator().toLiteral(0, options); if (literalValue === null) { return null; } return { value: 0, literalValue }; } case types_1.CodegenSchemaType.BOOLEAN: { const literalValue = context.generator().toLiteral(false, options); if (literalValue === null) { return null; } return { value: false, literalValue }; } } throw new Error(`Unsupported default value type: ${schemaType}`); }, initialValue: (options) => { const { required, schemaType, nativeType, defaultValue } = options; /* Default values in the spec are intended to be applied when a client or server receives a response or request, respectively, and values are missing. This implementation means that properties with defaults will get those default values as their initial value, meaning that any properties that are omitted in the _received_ request or response will have the default value. TODO But it also means that any requests or responses _sent_ will _also_ have the default values, rather than omitting the property and letting the receiving side apply the default value. This is NOT according to the spec and should be fixed. */ if (defaultValue) { return defaultValue; } if (!required) { return null; } /* We create empty collections for required properties in the Java code. This is because we generate convenience methods for collections that initialise the collection when adding the first element, which would mean if we didn't initialise required collection properties we might end up sending a null collection value if the code didn't _add_ any elements. This would then require explicitly initialising each required collection in user code, either every time, or whenever no elements are added to it. Therfore we are not able to detect whether the user code has forgotten to populate the collection, like we are with scalar required properties, so we populate it with an empty collection so we always generate a valid result. */ switch (schemaType) { case types_1.CodegenSchemaType.ARRAY: /* Initialise required array properties with an empty array */ return { value: [], literalValue: `new ${nativeType.concreteType}()` }; case types_1.CodegenSchemaType.MAP: /* Initialise empty map properties with an empty map */ return { value: {}, literalValue: `new ${nativeType.concreteType}()` }; default: return null; } }, operationGroupingStrategy: () => { return context.operationGroupingStrategies.addToGroupsByTagOrPath; }, allOfStrategy: () => types_1.CodegenAllOfStrategy.OBJECT, anyOfStrategy: () => types_1.CodegenAnyOfStrategy.OBJECT, oneOfStrategy: () => types_1.CodegenOneOfStrategy.INTERFACE, supportsInheritance: () => true, supportsMultipleInheritance: () => false, nativeCompositionCanBeScope: () => false, nativeComposedSchemaRequiresName: () => false, nativeComposedSchemaRequiresObjectLikeOrWrapper: () => false, interfaceCanBeNested: () => true, watchPaths: () => { const result = [path_1.default.resolve(__dirname, '..', 'templates')]; if (context.additionalWatchPaths) { result.push(...context.additionalWatchPaths()); } if (generatorOptions.customTemplatesPath) { result.push(generatorOptions.customTemplatesPath); } return result; }, cleanPathPatterns: () => { const relativeSourceOutputPath = generatorOptions.relativeSourceOutputPath; const modelPackagePath = packageToPath(generatorOptions.modelPackage); const validationPackagePath = packageToPath(generatorOptions.validationPackage); const result = [ path_1.default.join(relativeSourceOutputPath, modelPackagePath, '*.java'), path_1.default.join(relativeSourceOutputPath, validationPackagePath, 'Request.java'), path_1.default.join(relativeSourceOutputPath, validationPackagePath, 'Response.java'), ]; if (context.additionalCleanPathPatterns) { result.push(...context.additionalCleanPathPatterns()); } return result; }, templateRootContext: () => { return Object.assign(Object.assign(Object.assign({}, aCommonGenerator.templateRootContext()), generatorOptions), { generatorClass: '@openapi-generator-plus/java-jaxrs-generator' }); }, exportTemplates: async (outputPath, doc) => { const hbs = handlebars_1.default.create(); (0, handlebars_templates_1.registerStandardHelpers)(hbs, context); hbs.registerHelper('getter', function (property) { if (property.schema.schemaType === types_1.CodegenSchemaType.BOOLEAN && property.required && !property.nullable) { return `is${(0, generator_common_1.capitalize)(context.generator().toIdentifier(property.name))}`; } else { return `get${(0, generator_common_1.capitalize)(context.generator().toIdentifier(property.name))}`; } }); hbs.registerHelper('setter', function (property) { return `set${(0, generator_common_1.capitalize)(context.generator().toIdentifier(property.name))}`; }); hbs.registerHelper('escapeString', function (value) { // eslint-disable-next-line prefer-rest-params const options = arguments[arguments.length - 1]; try { return escapeString(value); } catch (error) { throw new Error(`${error instanceof Error ? error.message : error} @ ${(0, handlebars_templates_1.sourcePosition)(options)}`); } }); hbs.registerHelper('javax', function () { if (generatorOptions.useJakarta) { return 'jakarta'; } else { return 'javax'; } }); await (0, handlebars_templates_1.loadTemplates)(path_1.default.resolve(__dirname, '..', 'templates'), hbs); if (context.loadAdditionalTemplates) { await context.loadAdditionalTemplates(hbs); } if (generatorOptions.customTemplatesPath) { await (0, handlebars_templates_1.loadTemplates)(generatorOptions.customTemplatesPath, hbs); } const rootContext = context.generator().templateRootContext(); const relativeSourceOutputPath = generatorOptions.relativeSourceOutputPath; const relativeTestOutputPath = generatorOptions.relativeTestOutputPath; /* Augment operations */ for (const groups of doc.groups) { for (const operation of groups.operations) { /* We use a params object if an operation has multiple parameters */ operation.useParamsClasses = generatorOptions.apiParamsPackage && operation.parameters ? idx.size(operation.parameters) > 1 : false; } } const modelPackagePath = packageToPath(generatorOptions.modelPackage); for (const schema of context.utils.values(doc.schemas)) { if ((0, types_1.isCodegenObjectSchema)(schema)) { await (0, handlebars_templates_1.emit)('pojo', path_1.default.join(outputPath, relativeSourceOutputPath, modelPackagePath, `${context.generator().toClassName(schema.name)}.java`), Object.assign(Object.assign({}, rootContext), { pojo: schema }), true, hbs); } else if ((0, types_1.isCodegenEnumSchema)(schema)) { await (0, handlebars_templates_1.emit)('enum', path_1.default.join(outputPath, relativeSourceOutputPath, modelPackagePath, `${context.generator().toClassName(schema.name)}.java`), Object.assign(Object.assign({}, rootContext), { enum: schema }), true, hbs); } else if ((0, types_1.isCodegenInterfaceSchema)(schema)) { await (0, handlebars_templates_1.emit)('interface', path_1.default.join(outputPath, relativeSourceOutputPath, modelPackagePath, `${context.generator().toClassName(schema.name)}.java`), Object.assign(Object.assign({}, rootContext), { interface: schema }), true, hbs); } else if ((0, types_1.isCodegenWrapperSchema)(schema)) { await (0, handlebars_templates_1.emit)('wrapper', path_1.default.join(outputPath, relativeSourceOutputPath, modelPackagePath, `${context.generator().toClassName(schema.name)}.java`), Object.assign(Object.assign({}, rootContext), { schema }), true, hbs); } } if (generatorOptions.useBeanValidation) { const validationPackagePath = packageToPath(generatorOptions.validationPackage); await (0, handlebars_templates_1.emit)('validation/Request', path_1.default.join(outputPath, relativeSourceOutputPath, validationPackagePath, 'Request.java'), rootContext, true, hbs); await (0, handlebars_templates_1.emit)('validation/Response', path_1.default.join(outputPath, relativeSourceOutputPath, validationPackagePath, 'Response.java'), rootContext, true, hbs); } const maven = generatorOptions.maven; if (maven) { await (0, handlebars_templates_1.emit)('pom', path_1.default.join(outputPath, 'pom.xml'), Object.assign(Object.assign({}, rootContext), maven), false, hbs); } if (generatorOptions.includeTests && hbs.partials['tests/apiTest']) { const apiPackagePath = packageToPath(generatorOptions.apiPackage); for (const group of doc.groups) { const operations = group.operations; if (!operations.length) { continue; } await (0, handlebars_templates_1.emit)('tests/apiTest', path_1.default.join(outputPath, relativeTestOutputPath, apiPackagePath, `${context.generator().toClassName(group.name)}ApiTest.java`), Object.assign(Object.assign({}, rootContext), group), false, hbs); } } if (context.additionalExportTemplates) { await context.additionalExportTemplates(outputPath, doc, hbs, rootContext); } }, postProcessDocument: (doc) => { for (const group of doc.groups) { for (const op of group.operations) { /* Fix form post request bodies, as we can't properly handle them using https://docs.oracle.com/javaee/7/api/javax/ws/rs/BeanParam.html yet */ if (op.requestBody && op.consumes && op.consumes[0].mimeType === 'application/x-www-form-urlencoded') { op.requestBody.nativeType = context.formUrlEncodedImplementation ? context.formUrlEncodedImplementation() : new context.NativeType(`${generatorOptions.useJakarta ? 'jakarta' : 'javax'}.ws.rs.core.MultivaluedHashMap<java.lang.String, java.lang.String>`); } } } }, postProcessSchema(schema) { checkCannotUseDeduction(schema); }, checkPropertyCompatibility: (parentProp, childProp) => { if (!baseGenerator.checkPropertyCompatibility(parentProp, childProp)) { return false; } /* Because in Java we use a java.util.Optional if a property is nullable, properties are not compatible if their nullability varies. */ if (!parentProp.nullable !== !childProp.nullable) { return false; } return true; } }); } exports.default = createGenerator; /** * Identify polymorphic schemas that cannot use Jackson's DEDUCTION polymorphism, as it only supports object structures. */ function checkCannotUseDeduction(schema) { if ((0, types_1.isCodegenObjectSchema)(schema) && schema.polymorphic && schema.children) { schema.__cannotUseDeduction = false; for (const child of schema.children) { if (child.type !== 'object') { schema.__cannotUseDeduction = true; break; } } } if ((0, types_1.isCodegenInterfaceSchema)(schema) && schema.polymorphic && schema.implementors) { schema.__cannotUseDeduction = false; for (const impl of schema.implementors) { if (impl.type !== 'object') { schema.__cannotUseDeduction = true; break; } } } }