@asyncapi/java-spring-cloud-stream-template
Version:
Java Spring Cloud Stream template for AsyncAPI generator.
173 lines (158 loc) • 6.96 kB
JavaScript
const ModelClass = require('./modelClass.js');
const debugApplicationModel = require('debug')('applicationModel');
const _ = require('lodash');
const ScsLib = require('./scsLib.js');
const scsLib = new ScsLib();
const instanceMap = new Map();
class ApplicationModel {
constructor(caller) {
this.caller = caller;
debugApplicationModel(`constructor for ${caller} ++++++++++++++++++++++++++++++++++++++++++`);
instanceMap.set(caller, this);
debugApplicationModel(instanceMap);
}
getModelClass({schema, schemaName}) {
debugApplicationModel(`getModelClass for caller ${this.caller} schema ${schemaName}`);
this.setupSuperClassMap();
this.setupModelClassMap();
let modelClass;
if (schema) {
const parserSchemaName = schema.ext('x-parser-schema-id');
// Try to use x-parser-schema-id as key
modelClass = this.modelClassMap[parserSchemaName];
if (modelClass && _.startsWith(modelClass.getClassName(), 'Anonymous')) {
// If we translated this schema from the map using an anonymous schema key, we have no idea what the name should be, so we use the one provided directly from the source - not the generator.
// Otherwise, if we translated this schema from the map using a known schema (the name of the schema was picked out correctly by the generator), use that name.
modelClass.setClassName(_.upperFirst(this.isAnonymousSchema(parserSchemaName) ? schemaName : parserSchemaName));
}
}
// Using x-parser-schema-id didn't work for us, fall back to trying to get at least something using the provided name.
if (!modelClass) {
modelClass = this.modelClassMap[schemaName] || this.modelClassMap[_.camelCase(schemaName)];
}
debugApplicationModel(`returning modelClass for caller ${this.caller} ${schemaName}`);
debugApplicationModel(modelClass);
return modelClass;
}
getSchema(schemaName) {
return ApplicationModel.asyncapi.components().schema(schemaName);
}
setupSuperClassMap() {
if (this.superClassMap) {
return;
}
this.superClassMap = new Map();
this.anonymousSchemaToSubClassMap = new Map();
debugApplicationModel('-------- SCHEMAS -------------');
debugApplicationModel(ApplicationModel.asyncapi.allSchemas());
ApplicationModel.asyncapi.allSchemas().forEach((schema, schemaName) => {
debugApplicationModel(`${schemaName}:`);
debugApplicationModel(schema);
const allOf = schema.allOf();
if (allOf) {
this.handleAllOfSchema(schema, schemaName, allOf);
}
});
debugApplicationModel('-----------------------------');
debugApplicationModel('superclassMap:');
debugApplicationModel(this.superClassMap);
debugApplicationModel('anonymousSchemaToSubClassMap:');
debugApplicationModel(this.anonymousSchemaToSubClassMap);
}
handleAllOfSchema(schema, schemaName, allOfSchema) {
let anonymousSchema;
let namedSchema;
allOfSchema.forEach(innerSchema => {
debugApplicationModel('=== allOf inner schema: ===');
debugApplicationModel(innerSchema);
debugApplicationModel('===========================');
const name = innerSchema._json['x-parser-schema-id'];
if (this.isAnonymousSchema(name)) {
anonymousSchema = name;
} else {
namedSchema = name;
}
});
if (!anonymousSchema || !namedSchema) {
console.log('Warning: Unable to find both an anonymous and a named schema in an allOf schema.');
console.log(schema);
} else {
this.superClassMap[anonymousSchema] = namedSchema;
this.anonymousSchemaToSubClassMap[anonymousSchema] = schemaName;
this.superClassMap[schemaName] = namedSchema;
this.anonymousSchemaToSubClassMap[schemaName] = anonymousSchema;
}
}
setupModelClassMap() {
if (this.modelClassMap) {
return;
}
this.modelClassMap = new Map();
this.nameToSchemaMap = new Map();
// Register all schemas recursively as a flat map of name -> ModelClass
ApplicationModel.asyncapi.allSchemas().forEach((schema, name) => {
debugApplicationModel(`setupModelClassMap ${name} type ${schema.type()}`);
this.registerSchemaNameToModelClass(schema, name);
this.nameToSchemaMap[name] = schema;
});
debugApplicationModel('modelClassMap:');
debugApplicationModel(this.modelClassMap);
}
isAnonymousSchema(schemaName) {
return schemaName.startsWith('<');
}
registerSchemaNameToModelClass(schema, schemaName) {
let modelClass = this.modelClassMap[schemaName];
if (!modelClass) {
modelClass = new ModelClass();
}
if (this.isAnonymousSchema(schemaName)) {
this.handleAnonymousSchemaForAllOf(modelClass, schemaName);
}
const components = ApplicationModel.asyncapi._json.components;
const nonInnerClassSchemas = Object.keys(components? components.schemas || {} : {});
if (nonInnerClassSchemas.includes(schemaName)) {
modelClass.setCanBeInnerClass(false);
}
const classNameAndLocation = scsLib.stripPackageName(schemaName);
let className = classNameAndLocation.className;
const javaPackage = classNameAndLocation.javaPackage;
if (schema._json['x-model-class-name']) {
className = schema._json['x-model-class-name'];
}
modelClass.setJavaPackage(javaPackage);
modelClass.setClassName(className);
debugApplicationModel(`schemaName ${schemaName} className: ${modelClass.getClassName()} super: ${modelClass.getSuperClassName()} javaPackage: ${javaPackage}`);
this.modelClassMap[schemaName] = modelClass;
debugApplicationModel(`Added ${schemaName}`);
debugApplicationModel(modelClass);
}
getAnonymousSchemaForRef(realSchemaName) {
// During our allOf parsing, we found this real schema to anon-schema association
const anonSchema = this.anonymousSchemaToSubClassMap[realSchemaName];
return anonSchema ? this.nameToSchemaMap[anonSchema] : undefined;
}
handleAnonymousSchemaForAllOf(modelClass, schemaName) {
const subclassName = this.anonymousSchemaToSubClassMap[schemaName];
if (subclassName) {
modelClass.setSuperClassName(this.superClassMap[schemaName]);
// Be sure the anonymous modelClass and the named modelClass are updated with the superclass information
// We dont want the anonymous schema because the class name won't be correct if it's a $ref, so if the modelClass exists, update that one, if it doesn't we'll make it
const existingModelClass = this.modelClassMap[subclassName];
if (existingModelClass) {
existingModelClass.setSuperClassName(this.superClassMap[schemaName]);
}
return subclassName;
}
return schemaName;
}
reset() {
instanceMap.forEach((val) => {
val.superClassMap = null;
val.anonymousSchemaToSubClassMap = null;
val.modelClassMap = null;
val.nameToSchemaMap = null;
});
}
}
module.exports = ApplicationModel;