From 6fff2a620b162264fd796af54502f961f3039378 Mon Sep 17 00:00:00 2001 From: "Thomas, Eiko" Date: Wed, 24 Oct 2018 13:31:12 +0200 Subject: [PATCH 1/3] improvements of main type printing --- Releases.md | 5 ++ .../groovy/de/lisaplus/atlas/DoCodeGen.groovy | 46 +++++++++++- .../atlas/builder/JsonSchemaBuilder.groovy | 75 ++++++++++++------- .../de/lisaplus/atlas/model/Type.groovy | 36 +++++++++ .../test/jsonschema/JsonSchemaBuilder.groovy | 46 ++++++++++++ 5 files changed, 177 insertions(+), 31 deletions(-) diff --git a/Releases.md b/Releases.md index 13bce63..150f0d7 100644 --- a/Releases.md +++ b/Releases.md @@ -1,3 +1,8 @@ +## 0.8.1 +- add to types schemaPath and schemaFileName attributes (to finally detect what are the interesting main types of a model) +- add a isMainType function to model type +- add command line switches pro print only main types + ## 0.8.0 - command line switches for type black- and white-lists - command line switch to add tags to types diff --git a/src/main/groovy/de/lisaplus/atlas/DoCodeGen.groovy b/src/main/groovy/de/lisaplus/atlas/DoCodeGen.groovy index e866789..7bd3f03 100644 --- a/src/main/groovy/de/lisaplus/atlas/DoCodeGen.groovy +++ b/src/main/groovy/de/lisaplus/atlas/DoCodeGen.groovy @@ -40,7 +40,7 @@ class DoCodeGen { /** * Base directory for the output */ - @Parameter(names = [ '-o', '--outputBase' ], description = "Base directory for the output", required = true) + @Parameter(names = [ '-o', '--outputBase' ], description = "Base directory for the output") String outputBaseDir /** @@ -73,6 +73,25 @@ class DoCodeGen { @Parameter(names = ['-h','--help'], help = true) boolean help = false + /** + * Simply print main types + */ + @Parameter(names = ['-pmt','--print-main-types'], description = "don't do any code generation, simply loads the model and print the main-types of it") + boolean printMainTypes = false + + @Parameter(names = ['-pmts','--print-main-types-separator'], description = "separator to use for printing main types") + String printMainTypesSeparator + + @Parameter(names = ['-pmti','--print-main-types-info'], description = "print with info header") + boolean printMainTypesInfo = false + + /** + * an required type property to include into main types + */ + @Parameter(names = ['-pmta','--print-main-types-attrib'], description = "don't do any code generation, simply loads the model and print the main-types of it") + String mainTypeAttrib + + /** * List of type-name tag-text tuple, The tags will be merged after initialization with the object tree */ @@ -129,8 +148,6 @@ class DoCodeGen { log.info("use model file: ${model}") } - prepareOutputBaseDir(outputBaseDir) - IModelBuilder builder = model.toLowerCase().endsWith('.json') ? new JsonSchemaBuilder() : model.toLowerCase().endsWith('.xsd') ? new XSDBuilder() : null if (builder==null) { @@ -138,7 +155,11 @@ class DoCodeGen { System.exit(1) } dataModel = builder.buildModel(modelFile) + printMainTypesIfNeeded(dataModel,modelFile.getName()) + adjustTagsForModel(dataModel) + prepareOutputBaseDir(outputBaseDir) + // convert extra generator parameter to a map Map extraParameters = getMapFromGeneratorParams(generator_parameters) extraParameters['blackListed']=blackListed @@ -166,6 +187,25 @@ class DoCodeGen { } } + void printMainTypesIfNeeded(Model dataModel, String fileName) { + if (printMainTypes) { + def mfn = fileName + String separator = printMainTypesSeparator ? printMainTypesSeparator : ' ' + def attrib = mainTypeAttrib ? " - needed attrib: $mainTypeAttrib" : '' + def info = "mainTypes [$mfn$attrib]:" + def outStr = printMainTypesInfo ? info : '' + dataModel.types.each { type -> + if (type.isMainType(mfn)) { + if ((!mainTypeAttrib) || (type.hasPropertyWithName(mainTypeAttrib))) { + outStr = "${outStr}${separator}${type.name}" + } + } + } + println (outStr) + System.exit(0) + } + } + /** * splits extra generator parameter to Map values * expected entries looks like this: packageBase=de.sw.atlas diff --git a/src/main/groovy/de/lisaplus/atlas/builder/JsonSchemaBuilder.groovy b/src/main/groovy/de/lisaplus/atlas/builder/JsonSchemaBuilder.groovy index 18a1ec8..3260968 100644 --- a/src/main/groovy/de/lisaplus/atlas/builder/JsonSchemaBuilder.groovy +++ b/src/main/groovy/de/lisaplus/atlas/builder/JsonSchemaBuilder.groovy @@ -62,7 +62,7 @@ class JsonSchemaBuilder implements IModelBuilder { Model model = initModel(objectModel) if (objectModel['definitions']) { // multi type schema - loadSchemaTypes(objectModel,currentSchemaPath,model) + loadSchemaTypes(objectModel,modelFile.getName(),currentSchemaPath,model) } if (objectModel['allOf']) { // single type schema @@ -104,16 +104,18 @@ class JsonSchemaBuilder implements IModelBuilder { typeName = string2Name(typeName) Type newType = new Type() newType.name = typeName + newType.schemaPath = currentSchemaPath + newType.schemaFileName = modelFileName newType.description = strFromMap(objectModel,'description') if (objectModel.allOf) { // TODO - add allof Properties objectModel.allOf.each { allOfElem -> if (allOfElem.properties) { - newType.properties.addAll(getProperties(model,allOfElem,typeName,currentSchemaPath)) + newType.properties.addAll(getProperties(model,allOfElem,typeName,modelFileName,currentSchemaPath)) } else { if (allOfElem.'$ref') { - RefType tmp = initRefType(allOfElem.'$ref',currentSchemaPath) + RefType tmp = initRefType(allOfElem.'$ref',modelFileName,currentSchemaPath) newType.properties.addAll(tmp.type.properties) newType.baseTypes.add(tmp.type.name) } @@ -121,7 +123,7 @@ class JsonSchemaBuilder implements IModelBuilder { } } else { - newType.properties = getProperties(model,objectModel,typeName,currentSchemaPath) + newType.properties = getProperties(model,objectModel,typeName,modelFileName,currentSchemaPath) } if (objectModel.'__tags') { newType.tags=objectModel.'__tags' @@ -150,25 +152,26 @@ class JsonSchemaBuilder implements IModelBuilder { } } - - private Model loadSchemaTypes(def objectModel,String currentSchemaPath,Model model) { + private Model loadSchemaTypes(def objectModel, String schemaFileName,String currentSchemaPath,Model model) { if (model==null) model = initModel(objectModel) objectModel.definitions.each { typeObj -> def typeName = string2Name(typeObj.key) Type newType = new Type() newType.name = typeName + newType.schemaPath = currentSchemaPath + newType.schemaFileName = schemaFileName newType.description = strFromMap(typeObj.value,'description') newType.properties = [] if (typeObj.value.allOf) { // TODO - add allof Properties typeObj.value.allOf.each { allOfElem -> if (allOfElem.properties) { - newType.properties.addAll(getProperties(model,allOfElem,typeName,currentSchemaPath)) + newType.properties.addAll(getProperties(model,allOfElem,typeName,schemaFileName,currentSchemaPath)) } else { if (allOfElem.'$ref') { - RefType tmp = initRefType(allOfElem.'$ref',currentSchemaPath) + RefType tmp = initRefType(allOfElem.'$ref',schemaFileName,currentSchemaPath) newType.properties.addAll(tmp.type.properties) newType.baseTypes.add(tmp.type.name) } @@ -177,12 +180,12 @@ class JsonSchemaBuilder implements IModelBuilder { } else if (typeObj.value.'$ref') { // this type refers to an external definition - RefType tmp = initRefType(typeObj.value.'$ref', currentSchemaPath) + RefType tmp = initRefType(typeObj.value.'$ref', schemaFileName, currentSchemaPath) newType.properties.addAll(tmp.type.properties) newType.baseTypes.add(tmp.type.name) } else { - newType.properties = getProperties(model,typeObj.value,typeName,currentSchemaPath) + newType.properties = getProperties(model,typeObj.value,typeName,schemaFileName,currentSchemaPath) } if (typeObj.value.'__tags') { newType.tags=typeObj.value.'__tags' @@ -226,10 +229,10 @@ class JsonSchemaBuilder implements IModelBuilder { model.types.add(newType) } - private List getProperties(Model model,def propertyParent,def parentName,String currentSchemaPath) { + private List getProperties(Model model,def propertyParent,def parentName,String schemaFileName, String currentSchemaPath) { List propList = [] propertyParent.properties.each { propObj -> - propList.add(creeateSimpleProperty(model, parentName,currentSchemaPath,propObj)) + propList.add(creeateSimpleProperty(model, parentName,schemaFileName,currentSchemaPath,propObj)) } // Dirty hack for enabling the usage of mongoDB Index2d: // For performing filtering on geo coordinates in Documents of the mongoDB (e.g. operation geoWithin), the Json @@ -250,12 +253,12 @@ class JsonSchemaBuilder implements IModelBuilder { return propList } - private Property creeateSimpleProperty (Model model, def parentName,String currentSchemaPath,def propObj) { + private Property creeateSimpleProperty (Model model, def parentName,String schemaFileName,String currentSchemaPath, def propObj) { def newProp = new Property() newProp.name = string2Name(propObj.key, false) newProp.description = propObj.value['description'] String key = makeCamelCase(propObj.key) - newProp.type = getPropertyType(model, propObj.value, parentName + string2Name(key), currentSchemaPath) + newProp.type = getPropertyType(model, propObj.value, parentName + string2Name(key),schemaFileName, currentSchemaPath) if (newProp.type instanceof RefType) { if (propObj.key.toLowerCase().endsWith('_id') || propObj.key.toLowerCase().endsWith('Id')) { // per convention newProp.aggregationType = AggregationType.aggregation @@ -276,16 +279,16 @@ class JsonSchemaBuilder implements IModelBuilder { // implicit refs for normal types and array types differ if (newProp.type.isArray) { if (propObj.value.items.'__ref') { - newProp.implicitRef = initRefType(propObj.value.items.'__ref', currentSchemaPath) + newProp.implicitRef = initRefType(propObj.value.items.'__ref', schemaFileName, currentSchemaPath) } } else { if (propObj.value.'__ref') { - newProp.implicitRef = initRefType(propObj.value.'__ref', currentSchemaPath) + newProp.implicitRef = initRefType(propObj.value.'__ref', schemaFileName, currentSchemaPath) } } if (propObj.value.'__ref') { - newProp.implicitRef = initRefType(propObj.value.'__ref', currentSchemaPath) + newProp.implicitRef = initRefType(propObj.value.'__ref', schemaFileName, currentSchemaPath) } if (propObj.value.'__tags') { newProp.tags=propObj.value.'__tags' @@ -293,10 +296,10 @@ class JsonSchemaBuilder implements IModelBuilder { return newProp } - private BaseType getPropertyType(Model model,def propObjMap,def innerTypeBaseName,String currentSchemaPath) { + private BaseType getPropertyType(Model model,def propObjMap,def innerTypeBaseName, String schemaFileName,String currentSchemaPath) { if (propObjMap.'$ref') { // reference to an external type - return initRefType(propObjMap.'$ref',currentSchemaPath) + return initRefType(propObjMap.'$ref', schemaFileName,currentSchemaPath) } else if (! propObjMap.type) { def errorMsg = "property object w/o any type: ${propObjMap}" @@ -304,11 +307,11 @@ class JsonSchemaBuilder implements IModelBuilder { throw new Exception(errorMsg) } else { - return getBaseTypeFromString(model,currentSchemaPath,propObjMap,innerTypeBaseName) + return getBaseTypeFromString(model,schemaFileName,currentSchemaPath,propObjMap,innerTypeBaseName) } } - private RefType initRefType(def refStr,String currentSchemaPath) { + private RefType initRefType(def refStr,String schemaFileName,String currentSchemaPath) { if (!refStr) { def errorMsg = "undefined refStr, so cancel init reference type" log.error(errorMsg) @@ -323,6 +326,10 @@ class JsonSchemaBuilder implements IModelBuilder { if (refStr.startsWith(localDefStrBase)) { def schemaTypeName = refStr.substring(localDefStrBase.length()) Type t = getLocalRefType(schemaTypeName) + if (!t.schemaPath) { + t.schemaPath = currentSchemaPath + t.schemaFileName = schemaFileName + } if (t instanceof DummyType) { // the needed type isn't already in the model created. later a update to the // right references is needed @@ -337,6 +344,10 @@ class JsonSchemaBuilder implements IModelBuilder { // "$ref": "definitions.json#/address" // "$ref": "http: //json-schema.org/geo" - HTTP not supported (eiko) Type t = getExternalRefType(refStr,currentSchemaPath) + if (!t.schemaPath) { + t.schemaPath = currentSchemaPath + t.schemaFileName = schemaFileName + } refType.type=t refType.typeName=t.name } @@ -368,6 +379,8 @@ class JsonSchemaBuilder implements IModelBuilder { tmpModel.types.each { type -> if ((type.name!=null) && (type.name.toLowerCase()==desiredName)) { extT2 = type + extT2.schemaPath = currentSchemaPath + extT2.schemaFileName = fileName } } if (extT2==null) { @@ -394,6 +407,10 @@ class JsonSchemaBuilder implements IModelBuilder { Type tmpT = tmpModel.types.find { ! (it instanceof InnerType) } + if (!tmpT.schemaPath) { + tmpT.schemaPath = currentSchemaPath + tmpT.schemaFileName = fileName + } extT.refStr = refStr extT.initFromType(tmpT) // can be removed, because it's identical to the early init call (*1) @@ -445,7 +462,7 @@ class JsonSchemaBuilder implements IModelBuilder { } - private ComplexType initComplexType(Model model,def propertiesParent,def baseTypeName, String currentSchemaPath) { + private ComplexType initComplexType(Model model,def propertiesParent,def baseTypeName, String schemaFileName, String currentSchemaPath) { if (!propertiesParent) { def errorMsg = "undefined properties map, so cancel init complex type" log.error(errorMsg) @@ -454,13 +471,15 @@ class JsonSchemaBuilder implements IModelBuilder { ComplexType complexType = new ComplexType() Type newType = new InnerType() newType.name = baseTypeName - newType.properties = getProperties(model,propertiesParent,baseTypeName,currentSchemaPath) + newType.schemaPath = currentSchemaPath + newType.schemaFileName = schemaFileName + newType.properties = getProperties(model,propertiesParent,baseTypeName,schemaFileName,currentSchemaPath) complexType.type = newType addNewType(newType,model) return complexType } - private BaseType getBaseTypeFromString(Model model,String currentSchemaPath,def propObjMap, def innerTypeBaseName, def isArrayAllowed=true) { + private BaseType getBaseTypeFromString(Model model,String schemaFileName, String currentSchemaPath,def propObjMap, def innerTypeBaseName, def isArrayAllowed=true) { switch (propObjMap.type) { case 'string': if (propObjMap.format && propObjMap.format.toLowerCase()=="uuid") { @@ -490,7 +509,7 @@ class JsonSchemaBuilder implements IModelBuilder { return new UnsupportedType() } else - return initComplexType(model,propObjMap,innerTypeBaseName,currentSchemaPath) + return initComplexType(model,propObjMap,innerTypeBaseName,schemaFileName,currentSchemaPath) case 'array': /* if (!isArrayAllowed) { @@ -503,14 +522,14 @@ class JsonSchemaBuilder implements IModelBuilder { // test - eiko // BaseType ret = getBaseTypeFromString(model,currentSchemaPath,propObjMap.items,innerTypeBaseName+'Item',false) if (propObjMap.items.type=='array') { - BaseType tmp = getBaseTypeFromString(model,currentSchemaPath,propObjMap.items,innerTypeBaseName+'Item') + BaseType tmp = getBaseTypeFromString(model,schemaFileName,currentSchemaPath,propObjMap.items,innerTypeBaseName+'Item') ArrayType ret = new ArrayType() ret.isArray = true ret.baseType = tmp return ret } else { - BaseType ret = getBaseTypeFromString(model,currentSchemaPath,propObjMap.items,innerTypeBaseName+'Item') + BaseType ret = getBaseTypeFromString(model,schemaFileName,currentSchemaPath,propObjMap.items,innerTypeBaseName+'Item') ret.isArray = true // the attrib has an _t_tags entry ... if (propObjMap.'__tags') { @@ -523,7 +542,7 @@ class JsonSchemaBuilder implements IModelBuilder { } } else if (propObjMap.items['$ref']) { - BaseType ret = initRefType(propObjMap.items['$ref'],currentSchemaPath) + BaseType ret = initRefType(propObjMap.items['$ref'],schemaFileName,currentSchemaPath) ret.isArray = true return ret } diff --git a/src/main/groovy/de/lisaplus/atlas/model/Type.groovy b/src/main/groovy/de/lisaplus/atlas/model/Type.groovy index cafa365..4f0ad7a 100644 --- a/src/main/groovy/de/lisaplus/atlas/model/Type.groovy +++ b/src/main/groovy/de/lisaplus/atlas/model/Type.groovy @@ -20,6 +20,16 @@ class Type { */ String color='#000000' + /** + * path where the schema for that type was located + */ + String schemaPath + + /** + * path where the schema for that type was located + */ + private String schemaFileName + /** * List of properties, type of PropertyType */ @@ -96,12 +106,24 @@ class Type { // TODO Check whether incomplete initialization is necessary / intended! this.name = t.name this.tags = t.tags + this.schemaPath = t.schemaPath + this.schemaFileName = t.schemaFileName this.properties = t.properties this.description = t.description this.requiredProps = t.requiredProps this.sinceVersion = t.sinceVersion } + /** + * + * @param model string of the model file name: f.e. junction, junction.json + */ + boolean isMainType(String model) { + if (model==null || this.schemaFileName==null) return false + String mStr = model.indexOf('.')!=-1 ? model.substring(0,model.lastIndexOf('.')) : model + return (!this.innerType) && this.schemaFileName==mStr + } + boolean equals(Object b) { if (! b instanceof Type) return false return name==b.name @@ -162,6 +184,20 @@ class Type { } return copy } + + String getSchemaFileName() { + return schemaFileName + } + + void setSchemaFileName(String schemaFileName) { + this.schemaFileName = schemaFileName + if (this.schemaFileName!=null) { + this.schemaFileName = this.schemaFileName.replaceAll('\\.json','') + this.schemaFileName = this.schemaFileName.replaceAll('\\.xsd','') + this.schemaFileName = this.schemaFileName.replaceAll('\\.','') + this.schemaFileName = this.schemaFileName.replaceAll('/','') + } + } } /** diff --git a/src/test/groovy/de/lisaplus/atlas/builder/test/jsonschema/JsonSchemaBuilder.groovy b/src/test/groovy/de/lisaplus/atlas/builder/test/jsonschema/JsonSchemaBuilder.groovy index 8cef4ad..c1f9eaa 100644 --- a/src/test/groovy/de/lisaplus/atlas/builder/test/jsonschema/JsonSchemaBuilder.groovy +++ b/src/test/groovy/de/lisaplus/atlas/builder/test/jsonschema/JsonSchemaBuilder.groovy @@ -6,6 +6,7 @@ import de.lisaplus.atlas.model.AggregationType import org.junit.Test import static org.junit.Assert.assertEquals +import static org.junit.Assert.assertFalse import static org.junit.Assert.assertNotNull import static org.junit.Assert.assertTrue @@ -247,4 +248,49 @@ class JsonSchemaBuilder { assertEquals(2,tagCount) } + + @Test + void testSchemaPath() { + def modelFile = new File('src/test/resources/test_schemas/ds/junction.json') + assertTrue(modelFile.isFile()) + def builder = new de.lisaplus.atlas.builder.JsonSchemaBuilder() + def model = builder.buildModel(modelFile) + assertNotNull(model) + model.types.each { type -> + assertNotNull(type.schemaPath) + assertNotNull(type.schemaFileName) + println "schema-path: ${type.schemaPath}, filename: ${type.schemaFileName}" + } + } + + @Test + void testMainTypes() { + def modelFile = new File('src/test/resources/test_schemas/ds/junction.json') + assertTrue(modelFile.isFile()) + def builder = new de.lisaplus.atlas.builder.JsonSchemaBuilder() + def model = builder.buildModel(modelFile) + assertNotNull(model) + model.types.each { type -> + println "type-name: ${type.name}" + if (type.name=='Junction') { + assertTrue (type.isMainType('junction')) + } + else if (type.name=='JunctionDocument') { + assertTrue (type.isMainType('junction')) + } + else if (type.name=='JunctionComment') { + assertTrue (type.isMainType('junction')) + } + else if (type.name=='JunctionState') { + assertTrue (type.isMainType('junction')) + } + else if (type.name=='JunctionType') { + assertTrue (type.isMainType('junction')) + } + else { + assertFalse (type.isMainType('junction')) + } + } + } + } From d235b7f411c05f161f95bed927469d9b7fcafaec Mon Sep 17 00:00:00 2001 From: "Thomas, Eiko" Date: Wed, 24 Oct 2018 13:34:35 +0200 Subject: [PATCH 2/3] modify README --- README.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6e098c0..2d72f3f 100644 --- a/README.md +++ b/README.md @@ -102,10 +102,25 @@ Usage: de.lisaplus.atlas.DoCodeGen [options] * -m, --model Path to JSON schema to parse - * -o, --outputBase + -o, --outputBase Base directory for the output + -pmt, --print-main-types + don't do any code generation, simply loads the model and print the + main-types of it + Default: false + -pmta, --print-main-types-attrib + don't do any code generation, simply loads the model and print the + main-types of it + -pmti, --print-main-types-info + print with info header + Default: false + -pmts, --print-main-types-separator + separator to use for printing main types -rt, --remove-tag - remove a tag from a specific type, f.e. -at User=unused + remove a tag from a specific type, f.e. -rt User=unused + Default: [] + -rta, --remove-tag-all + remove a tag from all model types, f.e. -rta rest Default: [] -w, --white-list white listed type, multiple usage possible From 1c95311001c4b947cd589fed9fe739019b89d37c Mon Sep 17 00:00:00 2001 From: "Thomas, Eiko" Date: Wed, 24 Oct 2018 13:35:04 +0200 Subject: [PATCH 3/3] increment project version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index bafecbd..6f419eb 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ sourceCompatibility = 1.8 def mainClass='de.lisaplus.atlas.DoCodeGen' project.group = 'de.lisaplus.tools' -project.version = '0.7.5' +project.version = '0.8.1' /* * the following attributes need to be declared in $HOME/.gradle/gradle.properties