From 9b917aa0d0bdee005f9a24dcb4da459ae2fcd87f Mon Sep 17 00:00:00 2001 From: SimonCockx <47859223+SimonCockx@users.noreply.github.com> Date: Fri, 13 Dec 2024 16:06:27 +0100 Subject: [PATCH] Attribute restrictions (#875) * Implemented syntax and validation * WIP * Implemented code gen * Fixed tests * Location fix * Relaxed errors * Fixed errors * Cleaned * Made metadata unmodifiable * Made metadata unmodifiable * Implemented autocompletion * Typos * Fix rule inheritance * Fixed * Auto-complete * Clean * Inherit deprecated annotation --- rosetta-ide/rosetta.tmLanguage.yaml | 4 + .../rosetta/ide/RosettaIdeModule.xtend | 6 + .../RosettaContentProposalProvider.java | 48 + .../ide/textmate/GenerateTmGrammar.java | 2 +- .../ide/contentassist/ContentAssistTest.xtend | 29 + rosetta-ide/vscode/package-lock.json | 1808 ++++------------- rosetta-ide/vscode/src/extension.ts | 6 +- rosetta-lang/model/Rosetta.xcore | 6 +- rosetta-lang/model/RosettaSimple.xcore | 4 +- .../java/com/regnosys/rosetta/Rosetta.xtext | 5 +- .../regnosys/rosetta/RosettaEcoreUtil.xtend | 126 +- .../rosetta/formatting2/FormattingUtil.java | 2 +- .../generator/java/enums/EnumGenerator.xtend | 2 +- .../expression/DeepPathUtilGenerator.xtend | 11 +- .../java/expression/ExpressionGenerator.xtend | 84 +- .../java/expression/TypeCoercionService.xtend | 177 +- .../java/function/FunctionGenerator.xtend | 84 +- .../java/object/MetaFieldGenerator.xtend | 209 +- .../java/object/ModelMetaGenerator.xtend | 6 +- .../java/object/ModelObjectBoilerPlate.xtend | 152 +- .../object/ModelObjectBuilderGenerator.xtend | 623 ++++-- .../java/object/ModelObjectGenerator.xtend | 259 +-- .../java/object/ValidatorsGenerator.xtend | 116 +- .../java/reports/TabulatorGenerator.xtend | 28 +- .../java/statement/JavaEnhancedForLoop.java | 52 + .../java/statement/builder/JavaVariable.java | 4 +- .../java/types/JavaPojoInterface.java | 82 + .../java/types/JavaPojoProperty.java | 115 ++ .../java/types/JavaTypeTranslator.java | 50 +- .../generator/java/types/JavaTypeUtil.java | 10 +- .../java/types/RJavaFieldWithMeta.java | 52 +- .../java/types/RJavaPojoInterface.java | 171 +- .../java/types/RJavaReferenceWithMeta.java | 41 +- .../java/types/RJavaWithMetaValue.java | 33 +- .../java/util/ModelGeneratorUtil.xtend | 4 +- .../java/validator/ValidatorGenerator.xtend | 11 +- .../scoping/RosettaScopeProvider.xtend | 18 +- .../regnosys/rosetta/types/RAttribute.java | 69 +- .../regnosys/rosetta/types/RCardinality.java | 120 ++ .../com/regnosys/rosetta/types/RDataType.java | 62 +- .../rosetta/types/RMetaAnnotatedType.java | 4 + .../rosetta/types/RObjectFactory.java | 63 +- .../regnosys/rosetta/types/Rosetta.xsemantics | 3 + .../rosetta/types/RosettaAuxiliary.xsemantics | 5 +- .../rosetta/types/RosettaTypeProvider.xtend | 10 +- .../rosetta/utils/BigDecimalInterval.java | 3 + .../rosetta/utils/DeepFeatureCallUtil.java | 19 +- .../rosetta/utils/ExternalAnnotationUtil.java | 4 +- .../com/regnosys/rosetta/utils/Interval.java | 46 +- .../AbstractDeclarativeRosettaValidator.java | 29 + .../validation/AttributeValidator.java | 121 ++ .../rosetta/validation/ChoiceValidator.java | 1 - .../rosetta/validation/EnumValidator.java | 20 +- .../validation/RosettaSimpleValidator.xtend | 153 +- .../rosetta/validation/RosettaValidator.xtend | 9 +- .../StandaloneRosettaTypingValidator.java | 13 +- .../rosetta/validation/TypeValidator.java | 103 + .../metafields/MetaAndTemplateFields.java | 504 +++++ .../rosetta/model/metafields/MetaFields.java | 468 +++++ .../util/types/JavaParameterizedType.java | 17 +- .../tests/util/CodeGeneratorTestHelper.xtend | 6 +- .../rosetta/tests/util/ExpressionParser.xtend | 12 +- .../formatting2/RosettaFormattingTest.xtend | 2 +- .../expression/ExpressionGeneratorTest.xtend | 433 ++-- .../java/function/FunctionGeneratorTest.xtend | 63 +- .../java/object/ModelMetaGeneratorTest.xtend | 4 +- .../ModelObjectBuilderGeneratorTest.xtend | 4 +- .../object/ModelObjectGeneratorTest.xtend | 8 +- .../PojoInheritanceRegressionTest.xtend | 1517 ++++++++++++++ .../java/object/PojoRegressionTest.xtend | 1285 ++++-------- .../java/reports/TabulatorTest.xtend | 15 +- .../java/util/ModelGeneratorUtilTest.xtend | 2 +- .../rosetta/tests/RosettaParsingTest.xtend | 35 + .../validation/AttributeValidatorTest.xtend | 275 +++ .../validation/EnumValidatorTest.xtend | 11 + ...ttaNamespaceDescriptionValidatorTest.xtend | 38 - .../validation/RosettaValidatorTest.xtend | 62 +- .../validation/TypeValidatorTest.xtend | 122 ++ .../tools/modelimport/XsdTypeImport.java | 1 + 79 files changed, 6131 insertions(+), 4050 deletions(-) create mode 100644 rosetta-ide/src/main/java/com/regnosys/rosetta/ide/contentassist/RosettaContentProposalProvider.java create mode 100644 rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/statement/JavaEnhancedForLoop.java create mode 100644 rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/JavaPojoInterface.java create mode 100644 rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/JavaPojoProperty.java create mode 100644 rosetta-lang/src/main/java/com/regnosys/rosetta/types/RCardinality.java create mode 100644 rosetta-lang/src/main/java/com/regnosys/rosetta/validation/AttributeValidator.java create mode 100644 rosetta-lang/src/main/java/com/regnosys/rosetta/validation/TypeValidator.java create mode 100644 rosetta-runtime/src/main/java/com/rosetta/model/metafields/MetaAndTemplateFields.java create mode 100644 rosetta-runtime/src/main/java/com/rosetta/model/metafields/MetaFields.java create mode 100644 rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/PojoInheritanceRegressionTest.xtend create mode 100644 rosetta-testing/src/test/java/com/regnosys/rosetta/validation/AttributeValidatorTest.xtend delete mode 100644 rosetta-testing/src/test/java/com/regnosys/rosetta/validation/RosettaNamespaceDescriptionValidatorTest.xtend create mode 100644 rosetta-testing/src/test/java/com/regnosys/rosetta/validation/TypeValidatorTest.xtend diff --git a/rosetta-ide/rosetta.tmLanguage.yaml b/rosetta-ide/rosetta.tmLanguage.yaml index 81e65de19..d3ef0e765 100644 --- a/rosetta-ide/rosetta.tmLanguage.yaml +++ b/rosetta-ide/rosetta.tmLanguage.yaml @@ -763,6 +763,8 @@ repository: - include: '#comment' - include: '#annotation' - include: '#documentation' + - name: keyword.other.override.rosetta + match: '{{wordStart}}override{{wordEnd}}' - name: meta.attribute.rosetta begin: '{{identifier}}' beginCaptures: @@ -776,6 +778,8 @@ repository: - include: '#comment' - include: '#annotation' - include: '#documentation' + - name: keyword.other.override.rosetta + match: '{{wordStart}}override{{wordEnd}}' - name: meta.attribute.rosetta begin: '{{identifier}}' beginCaptures: diff --git a/rosetta-ide/src/main/java/com/regnosys/rosetta/ide/RosettaIdeModule.xtend b/rosetta-ide/src/main/java/com/regnosys/rosetta/ide/RosettaIdeModule.xtend index 86a8a20f8..c198ea4f0 100644 --- a/rosetta-ide/src/main/java/com/regnosys/rosetta/ide/RosettaIdeModule.xtend +++ b/rosetta-ide/src/main/java/com/regnosys/rosetta/ide/RosettaIdeModule.xtend @@ -32,6 +32,8 @@ import com.regnosys.rosetta.ide.contentassist.cancellable.RosettaOperationCancel import com.regnosys.rosetta.ide.semantictokens.RosettaSemanticTokenModifiersProvider import org.eclipse.xtext.ide.server.hover.IHoverService import com.regnosys.rosetta.ide.hover.RosettaHoverService +import org.eclipse.xtext.ide.editor.contentassist.IdeContentProposalProvider +import com.regnosys.rosetta.ide.contentassist.RosettaContentProposalProvider /** * Use this class to register ide components. @@ -101,4 +103,8 @@ class RosettaIdeModule extends AbstractRosettaIdeModule { def Class bindIHoverService() { RosettaHoverService } + + def Class bindIdeContentProposalProvider() { + RosettaContentProposalProvider + } } diff --git a/rosetta-ide/src/main/java/com/regnosys/rosetta/ide/contentassist/RosettaContentProposalProvider.java b/rosetta-ide/src/main/java/com/regnosys/rosetta/ide/contentassist/RosettaContentProposalProvider.java new file mode 100644 index 000000000..b935153a6 --- /dev/null +++ b/rosetta-ide/src/main/java/com/regnosys/rosetta/ide/contentassist/RosettaContentProposalProvider.java @@ -0,0 +1,48 @@ +package com.regnosys.rosetta.ide.contentassist; + +import javax.inject.Inject; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.RuleCall; +import org.eclipse.xtext.ide.editor.contentassist.ContentAssistContext; +import org.eclipse.xtext.ide.editor.contentassist.ContentAssistEntry; +import org.eclipse.xtext.ide.editor.contentassist.IIdeContentProposalAcceptor; +import org.eclipse.xtext.ide.editor.contentassist.IdeContentProposalProvider; +import org.eclipse.xtext.resource.EObjectDescription; + +import com.regnosys.rosetta.RosettaEcoreUtil; +import com.regnosys.rosetta.rosetta.simple.Attribute; +import com.regnosys.rosetta.rosetta.simple.Data; +import com.regnosys.rosetta.services.RosettaGrammarAccess; + +public class RosettaContentProposalProvider extends IdeContentProposalProvider { + @Inject + private RosettaGrammarAccess grammarAccess; + @Inject + private RosettaEcoreUtil ecoreUtil; + + @Override + protected void _createProposals(RuleCall ruleCall, ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + if (context.getCurrentModel() instanceof Attribute && ruleCall.equals(grammarAccess.getAttributeAccess().getRosettaNamedParserRuleCall_1())) { + createProposalsForAttributeName((Attribute) context.getCurrentModel(), context, acceptor); + } + super._createProposals(ruleCall, context, acceptor); + } + + private void createProposalsForAttributeName(Attribute attr, ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + if (attr.isOverride()) { + EObject container = attr.eContainer(); + if (container instanceof Data) { + Data data = (Data) container; + if (data.getSuperType() != null) { + ecoreUtil.getAllAttributes(data.getSuperType()) + .forEach((superAttr) -> { + ContentAssistEntry proposal = getProposalCreator().createProposal(superAttr.getName(), context); + int priority = getProposalPriorities().getCrossRefPriority(EObjectDescription.create(superAttr.getName(), superAttr), proposal); + acceptor.accept(proposal, priority); + }); + } + } + } + } +} diff --git a/rosetta-ide/src/main/java/com/regnosys/rosetta/ide/textmate/GenerateTmGrammar.java b/rosetta-ide/src/main/java/com/regnosys/rosetta/ide/textmate/GenerateTmGrammar.java index 1235a382d..f3ebe0854 100644 --- a/rosetta-ide/src/main/java/com/regnosys/rosetta/ide/textmate/GenerateTmGrammar.java +++ b/rosetta-ide/src/main/java/com/regnosys/rosetta/ide/textmate/GenerateTmGrammar.java @@ -53,7 +53,7 @@ import com.regnosys.rosetta.services.RosettaGrammarAccess; public class GenerateTmGrammar { - private static List ignoredRosettaKeywords = List.of("..", "namespace", "condition", "required", "optional", /* @Compat */"qualifiedType", "calculationType"); + private static List ignoredRosettaKeywords = List.of("..", "namespace", "condition", "required", "optional", "override", /* @Compat */"qualifiedType", "calculationType"); /** * param 0: path to input yaml file diff --git a/rosetta-ide/src/test/java/com/regnosys/rosetta/ide/contentassist/ContentAssistTest.xtend b/rosetta-ide/src/test/java/com/regnosys/rosetta/ide/contentassist/ContentAssistTest.xtend index 5467dd7aa..41bcf0bba 100644 --- a/rosetta-ide/src/test/java/com/regnosys/rosetta/ide/contentassist/ContentAssistTest.xtend +++ b/rosetta-ide/src/test/java/com/regnosys/rosetta/ide/contentassist/ContentAssistTest.xtend @@ -469,4 +469,33 @@ class ContentAssistTest extends AbstractRosettaLanguageServerTest { ''' ] } + + @Test + def void testAttributeOverride() { + val model = ''' + namespace my.ns + + type Parent: + attr int (0..1) + parentAttr int (1..1) + + type Foo extends Parent: + override attr int (1..1) + otherAttr string (1..1) + + type Bar extends Foo: + override + barAttr int (1..1) + ''' + testCompletion[ + it.model = model + it.line = 11 + it.column = 10 + it.expectedCompletionItems = ''' + attr -> attr [[11, 10] .. [11, 10]] + otherAttr -> otherAttr [[11, 10] .. [11, 10]] + parentAttr -> parentAttr [[11, 10] .. [11, 10]] + ''' + ] + } } \ No newline at end of file diff --git a/rosetta-ide/vscode/package-lock.json b/rosetta-ide/vscode/package-lock.json index db5a49877..23228c11a 100644 --- a/rosetta-ide/vscode/package-lock.json +++ b/rosetta-ide/vscode/package-lock.json @@ -1,7 +1,7 @@ { "name": "rune-language", "version": "5.0.0", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -33,18 +33,18 @@ } }, "node_modules/@types/node": { - "version": "22.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", - "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", + "version": "22.9.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.3.tgz", + "integrity": "sha512-F3u1fs/fce3FFk+DAxbxc78DF8x0cY09RRL8GnXLmkJ1jvx3TtPdWoTT5/NiYfI5ASqXBmfqJi9dZ3gxMx4lzw==", "dev": true, "dependencies": { "undici-types": "~6.19.8" } }, "node_modules/@types/vscode": { - "version": "1.90.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.90.0.tgz", - "integrity": "sha512-oT+ZJL7qHS9Z8bs0+WKf/kQ27qWYR3trsXpq46YDjFqBsMLG4ygGGjPaJ2tyrH0wJzjOEmDyg9PDJBBhWg9pkQ==", + "version": "1.95.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.95.0.tgz", + "integrity": "sha512-0LBD8TEiNbet3NvWsmn59zLzOFu/txSlGxnv5yAFHCrhG9WvAnR3IvfHzMOs2aeWqgvNjq9pO99IUw8d3n+unw==", "dev": true }, "node_modules/agent-base": { @@ -109,9 +109,9 @@ ] }, "node_modules/big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", "dev": true, "engines": { "node": ">=0.6" @@ -140,19 +140,6 @@ "readable-stream": "^3.4.0" } }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/bluebird": { "version": "3.4.7", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", @@ -223,12 +210,18 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -260,20 +253,24 @@ } }, "node_modules/cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz", + "integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==", "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" + "domutils": "^3.1.0", + "encoding-sniffer": "^0.2.0", + "htmlparser2": "^9.1.0", + "parse5": "^7.1.2", + "parse5-htmlparser2-tree-adapter": "^7.0.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^6.19.5", + "whatwg-mimetype": "^4.0.0" }, "engines": { - "node": ">= 6" + "node": ">=18.17" }, "funding": { "url": "https://github.com/cheeriojs/cheerio?sponsor=1" @@ -359,12 +356,12 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -397,10 +394,26 @@ "node": ">=4.0.0" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", "engines": { "node": ">=8" } @@ -444,13 +457,13 @@ } }, "node_modules/domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "domhandler": "^5.0.3" }, "funding": { "url": "https://github.com/fb55/domutils?sponsor=1" @@ -465,6 +478,48 @@ "readable-stream": "^2.0.2" } }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexer2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/encoding-sniffer": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz", + "integrity": "sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==", + "dependencies": { + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" + }, + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" + } + }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -474,9 +529,9 @@ } }, "node_modules/entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "engines": { "node": ">=0.12" }, @@ -484,6 +539,25 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -522,6 +596,7 @@ "version": "1.0.12", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "deprecated": "This package is no longer supported.", "dev": true, "dependencies": { "graceful-fs": "^4.1.2", @@ -537,6 +612,7 @@ "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "dependencies": { "glob": "^7.1.3" @@ -546,18 +622,26 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -572,6 +656,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -587,23 +672,23 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dependencies": { - "function-bind": "^1.1.1" + "get-intrinsic": "^1.1.3" }, - "engines": { - "node": ">= 0.4.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -612,6 +697,28 @@ "node": ">=4" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -623,6 +730,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hosted-git-info": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", @@ -635,9 +753,9 @@ } }, "node_modules/htmlparser2": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", - "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", + "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", { @@ -647,9 +765,9 @@ ], "dependencies": { "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "entities": "^4.3.0" + "domhandler": "^5.0.3", + "domutils": "^3.1.0", + "entities": "^4.5.0" } }, "node_modules/http-proxy-agent": { @@ -679,6 +797,17 @@ "node": ">= 6" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -702,6 +831,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -727,12 +857,15 @@ } }, "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -849,9 +982,9 @@ } }, "node_modules/minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -874,9 +1007,9 @@ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "node_modules/mute-stream": { @@ -890,9 +1023,9 @@ "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" }, "node_modules/node-abi": { - "version": "3.28.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.28.0.tgz", - "integrity": "sha512-fRlDb4I0eLcQeUvGq7IY3xHrSb0c9ummdvDSYWfT9+LKP+3jCKw/tKoqaM7r1BAoiAC6GtwyjaGnOz6B3OtF+A==", + "version": "3.71.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.71.0.tgz", + "integrity": "sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==", "dependencies": { "semver": "^7.3.5" }, @@ -900,6 +1033,17 @@ "node": ">=10" } }, + "node_modules/node-abi/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/node-addon-api": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", @@ -917,9 +1061,12 @@ } }, "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -940,31 +1087,34 @@ "semver": "^5.1.0" } }, - "node_modules/parse-semver/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", "dependencies": { - "entities": "^4.4.0" + "entities": "^4.5.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" } }, "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", - "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-parser-stream": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", + "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", "dependencies": { - "domhandler": "^5.0.2", "parse5": "^7.0.0" }, "funding": { @@ -991,9 +1141,9 @@ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" }, "node_modules/prebuild-install": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", - "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", + "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", @@ -1022,20 +1172,20 @@ "dev": true }, "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.1.tgz", + "integrity": "sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -1070,18 +1220,16 @@ } }, "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/rechoir": { @@ -1097,12 +1245,12 @@ } }, "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -1117,6 +1265,8 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -1128,27 +1278,56 @@ } }, "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { - "semver": "bin/semver.js" + "semver": "bin/semver" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" }, "engines": { - "node": ">=10" + "node": ">= 0.4" } }, "node_modules/setimmediate": { @@ -1191,13 +1370,17 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1247,11 +1430,11 @@ } }, "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dependencies": { - "safe-buffer": "~5.1.0" + "safe-buffer": "~5.2.0" } }, "node_modules/strip-json-comments": { @@ -1311,28 +1494,12 @@ "node": ">=6" } }, - "node_modules/tar-stream/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dependencies": { - "rimraf": "^3.0.0" - }, + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", "engines": { - "node": ">=8.17.0" + "node": ">=14.14" } }, "node_modules/traverse": { @@ -1364,9 +1531,9 @@ } }, "node_modules/typed-rest-client": { - "version": "1.8.9", - "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.9.tgz", - "integrity": "sha512-uSmjE38B80wjL85UFX3sTYEUlvZ1JgCRhsWj/fJ4rZ0FqDUFoIuodtiVeE+cUqiVTOKPdKrp/sdftD15MDek6g==", + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", + "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==", "dependencies": { "qs": "^6.9.1", "tunnel": "0.0.6", @@ -1374,9 +1541,9 @@ } }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -1392,9 +1559,17 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, "node_modules/underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==" + }, + "node_modules/undici": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.0.tgz", + "integrity": "sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw==", + "engines": { + "node": ">=18.17" + } }, "node_modules/undici-types": { "version": "6.19.8", @@ -1403,9 +1578,9 @@ "dev": true }, "node_modules/unzipper": { - "version": "0.10.11", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", - "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", + "version": "0.10.14", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", + "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==", "dev": true, "dependencies": { "big-integer": "^1.6.17", @@ -1420,6 +1595,36 @@ "setimmediate": "~1.0.4" } }, + "node_modules/unzipper/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/unzipper/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/unzipper/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/url-join": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", @@ -1464,14 +1669,6 @@ "node": ">= 14" } }, - "node_modules/vsce/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/vscode-jsonrpc": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", @@ -1512,7 +1709,18 @@ "node": ">=10" } }, - "node_modules/vscode-languageserver-protocol": { + "node_modules/vscode-languageclient/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vscode-languageserver-protocol": { "version": "3.17.5", "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", @@ -1542,6 +1750,25 @@ "node": ">=8.9.3" } }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "engines": { + "node": ">=18" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -1589,1186 +1816,5 @@ "buffer-crc32": "~0.2.3" } } - }, - "dependencies": { - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true - }, - "@types/node": { - "version": "22.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", - "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", - "dev": true, - "requires": { - "undici-types": "~6.19.8" - } - }, - "@types/vscode": { - "version": "1.90.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.90.0.tgz", - "integrity": "sha512-oT+ZJL7qHS9Z8bs0+WKf/kQ27qWYR3trsXpq46YDjFqBsMLG4ygGGjPaJ2tyrH0wJzjOEmDyg9PDJBBhWg9pkQ==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "azure-devops-node-api": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz", - "integrity": "sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==", - "requires": { - "tunnel": "0.0.6", - "typed-rest-client": "^1.8.4" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", - "dev": true - }, - "binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", - "dev": true, - "requires": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" - } - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "bluebird": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", - "dev": true - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==" - }, - "buffer-indexof-polyfill": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", - "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", - "dev": true - }, - "buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", - "dev": true - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", - "dev": true, - "requires": { - "traverse": ">=0.3.0 <0.4" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", - "requires": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" - } - }, - "cheerio-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", - "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", - "requires": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "requires": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - } - }, - "css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "requires": { - "mimic-response": "^3.1.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, - "detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==" - }, - "dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - } - }, - "domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" - }, - "domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "requires": { - "domelementtype": "^2.3.0" - } - }, - "domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", - "requires": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" - } - }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", - "dev": true, - "requires": { - "readable-stream": "^2.0.2" - } - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" - }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "requires": { - "pend": "~1.2.0" - } - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - }, - "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - } - }, - "github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "htmlparser2": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", - "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "entities": "^4.3.0" - } - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true - }, - "is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "keytar": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", - "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", - "requires": { - "node-addon-api": "^4.3.0", - "prebuild-install": "^7.0.1" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" - }, - "linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", - "requires": { - "uc.micro": "^1.0.1" - } - }, - "listenercount": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", - "requires": { - "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "dependencies": { - "entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==" - } - } - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" - }, - "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "requires": { - "minimist": "^1.2.6" - } - }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" - }, - "napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" - }, - "node-abi": { - "version": "3.28.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.28.0.tgz", - "integrity": "sha512-fRlDb4I0eLcQeUvGq7IY3xHrSb0c9ummdvDSYWfT9+LKP+3jCKw/tKoqaM7r1BAoiAC6GtwyjaGnOz6B3OtF+A==", - "requires": { - "semver": "^7.3.5" - } - }, - "node-addon-api": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", - "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" - }, - "nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "requires": { - "boolbase": "^1.0.0" - } - }, - "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "parse-semver": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", - "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==", - "requires": { - "semver": "^5.1.0" - }, - "dependencies": { - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" - } - } - }, - "parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "requires": { - "entities": "^4.4.0" - } - }, - "parse5-htmlparser2-tree-adapter": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", - "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", - "requires": { - "domhandler": "^5.0.2", - "parse5": "^7.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" - }, - "prebuild-install": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", - "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", - "requires": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - } - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "requires": { - "side-channel": "^1.0.4" - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", - "requires": { - "mute-stream": "~0.0.4" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dev": true, - "requires": { - "resolve": "^1.1.6" - } - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true - }, - "shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - }, - "shx": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", - "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", - "dev": true, - "requires": { - "minimist": "^1.2.3", - "shelljs": "^0.8.5" - } - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" - }, - "simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "requires": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "requires": { - "rimraf": "^3.0.0" - } - }, - "traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", - "dev": true - }, - "tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "typed-rest-client": { - "version": "1.8.9", - "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.9.tgz", - "integrity": "sha512-uSmjE38B80wjL85UFX3sTYEUlvZ1JgCRhsWj/fJ4rZ0FqDUFoIuodtiVeE+cUqiVTOKPdKrp/sdftD15MDek6g==", - "requires": { - "qs": "^6.9.1", - "tunnel": "0.0.6", - "underscore": "^1.12.1" - } - }, - "typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "dev": true - }, - "uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" - }, - "underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" - }, - "undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "dev": true - }, - "unzipper": { - "version": "0.10.11", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", - "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", - "dev": true, - "requires": { - "big-integer": "^1.6.17", - "binary": "~0.3.0", - "bluebird": "~3.4.1", - "buffer-indexof-polyfill": "~1.0.0", - "duplexer2": "~0.1.4", - "fstream": "^1.0.12", - "graceful-fs": "^4.2.2", - "listenercount": "~1.0.1", - "readable-stream": "~2.3.6", - "setimmediate": "~1.0.4" - } - }, - "url-join": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "vsce": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.15.0.tgz", - "integrity": "sha512-P8E9LAZvBCQnoGoizw65JfGvyMqNGlHdlUXD1VAuxtvYAaHBKLBdKPnpy60XKVDAkQCfmMu53g+gq9FM+ydepw==", - "requires": { - "azure-devops-node-api": "^11.0.1", - "chalk": "^2.4.2", - "cheerio": "^1.0.0-rc.9", - "commander": "^6.1.0", - "glob": "^7.0.6", - "hosted-git-info": "^4.0.2", - "keytar": "^7.7.0", - "leven": "^3.1.0", - "markdown-it": "^12.3.2", - "mime": "^1.3.4", - "minimatch": "^3.0.3", - "parse-semver": "^1.1.1", - "read": "^1.0.7", - "semver": "^5.1.0", - "tmp": "^0.2.1", - "typed-rest-client": "^1.8.4", - "url-join": "^4.0.1", - "xml2js": "^0.4.23", - "yauzl": "^2.3.1", - "yazl": "^2.2.2" - }, - "dependencies": { - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" - } - } - }, - "vscode-jsonrpc": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", - "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==" - }, - "vscode-languageclient": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz", - "integrity": "sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==", - "requires": { - "minimatch": "^5.1.0", - "semver": "^7.3.7", - "vscode-languageserver-protocol": "3.17.5" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "vscode-languageserver-protocol": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", - "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", - "requires": { - "vscode-jsonrpc": "8.2.0", - "vscode-languageserver-types": "3.17.5" - } - }, - "vscode-languageserver-types": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", - "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==" - }, - "vscode-test": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.6.1.tgz", - "integrity": "sha512-086q88T2ca1k95mUzffvbzb7esqQNvJgiwY4h29ukPhFo8u+vXOOmelUoU5EQUHs3Of8+JuQ3oGdbVCqaxuTXA==", - "dev": true, - "requires": { - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "rimraf": "^3.0.2", - "unzipper": "^0.10.11" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - } - }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "requires": { - "buffer-crc32": "~0.2.3" - } - } } } diff --git a/rosetta-ide/vscode/src/extension.ts b/rosetta-ide/vscode/src/extension.ts index c479b25d6..cc6d87cc3 100644 --- a/rosetta-ide/vscode/src/extension.ts +++ b/rosetta-ide/vscode/src/extension.ts @@ -31,8 +31,8 @@ export async function activate(context: ExtensionContext) { let script = context.asAbsolutePath(path.join('src', 'rosetta', 'languageserver', 'bin', launcher)); let serverOptions: ServerOptions = { - run : { command: script }, - debug: { command: script, args: ['-trace'], options: { env: createDebugEnv() } } + run : { command: script, options: { shell: true } }, + debug: { command: script, args: ['-trace'], options: { shell: true, env: createDebugEnv() } }, }; let clientOptions: LanguageClientOptions = { @@ -63,7 +63,7 @@ export async function activate(context: ExtensionContext) { await lc.start().then(() => { console.log("Rosetta Language Server started."); }).catch((err) => { - console.error("Failed to launch Rosetta Language Server.") + console.error("Failed to launch Rosetta Language Server."); console.error(err); }); } diff --git a/rosetta-lang/model/Rosetta.xcore b/rosetta-lang/model/Rosetta.xcore index 90d00c185..dac7ee3c6 100644 --- a/rosetta-lang/model/Rosetta.xcore +++ b/rosetta-lang/model/Rosetta.xcore @@ -63,10 +63,6 @@ interface RosettaRootElement { container RosettaModel model opposite elements } -abstract class RosettaFeatureOwner extends RosettaDefinable { - contains RosettaTypedFeature[] features -} - abstract class RosettaType extends RosettaRootElement, RosettaNamed { } @@ -126,7 +122,7 @@ class RosettaTypeAlias extends RosettaRootElement, RosettaType, RosettaTyped, Ro } -class RosettaMetaType extends RosettaRootElement, RosettaTypedFeature, RosettaType, RosettaSymbol { +class RosettaMetaType extends RosettaRootElement, RosettaTypedFeature, RosettaSymbol { } diff --git a/rosetta-lang/model/RosettaSimple.xcore b/rosetta-lang/model/RosettaSimple.xcore index f328e2264..558ee30fb 100644 --- a/rosetta-lang/model/RosettaSimple.xcore +++ b/rosetta-lang/model/RosettaSimple.xcore @@ -56,8 +56,8 @@ class AnnotationRef { interface AssignPathRoot extends RosettaSymbol { } - -class Attribute extends RosettaTypedFeature, RosettaDefinable, Annotated, AssignPathRoot, References { +class Attribute extends RosettaTypedFeature, RosettaDefinable, Annotated, References, AssignPathRoot { + boolean override contains RosettaCardinality card contains RosettaSynonym[] synonyms contains RosettaRuleReference ruleReference diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/Rosetta.xtext b/rosetta-lang/src/main/java/com/regnosys/rosetta/Rosetta.xtext index 76a07fba5..33bdbe341 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/Rosetta.xtext +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/Rosetta.xtext @@ -77,7 +77,7 @@ Choice: 'choice' RosettaNamed ':' RosettaDefinable? (Annotations|ClassSynonyms)* - attributes += ChoiceOption* + attributes+=ChoiceOption* ; ChoiceOption: @@ -87,7 +87,8 @@ ChoiceOption: ; Attribute: - RosettaNamed RosettaTyped card=RosettaCardinality RosettaDefinable? + override?='override'? RosettaNamed RosettaTyped card=RosettaCardinality + RosettaDefinable? (References|Annotations|Synonyms)* RuleReference? ; diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/RosettaEcoreUtil.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/RosettaEcoreUtil.xtend index 126b9266a..8a85e4665 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/RosettaEcoreUtil.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/RosettaEcoreUtil.xtend @@ -2,29 +2,22 @@ package com.regnosys.rosetta import com.google.common.base.CaseFormat import com.regnosys.rosetta.rosetta.RosettaEnumeration -import com.regnosys.rosetta.rosetta.RosettaFactory import com.regnosys.rosetta.rosetta.RosettaFeature import com.regnosys.rosetta.rosetta.RosettaRecordType import com.regnosys.rosetta.rosetta.RosettaSynonym import com.regnosys.rosetta.rosetta.expression.ChoiceOperation import com.regnosys.rosetta.rosetta.expression.OneOfOperation -import com.regnosys.rosetta.rosetta.simple.Annotated import com.regnosys.rosetta.rosetta.simple.Attribute import com.regnosys.rosetta.rosetta.simple.Condition import com.regnosys.rosetta.rosetta.simple.Data import com.regnosys.rosetta.rosetta.simple.Function -import com.regnosys.rosetta.rosetta.simple.SimpleFactory -import com.regnosys.rosetta.scoping.RosettaScopeProvider -import com.regnosys.rosetta.types.RAttribute import com.regnosys.rosetta.types.RChoiceType import com.regnosys.rosetta.types.RDataType import com.regnosys.rosetta.types.REnumType import com.regnosys.rosetta.types.RMetaAnnotatedType -import com.regnosys.rosetta.types.RObjectFactory import com.regnosys.rosetta.types.RType import com.regnosys.rosetta.types.builtin.RBuiltinTypeService import com.regnosys.rosetta.types.builtin.RRecordType -import com.regnosys.rosetta.utils.PositiveIntegerInterval import com.regnosys.rosetta.utils.RosettaConfigExtension import java.util.Collection import java.util.LinkedHashSet @@ -34,16 +27,14 @@ import javax.inject.Inject import javax.inject.Singleton import org.eclipse.emf.ecore.EObject import org.eclipse.emf.ecore.resource.ResourceSet -import org.eclipse.xtext.util.SimpleCache -import static extension com.regnosys.rosetta.types.RMetaAnnotatedType.withMeta import org.eclipse.emf.ecore.util.EcoreUtil +import com.regnosys.rosetta.rosetta.simple.Annotated @Singleton // see `metaFieldsCache` class RosettaEcoreUtil { @Inject RBuiltinTypeService builtins - @Inject extension RObjectFactory objectFactory @Inject extension RosettaConfigExtension configs def boolean isResolved(EObject obj) { @@ -61,7 +52,7 @@ class RosettaEcoreUtil { def Iterable allFeatures(RType t, ResourceSet resourceSet) { switch t { RDataType: - t.allNonOverridenAttributes.map[EObject] + t.allAttributes.map[EObject] RChoiceType: t.asRDataType.allFeatures(resourceSet) REnumType: @@ -120,6 +111,26 @@ class RosettaEcoreUtil { e.allSuperEnumerations.map[enumValues].flatten } + def Attribute getParentAttribute(Attribute attr) { + val t = attr.eContainer + if (t instanceof Data) { + val visited = newHashSet + visited.add(t) + var st = t.superType + while (st !== null) { + val p = st.attributes.findFirst[name == attr.name] + if (p !== null) { + return p + } + st = st.superType + if (!visited.add(st)) { + return null + } + } + } + return null + } + def Set getAllSynonyms(RosettaSynonym s) { doGetSynonyms(s, newLinkedHashSet) } @@ -130,55 +141,49 @@ class RosettaEcoreUtil { return seenSynonyms } + @Deprecated def metaAnnotations(Annotated it) { allAnnotations.filter[annotation?.name == "metadata"] } + @Deprecated def hasKeyedAnnotation(Annotated it) { metaAnnotations.exists[attribute?.name == "key"] } + @Deprecated def hasTemplateAnnotation(Annotated it) { metaAnnotations.exists[attribute?.name == "template"] } + @Deprecated def boolean hasMetaDataAnnotations(Annotated it) { metaAnnotations.exists[attribute?.name == "reference" || attribute?.name == "location" || attribute?.name == "scheme" || attribute?.name == "id"] } + @Deprecated def boolean hasMetaFieldAnnotations(Annotated it) { metaAnnotations.exists[attribute?.name != "reference" && attribute?.name != "address"] } - def boolean hasMetaDataReference(RAttribute attribute) { - attribute.RMetaAnnotatedType.getMetaAttributes.exists[name == "reference"] - } - - def boolean hasMetaDataAddress(RAttribute attribute) { - attribute.RMetaAnnotatedType.getMetaAttributes.exists[name == "address"] - } - + @Deprecated def boolean hasMetaDataAddress(Annotated it) { metaAnnotations.exists[attribute?.name == "address"] } + @Deprecated def boolean hasIdAnnotation(Annotated it) { metaAnnotations.exists[attribute?.name == "id"] } - def boolean hasIdAnnotation(RAttribute it) { - RMetaAnnotatedType.getMetaAttributes.exists[name == "id"] - } + @Deprecated def boolean hasReferenceAnnotation(Annotated it) { metaAnnotations.exists[attribute?.name == "reference"] } + @Deprecated def hasCalculationAnnotation(Annotated it) { allAnnotations.exists[annotation?.name == "calculation"] } - - def boolean isReference(RAttribute attribute) { - return attribute.hasMetaDataReference || attribute.hasMetaDataAddress - } - + @Deprecated def private allAnnotations(Annotated withAnnotations) { withAnnotations?.annotations?.filter[annotation.isResolved] } @@ -257,71 +262,4 @@ class RosettaEcoreUtil { val camel = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, allUnderscore) return camel } - - @Deprecated - def String javaAnnotation(RAttribute attr) { - if (attr.name == "key" && attr.RMetaAnnotatedType.RType.name == "Key" && attr.RMetaAnnotatedType.RType.namespace.toString == "com.rosetta.model.lib.meta") { - return 'location' - } else if (attr.name == "reference" && attr.RMetaAnnotatedType.RType.name == "Reference" && attr.RMetaAnnotatedType.RType.namespace.toString == "com.rosetta.model.lib.meta") { - return 'address' - } else - return attr.name - } - // Copied over from RosettaAttributeExtensions. - @Deprecated - private def List additionalAttributes(RDataType t) { - val res = newArrayList - if(hasKeyedAnnotation(t.EObject)){ - res.add(new RAttribute( - 'meta', - null, - emptyList, - provideMetaFieldsType(t).withMeta(#[]), - PositiveIntegerInterval.bounded(0, 1), - null, - null - )) - } - return res - } - def List javaAttributes(RDataType t) { - (t.ownAttributes + t.additionalAttributes).toList - } - def List allJavaAttributes(RDataType t) { - val atts = t.javaAttributes - if (t.superType !== null) { - val attsWithSuper = t.superType.allJavaAttributes - val result = newArrayList - attsWithSuper.forEach[ - val overridenAtt = atts.findFirst[att| att.name == name] - if (overridenAtt !== null) { - result.add(overridenAtt) - } else { - result.add(it) - } - ] - result.addAll(atts.filter[att| !result.contains(att)].toList) - return result - } - return atts - } - - @Deprecated - String METAFIELDS_CLASS_NAME = 'MetaFields' - @Deprecated - String META_AND_TEMPLATE_FIELDS_CLASS_NAME = 'MetaAndTemplateFields' - - @Deprecated - SimpleCache metaFieldsCache = new SimpleCache[RDataType t| - val rosModel = RosettaFactory.eINSTANCE.createRosettaModel() - rosModel.name = RosettaScopeProvider.LIB_NAMESPACE + ".metafields" - val name = if (hasTemplateAnnotation(t.EObject)) META_AND_TEMPLATE_FIELDS_CLASS_NAME else METAFIELDS_CLASS_NAME - val data = SimpleFactory.eINSTANCE.createData - data.model = rosModel - data.name = name - return objectFactory.buildRDataType(data) - ] - private def RType provideMetaFieldsType(RDataType t) { - metaFieldsCache.get(t) - } } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/formatting2/FormattingUtil.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/formatting2/FormattingUtil.java index 0c21d2316..8370ff080 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/formatting2/FormattingUtil.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/formatting2/FormattingUtil.java @@ -43,7 +43,7 @@ public void formatInlineOrMultiline(IFormattableDocument document, EObject objec public void formatInlineOrMultiline(IFormattableDocument document, EObject object, FormattingMode mode, int maxLineWidth, Consumer inlineFormatter, Consumer multilineFormatter) { IEObjectRegion objRegion = getTextRegionExt(document).regionForEObject(object); // I need to include the next hidden region in the conditional formatting as well, - // because that's where I might decrease indentation in case of a (long) multi-line operation. + // because that's where I might decrease indentation in case of a (long) multi-line operation. ITextSegment formattableRegion = objRegion.merge(objRegion.getNextHiddenRegion()); formatInlineOrMultiline(document, objRegion, formattableRegion, mode, maxLineWidth, inlineFormatter, multilineFormatter); } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/enums/EnumGenerator.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/enums/EnumGenerator.xtend index 640bea43e..c303cd829 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/enums/EnumGenerator.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/enums/EnumGenerator.xtend @@ -32,7 +32,7 @@ class EnumGenerator { val javaEnum = e.toJavaReferenceType val StringConcatenationClient classBody = ''' - «javadoc(e.EObject, version)» + «javadoc(e.EObject.definition, e.EObject.references, version)» @«RosettaEnum»("«e.name»") public enum «e.name» { diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/expression/DeepPathUtilGenerator.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/expression/DeepPathUtilGenerator.xtend index 3c4037bdf..661b9355a 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/expression/DeepPathUtilGenerator.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/expression/DeepPathUtilGenerator.xtend @@ -54,7 +54,7 @@ class DeepPathUtilGenerator { val classScope = topScope.classScope(javaClass.simpleName) val deepFeatures = choiceType.findDeepFeatures val dependencies = new HashSet>() - val recursiveDeepFeaturesMap = choiceType.allNonOverridenAttributes.toMap([it], [ + val recursiveDeepFeaturesMap = choiceType.allAttributes.toMap([it], [ val attrType = it.RMetaAnnotatedType.RType deepFeatures.toMap([it], [ var t = attrType @@ -99,12 +99,13 @@ class DeepPathUtilGenerator { } private def JavaStatementBuilder deepFeatureToStatement(RDataType choiceType, JavaVariable inputParameter, RAttribute deepFeature, Map> recursiveDeepFeaturesMap, JavaScope scope) { - val attrs = choiceType.allNonOverridenAttributes.toList + val attrs = choiceType.allAttributes.toList + val deepFeatureType = deepFeature.toMetaJavaType var JavaStatementBuilder acc = JavaExpression.NULL for (a : attrs.reverseView) { val currAcc = acc acc = inputParameter - .attributeCall(choiceType.withEmptyMeta, a, false, scope) + .attributeCall(choiceType.withEmptyMeta, a, false, a.toMetaJavaType, scope) .declareAsVariable(true, a.name.toFirstLower, scope) .mapExpression[attrVar| attrVar.exists(ExistsModifier.NONE, scope) @@ -123,9 +124,9 @@ class DeepPathUtilGenerator { val actualFeature = if (needsToGoDownDeeper || !(attrType instanceof RDataType)) { deepFeature } else { - (attrType as RDataType).allNonOverridenAttributes.findFirst[name.equals(deepFeature.name)] + (attrType as RDataType).allAttributes.findFirst[name.equals(deepFeature.name)] } - attrVar.attributeCall(metaRType, actualFeature, needsToGoDownDeeper, scope) + attrVar.attributeCall(metaRType, actualFeature, needsToGoDownDeeper, deepFeatureType, scope) } new JavaIfThenElseBuilder(it, deepFeatureExpr, currAcc, typeUtil) ] diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/expression/ExpressionGenerator.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/expression/ExpressionGenerator.xtend index 8580199e9..f93282bd1 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/expression/ExpressionGenerator.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/expression/ExpressionGenerator.xtend @@ -113,7 +113,6 @@ import com.rosetta.model.lib.mapper.MapperC import com.rosetta.model.lib.mapper.MapperS import com.rosetta.model.lib.records.Date import com.rosetta.model.lib.validation.ChoiceRuleValidationMethod -import com.rosetta.util.types.JavaClass import com.rosetta.util.types.JavaGenericTypeDeclaration import com.rosetta.util.types.JavaPrimitiveType import com.rosetta.util.types.JavaType @@ -294,26 +293,48 @@ class ExpressionGenerator extends RosettaExpressionSwitchmap("«feature.name.toFirstUpper»", «recordUtil.recordFeatureToLambda(receiverType.RType as RRecordType, feature, scope)»)''' val mapperReceiverCode = typeCoercionService.addCoercions(receiverCode, MAPPER.wrapExtendsWithoutMeta(receiverCode.expressionType.itemType), scope) - featureCall(mapperReceiverCode, resultItemType, right, receiverCode, receiverType, feature, scope) + featureCall(mapperReceiverCode, resultItemType, right, receiverCode, receiverType, cardinalityProvider.isFeatureMulti(feature), scope) } - def JavaStatementBuilder attributeCall(JavaStatementBuilder receiverCode, RMetaAnnotatedType receiverType, RAttribute attr, boolean isDeepFeature, JavaScope scope) { - val resultItemType = attr.toMetaItemJavaType - - val StringConcatenationClient right = receiverType.buildMapFunc(attr, isDeepFeature, scope) + def JavaStatementBuilder attributeCall(JavaStatementBuilder receiverCode, RMetaAnnotatedType receiverType, RAttribute attr, boolean isDeepFeature, JavaType expectedType, JavaScope scope) { + val receiverRType = receiverType.RType + val t = if (receiverRType instanceof RChoiceType) { + receiverRType.asRDataType + } else { + receiverRType as RDataType + } + val javaType = t.toJavaReferenceType + val lambdaScope = scope.lambdaScope + val lambdaParam = new JavaVariable(lambdaScope.createUniqueIdentifier(javaType.rosettaName.toFirstLower), javaType) + var JavaType resultItemType + val StringConcatenationClient mappingCode = if (isDeepFeature) { + resultItemType = attr.toMetaItemJavaType + '''"choose«attr.name.toFirstUpper»", «lambdaParam» -> «scope.getIdentifierOrThrow(t.toDeepPathUtilJavaClass.toDependencyInstance)».choose«attr.name.toFirstUpper»(«lambdaParam»)''' + } else { + val prop = javaType.findProperty(attr.name, expectedType) + resultItemType = prop.type.itemType + '''"get«prop.name.toFirstUpper»", «lambdaParam» -> «prop.applyGetter(lambdaParam)»''' + } + val r = resultItemType + val StringConcatenationClient right = if (attr.isMulti) { + '''.<«r»>mapC(«mappingCode»)''' + } else { + '''.<«r»>map(«mappingCode»)''' + } + val mapperReceiverCode = typeCoercionService.addCoercions(receiverCode, MAPPER.wrapExtendsWithoutMeta(receiverCode.expressionType.itemType), scope) - featureCall(mapperReceiverCode, resultItemType, right, receiverCode, receiverType, attr.EObject, scope) + featureCall(mapperReceiverCode, resultItemType, right, receiverCode, receiverType, attr.isMulti, scope) } - private def JavaStatementBuilder featureCall(JavaStatementBuilder mapperReceiverCode, JavaClass resultItemType, StringConcatenationClient right, JavaStatementBuilder receiverCode, RMetaAnnotatedType receiverType, RosettaFeature feature, JavaScope scope) { - val resultWrapper = if (mapperReceiverCode.expressionType.isMapperS && !cardinalityProvider.isFeatureMulti(feature)) { + private def JavaStatementBuilder featureCall(JavaStatementBuilder mapperReceiverCode, JavaType resultItemType, StringConcatenationClient right, JavaStatementBuilder receiverCode, RMetaAnnotatedType receiverType, boolean isMulti, JavaScope scope) { + val resultWrapper = if (mapperReceiverCode.expressionType.isMapperS && !isMulti) { MAPPER_S as JavaGenericTypeDeclaration } else { MAPPER_C as JavaGenericTypeDeclaration @@ -426,19 +447,6 @@ class ExpressionGenerator extends RosettaExpressionSwitchmapC(«mapFunc»)''' - } else { - '''.<«resultType»>map(«mapFunc»)''' - } - } - private def static StringConcatenationClient buildMapFunc(RosettaMetaType meta, JavaScope scope) { if (meta.name == "reference") { val lambdaScope = scope.lambdaScope @@ -536,22 +544,6 @@ class ExpressionGenerator extends RosettaExpressionSwitch «scope.getIdentifierOrThrow((t as RDataType).toDeepPathUtilJavaClass.toDependencyInstance)».choose«attribute.name.toFirstUpper»(«lambdaParam»)''' - } else { - '''"get«attribute.name.toFirstUpper»", «lambdaParam» -> «lambdaParam».get«attribute.name.toFirstUpper»()''' - } - } - /** * Create a string representation of a rosetta function * mainly used to give human readable names to the mapping functions used to extract attributes @@ -709,7 +701,7 @@ class ExpressionGenerator extends RosettaExpressionSwitch ].orElse(wrapConversion) @@ -152,7 +160,7 @@ class TypeCoercionService { ) } } - private def JavaStatementBuilder wrapperToItem(JavaExpression expr, JavaType expected, JavaScope scope) { + private def JavaStatementBuilder wrapperToItem(JavaExpression expr, JavaType expected, boolean throwOnFail, JavaScope scope) { val actual = expr.expressionType // Strategy: // - unwrap the given expression. @@ -167,9 +175,9 @@ class TypeCoercionService { val unwrappedExpr = getUnwrapConversion(actual).apply(expr) - itemToItem(unwrappedExpr, expected, scope) + itemToItem(unwrappedExpr, expected, throwOnFail, scope) } - private def JavaExpression wrapperToWrapper(JavaExpression expr, JavaType expected, JavaScope scope) { + private def JavaExpression wrapperToWrapper(JavaExpression expr, JavaType expected, boolean throwOnFail, JavaScope scope) { val actual = expr.expressionType val expectedItemType = expected.itemType @@ -178,7 +186,7 @@ class TypeCoercionService { // - Otherwise, first convert the item type to the expected item type (if necessary), // - then convert the wrapper type to the expected wrapper type (if necessary). - val optionalWrappedItemConversion = getWrappedItemConversion(actual, expectedItemType, scope) + val optionalWrappedItemConversion = getWrappedItemConversion(actual, expectedItemType, throwOnFail, scope) val optionalWrapperConversion = getWrapperConversion( optionalWrappedItemConversion.empty ? actual : actual.changeItemType(expectedItemType), expected @@ -199,7 +207,7 @@ class TypeCoercionService { return totalConversion.apply(expr) } - private def Optional> getItemConversion(JavaType actual, JavaType expected, JavaScope scope) { + private def Optional> getItemConversion(JavaType actual, JavaType expected, boolean throwOnFail, JavaScope scope) { if (actual == expected) { return Optional.empty } @@ -209,13 +217,17 @@ class TypeCoercionService { return Optional.of([it]) } else if (actual.toReferenceType.extendsNumber && expected.toReferenceType.extendsNumber) { // Number type to number type - return Optional.of([getNumberConversionExpression(it, expected)]) - } - else if (actual instanceof RJavaWithMetaValue) { - return Optional.of([metaToItemConversionExpression(it, expected, scope)]) - } else if (expected instanceof RJavaFieldWithMeta || expected instanceof RJavaReferenceWithMeta) { - return Optional.of([itemToMetaConversionExpression(it, expected as RJavaWithMetaValue, scope)]) - } + return Optional.of([getNumberConversionExpression(it, expected, throwOnFail, scope)]) + } else if (actual instanceof RJavaWithMetaValue) { + // Meta to non-meta + return Optional.of([metaToItemConversionExpression(it, expected, throwOnFail, scope)]) + } else if (expected instanceof RJavaWithMetaValue) { + // Non-meta to meta + return Optional.of([itemToMetaConversionExpression(it, expected, throwOnFail, scope)]) + } else if (expected instanceof JavaPojoInterface && expected.isSubtypeOf(actual)) { + // Supertype to subtype + return Optional.of([downCastConversionExpression(it, expected as JavaPojoInterface, throwOnFail, scope)]) + } return Optional.empty } private def Function getWrapConversion(JavaType wrapperType) { @@ -240,10 +252,10 @@ class TypeCoercionService { throw unexpectedWrapperException(wrapperType) } } - private def Optional> getWrappedItemConversion(JavaType actual, JavaType expectedItemType, JavaScope scope) { + private def Optional> getWrappedItemConversion(JavaType actual, JavaType expectedItemType, boolean throwOnFail, JavaScope scope) { val actualItemType = actual.itemType - getItemConversion(actualItemType, expectedItemType, scope) + getItemConversion(actualItemType, expectedItemType, throwOnFail, scope) .map[itemConversion| if (actual.isList) { [getListItemConversionExpression(it, itemConversion, expectedItemType.toReferenceType, scope)] @@ -376,11 +388,11 @@ class TypeCoercionService { * 1. Unwrap the meta by calling getValue() on the expression * 2. Map expression to a call to itemToItem(it, expected) */ - private def JavaStatementBuilder metaToItemConversionExpression(JavaExpression expression, JavaType expected, JavaScope scope) { + private def JavaStatementBuilder metaToItemConversionExpression(JavaExpression expression, JavaType expected, boolean throwOnFail, JavaScope scope) { val actual = expression.expressionType if (actual instanceof RJavaWithMetaValue) { JavaExpression.from('''«expression».getValue()''', actual.valueType) - .mapExpression[itemToItem(it, expected, scope)] + .mapExpression[itemToItem(it, expected, throwOnFail, scope)] } else { JavaExpression.NULL } @@ -391,9 +403,9 @@ class TypeCoercionService { * 2. If the lambda exists then run it and wrap the response in RJavaWithMetaValue builder * 3. If no lambda exists wrap the given expression in RJavaWithMetaValue builder */ - private def JavaStatementBuilder itemToMetaConversionExpression(JavaExpression expression, RJavaWithMetaValue expected, JavaScope scope) { + private def JavaStatementBuilder itemToMetaConversionExpression(JavaExpression expression, RJavaWithMetaValue expected, boolean throwOnFail, JavaScope scope) { val expectedValueType = expected.valueType - getItemConversion(expression.expressionType, expectedValueType, scope) + getItemConversion(expression.expressionType, expectedValueType, throwOnFail, scope) .map[itemConversion| itemConversion.apply(expression) .mapExpression[JavaExpression.from('''«expected».builder().setValue(«it»).build()''', expected)] @@ -401,7 +413,24 @@ class TypeCoercionService { .orElseGet[JavaExpression.from('''«expected».builder().setValue(«expression»).build()''', expected)] } - private def JavaExpression getNumberConversionExpression(JavaExpression expression, JavaType expected) { + private def JavaStatementBuilder downCastConversionExpression(JavaExpression expression, JavaPojoInterface expected, boolean throwOnFail, JavaScope scope) { + if (throwOnFail) { + JavaExpression.from('''«expected».class.cast(«expression»)''', expected) + } else { + expression + .declareAsVariable(true, expression.expressionType.simpleName.toFirstLower, scope) + .mapExpression[ + new JavaConditionalExpression( + JavaExpression.from('''«it» instanceof «expected»''', JavaPrimitiveType.BOOLEAN), + JavaExpression.from('''«expected».class.cast(«it»)''', expected), + JavaExpression.NULL, + typeUtil + ) + ] + } + } + + private def JavaStatementBuilder getNumberConversionExpression(JavaExpression expression, JavaType expected, boolean throwOnFail, JavaScope scope) { val actual = expression.expressionType if (actual.toReferenceType.isInteger) { if (expected.toReferenceType.isLong) { @@ -430,7 +459,19 @@ class TypeCoercionService { } else if (actual.toReferenceType.isLong) { if (expected.toReferenceType.isInteger) { // Case long/Long to int/Integer - JavaExpression.from('''«Math».toIntExact(«expression»)''', JavaPrimitiveType.INT) + if (throwOnFail) { + JavaExpression.from('''«Math».toIntExact(«expression»)''', JavaPrimitiveType.INT) + } else { + expression.declareAsVariable(true, "i", scope) + .mapExpression[ + new JavaConditionalExpression( + JavaExpression.from('''«it» <= «Integer».MAX_VALUE && «it» >= «Integer».MIN_VALUE''', JavaPrimitiveType.BOOLEAN), + JavaExpression.from('''(int) «it»''', JavaPrimitiveType.INT), + JavaExpression.NULL, + typeUtil + ) + ] + } } else if (expected.isBigInteger) { // Case long/Long to BigInteger JavaExpression.from('''«BigInteger».valueOf(«expression»)''', BIG_INTEGER) @@ -443,10 +484,34 @@ class TypeCoercionService { } else if (actual.isBigInteger) { if (expected.toReferenceType.isInteger) { // Case BigInteger to int/Integer - JavaExpression.from('''«expression».intValueExact()''', JavaPrimitiveType.INT) + if (throwOnFail) { + JavaExpression.from('''«expression».intValueExact()''', JavaPrimitiveType.INT) + } else { + expression.declareAsVariable(true, "i", scope) + .mapExpression[ + new JavaConditionalExpression( + JavaExpression.from('''«BigInteger».valueOf(«it».intValue()).equals(«it»)''', JavaPrimitiveType.BOOLEAN), + JavaExpression.from('''«it».intValue()''', JavaPrimitiveType.INT), + JavaExpression.NULL, + typeUtil + ) + ] + } } else if (expected.toReferenceType.isLong) { // Case BigInteger to long/Long - JavaExpression.from('''«expression».longValueExact()''', JavaPrimitiveType.LONG) + if (throwOnFail) { + JavaExpression.from('''«expression».longValueExact()''', JavaPrimitiveType.LONG) + } else { + expression.declareAsVariable(true, "i", scope) + .mapExpression[ + new JavaConditionalExpression( + JavaExpression.from('''«BigInteger».valueOf(«it».longValue()).equals(«it»)''', JavaPrimitiveType.BOOLEAN), + JavaExpression.from('''«it».longValue()''', JavaPrimitiveType.LONG), + JavaExpression.NULL, + typeUtil + ) + ] + } } else if (expected.isBigDecimal) { // Case BigInteger to BigDecimal JavaExpression.from('''new «BigDecimal»(«expression»)''', BIG_DECIMAL) @@ -456,13 +521,49 @@ class TypeCoercionService { } else if (actual.isBigDecimal) { if (expected.toReferenceType.isInteger) { // Case BigDecimal to int/Integer - JavaExpression.from('''«expression».intValueExact()''', JavaPrimitiveType.INT) + if (throwOnFail) { + JavaExpression.from('''«expression».intValueExact()''', JavaPrimitiveType.INT) + } else { + expression.declareAsVariable(true, "d", scope) + .mapExpression[ + new JavaConditionalExpression( + JavaExpression.from('''«BigDecimal».valueOf(«it».intValue()).compareTo(«it») == 0''', JavaPrimitiveType.BOOLEAN), + JavaExpression.from('''«it».intValue()''', JavaPrimitiveType.INT), + JavaExpression.NULL, + typeUtil + ) + ] + } } else if (expected.toReferenceType.isLong) { // Case BigDecimal to long/Long - JavaExpression.from('''«expression».longValueExact()''', JavaPrimitiveType.LONG) + if (throwOnFail) { + JavaExpression.from('''«expression».longValueExact()''', JavaPrimitiveType.LONG) + } else { + expression.declareAsVariable(true, "d", scope) + .mapExpression[ + new JavaConditionalExpression( + JavaExpression.from('''«BigDecimal».valueOf(«it».longValue()).compareTo(«it») == 0''', JavaPrimitiveType.BOOLEAN), + JavaExpression.from('''«it».longValue()''', JavaPrimitiveType.LONG), + JavaExpression.NULL, + typeUtil + ) + ] + } } else if (expected.isBigInteger) { // Case BigDecimal to BigInteger - JavaExpression.from('''«expression».toBigIntegerExact()''', BIG_INTEGER) + if (throwOnFail) { + JavaExpression.from('''«expression».toBigIntegerExact()''', BIG_INTEGER) + } else { + expression.declareAsVariable(true, "d", scope) + .mapExpression[ + new JavaConditionalExpression( + JavaExpression.from('''new «BigDecimal»(«it».toBigInteger()).compareTo(«it») == 0''', JavaPrimitiveType.BOOLEAN), + JavaExpression.from('''«it».toBigInteger()''', BIG_INTEGER), + JavaExpression.NULL, + typeUtil + ) + ] + } } else { throw unexpectedCaseException(actual, expected) } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/function/FunctionGenerator.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/function/FunctionGenerator.xtend index 149418f0f..66f6dbaa6 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/function/FunctionGenerator.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/function/FunctionGenerator.xtend @@ -69,6 +69,9 @@ import static com.regnosys.rosetta.generator.java.enums.EnumHelper.* import static com.regnosys.rosetta.generator.java.util.ModelGeneratorUtil.* import static extension com.regnosys.rosetta.types.RMetaAnnotatedType.withEmptyMeta +import com.regnosys.rosetta.generator.java.statement.builder.JavaVariable +import com.regnosys.rosetta.generator.java.types.JavaPojoInterface +import com.regnosys.rosetta.generator.java.types.RJavaWithMetaValue class FunctionGenerator { @@ -343,7 +346,7 @@ class FunctionGenerator { val evaluateScope = classScope.methodScope("evaluate") function.inputs.forEach[evaluateScope.createIdentifier(it)] ''' - «javadoc(function, version)» + «javadoc(function.definition, function.references, version)» public class «className» implements «RosettaFunction» { «FOR dep : dependencies» @«Inject» protected «dep» «dep.simpleName.toFirstLower»; @@ -437,16 +440,32 @@ class FunctionGenerator { assignValue(scope, op, op.assignAsKey) .collapseToSingleExpression(scope) .mapExpression[ - JavaExpression.from( - ''' - «op.assignTarget(function, outs, scope)» - «FOR seg : op.pathTail.indexed» - «IF seg.key < op.pathTail.size - 1» - .getOrCreate«seg.value.name.toFirstUpper»(«IF seg.value.multi»0«ENDIF»)«IF seg.value.RMetaAnnotatedType.hasMeta».getOrCreateValue()«ENDIF» - «ELSE» - .«IF op.ROperationType == ROperationType.ADD»add«ELSE»set«ENDIF»«seg.value.name.toFirstUpper»«IF seg.value.RMetaAnnotatedType.hasMeta && !op.assignAsKey»Value«ENDIF»(«it»)«ENDIF»«ENDFOR»''', - JavaPrimitiveType.VOID - ) + var expr = op.assignTarget(function, outs, scope) + for (seg : op.pathTail.indexed) { + val oldExpr = expr + val prop = (expr.expressionType as JavaPojoInterface).findProperty(seg.value.name) + val itemType = prop.type.itemType + if (seg.key < op.pathTail.size - 1) { + expr = JavaExpression.from( + ''' + «oldExpr» + .«prop.getOrCreateName»(«IF prop.type.isList»0«ENDIF»)''', + itemType + ) + if (itemType instanceof RJavaWithMetaValue) { + val metaExpr = expr + expr = JavaExpression.from('''«metaExpr».getOrCreateValue()''', itemType.valueType) + } + } else { + expr = JavaExpression.from( + ''' + «oldExpr» + .«IF op.ROperationType == ROperationType.ADD»add«ELSE»set«ENDIF»«prop.name.toFirstUpper»«IF itemType instanceof RJavaWithMetaValue && !op.assignAsKey»Value«ENDIF»(«it»)''', + JavaPrimitiveType.VOID + ) + } + } + expr ].completeAsExpressionStatement } } @@ -502,59 +521,60 @@ class FunctionGenerator { } } - private def StringConcatenationClient assignTarget(ROperation operation, RFunction function, Map outs, + private def JavaExpression assignTarget(ROperation operation, RFunction function, Map outs, JavaScope scope) { val root = operation.pathHead switch (root) { - RAttribute: '''«scope.getIdentifierOrThrow(root)»''' + RAttribute: new JavaVariable(scope.getIdentifierOrThrow(root), root.RMetaAnnotatedType.toJavaReferenceType) RShortcut: unfoldLHSShortcut(root, function, scope) } } - private def StringConcatenationClient unfoldLHSShortcut(RShortcut shortcut, RFunction function, JavaScope scope) { + private def JavaExpression unfoldLHSShortcut(RShortcut shortcut, RFunction function, JavaScope scope) { val e = shortcut.expression if (e instanceof RosettaSymbolReference) { if (e.symbol instanceof RosettaCallableWithArgs) { // assign-output for an alias - return '''«scope.getIdentifierOrThrow(shortcut)»(«expressionGenerator.aliasCallArgs(shortcut, function, scope)»)''' + return JavaExpression.from('''«scope.getIdentifierOrThrow(shortcut)»(«expressionGenerator.aliasCallArgs(shortcut, function, scope)»)''', shortcut.shortcutExpressionJavaType) } } - return '''«lhsExpand(e, scope)»''' + return lhsExpand(e, scope) } - private def dispatch StringConcatenationClient lhsExpand(RosettaExpression f, JavaScope scope) { + private def dispatch JavaExpression lhsExpand(RosettaExpression f, JavaScope scope) { throw new IllegalStateException("No implementation for lhsExpand for " + f.class) } - private def dispatch StringConcatenationClient lhsExpand(RosettaFeatureCall f, - JavaScope scope) '''«lhsExpand(f.receiver, scope)».«f.feature.lhsFeature»''' + private def dispatch JavaExpression lhsExpand(RosettaFeatureCall f, + JavaScope scope) { lhsExpand(f.receiver, scope).lhsFeature(f.feature) } - private def dispatch StringConcatenationClient lhsExpand(RosettaSymbolReference f, - JavaScope scope) '''«f.symbol.lhsExpand(scope)»''' + private def dispatch JavaExpression lhsExpand(RosettaSymbolReference f, + JavaScope scope) { f.symbol.lhsExpand(scope) } - private def dispatch StringConcatenationClient lhsExpand(ShortcutDeclaration f, - JavaScope scope) '''«f.expression.lhsExpand(scope)»''' + private def dispatch JavaExpression lhsExpand(ShortcutDeclaration f, + JavaScope scope) { f.expression.lhsExpand(scope) } - private def dispatch StringConcatenationClient lhsExpand(RosettaUnaryOperation f, - JavaScope scope) '''«f.argument.lhsExpand(scope)»''' + private def dispatch JavaExpression lhsExpand(RosettaUnaryOperation f, + JavaScope scope) { f.argument.lhsExpand(scope) } - private def dispatch StringConcatenationClient lhsFeature(RosettaFeature f) { + private def dispatch JavaExpression lhsFeature(JavaExpression receiver, RosettaFeature f) { throw new IllegalStateException("No implementation for lhsFeature for " + f.class) } - private def dispatch StringConcatenationClient lhsFeature(Attribute f) { - val rAttribute = rTypeBuilderFactory.buildRAttribute(f) - if (rAttribute.multi) '''getOrCreate«rAttribute.name.toFirstUpper»(0)''' else '''getOrCreate«rAttribute.name.toFirstUpper»()''' + private def dispatch JavaExpression lhsFeature(JavaExpression receiver, Attribute f) { + val t = receiver.expressionType as JavaPojoInterface + val prop = t.findProperty(f.name) + JavaExpression.from('''«receiver».«prop.getOrCreateName»(«IF prop.type.isList»0«ENDIF»)''', prop.type.itemType) } - private def dispatch StringConcatenationClient lhsExpand(RosettaSymbol c, JavaScope scope) { + private def dispatch JavaExpression lhsExpand(RosettaSymbol c, JavaScope scope) { throw new IllegalStateException("No implementation for lhsExpand for " + c.class) } - private def dispatch StringConcatenationClient lhsExpand(Attribute c, JavaScope scope) { + private def dispatch JavaExpression lhsExpand(Attribute c, JavaScope scope) { val rAttribute = rTypeBuilderFactory.buildRAttribute(c) - '''«scope.getIdentifierOrThrow(rAttribute)»''' + new JavaVariable(scope.getIdentifierOrThrow(rAttribute), rAttribute.RMetaAnnotatedType.toJavaReferenceType) } private def StringConcatenationClient contributeCondition(Condition condition, diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/MetaFieldGenerator.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/MetaFieldGenerator.xtend index 89c84fdcd..485b08b34 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/MetaFieldGenerator.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/MetaFieldGenerator.xtend @@ -1,36 +1,14 @@ package com.regnosys.rosetta.generator.java.object -import com.fasterxml.jackson.core.type.TypeReference -import com.google.common.collect.Multimaps import com.regnosys.rosetta.generator.java.JavaScope -import com.regnosys.rosetta.generator.java.RosettaJavaPackages import com.regnosys.rosetta.generator.java.RosettaJavaPackages.RootPackage import com.regnosys.rosetta.generator.java.types.JavaTypeTranslator import com.regnosys.rosetta.generator.java.util.ImportManagerExtension -import com.regnosys.rosetta.rosetta.RosettaFactory -import com.regnosys.rosetta.rosetta.RosettaMetaType import com.regnosys.rosetta.rosetta.RosettaModel -import com.regnosys.rosetta.rosetta.RosettaType -import com.regnosys.rosetta.rosetta.impl.RosettaFactoryImpl import com.regnosys.rosetta.rosetta.simple.Attribute -import com.regnosys.rosetta.rosetta.simple.Data -import com.regnosys.rosetta.rosetta.simple.SimpleFactory -import com.regnosys.rosetta.scoping.RosettaScopeProvider -import com.regnosys.rosetta.types.RAttribute -import com.regnosys.rosetta.types.RMetaAnnotatedType import com.regnosys.rosetta.types.RObjectFactory -import com.regnosys.rosetta.utils.PositiveIntegerInterval -import com.rosetta.model.lib.GlobalKey import com.rosetta.model.lib.meta.BasicRosettaMetaData -import com.rosetta.model.lib.meta.FieldWithMeta -import com.rosetta.model.lib.meta.GlobalKeyFields -import com.rosetta.model.lib.meta.MetaDataFields -import com.rosetta.model.lib.meta.ReferenceWithMeta -import com.rosetta.model.lib.meta.TemplateFields -import com.rosetta.util.types.JavaParameterizedType import com.rosetta.util.types.generated.GeneratedJavaClass -import java.util.ArrayList -import java.util.List import javax.inject.Inject import org.eclipse.emf.common.notify.impl.AdapterFactoryImpl import org.eclipse.emf.ecore.resource.Resource @@ -40,13 +18,11 @@ import org.eclipse.xtext.generator.IGeneratorContext import com.regnosys.rosetta.generator.java.types.RJavaFieldWithMeta import com.regnosys.rosetta.generator.java.types.RJavaReferenceWithMeta import static extension org.eclipse.xtext.EcoreUtil2.* -import static extension com.regnosys.rosetta.types.RMetaAnnotatedType.* import com.regnosys.rosetta.types.RType class MetaFieldGenerator { @Inject extension ImportManagerExtension @Inject extension ModelObjectGenerator - @Inject RosettaJavaPackages packages @Inject extension JavaTypeTranslator @Inject extension RObjectFactory @@ -56,28 +32,11 @@ class MetaFieldGenerator { val model = resource.contents.filter(RosettaModel).head if((model?.name).nullOrEmpty){ return - } - - -// TODO - This code is intended to only generate MetaFields.java once per name space. This however causes an issue when running with the incremental builder that deletes the file as a clean up and never re-generates it. -// if (resource.resourceSet.adapterFactories.filter(MarkerAdapterFactory).findFirst[namespace == model.name] === null) { -// try { - val allModels = resource.resourceSet.resources.flatMap[contents].filter(RosettaModel).toList - val allMetaTypes = allModels.flatMap[elements].filter(RosettaMetaType).toList - fsa.generateFile('''«packages.basicMetafields.withForwardSlashes»/MetaFields.java''', - metaFields("MetaFields", newArrayList(GlobalKeyFields), allMetaTypes.getMetaFieldTypes)) - - fsa.generateFile('''«packages.basicMetafields.withForwardSlashes»/MetaAndTemplateFields.java''', - metaFields("MetaAndTemplateFields", newArrayList(GlobalKeyFields, TemplateFields), allMetaTypes.getMetaAndTemplateFieldTypes)) -// } finally { -// resource.resourceSet.adapterFactories.add(new MarkerAdapterFactory(model.name)) -// } -// } - + } //find all the reference types if (ctx.cancelIndicator.canceled) { - return + return } for (attr : model.eAllOfType(Attribute).map[buildRAttribute].filter[RMetaAnnotatedType.hasMeta]) { val targetModel = attr.RMetaAnnotatedType.RType.namespace @@ -97,133 +56,12 @@ class MetaFieldGenerator { } } } - - def toTypeCall(RosettaType t) { - val typeCall = RosettaFactoryImpl.eINSTANCE.createTypeCall - typeCall.type = t - return typeCall - } - - def getStringType() { - val stringType = RosettaFactoryImpl.eINSTANCE.createRosettaMetaType - stringType.name="string" - stringType.model = RosettaFactory.eINSTANCE.createRosettaModel - stringType.model.name = "com.rosetta.model.lib" - return stringType.toTypeCall - } - - def getCardSingle() { - val cardSingle = RosettaFactory.eINSTANCE.createRosettaCardinality - cardSingle.inf = 0 - cardSingle.sup = 1 - cardSingle - } - - def List getMetaFieldTypes(List utypes) { - val cardMult = RosettaFactory.eINSTANCE.createRosettaCardinality - cardMult.inf = 0; - cardMult.sup = 1000; - cardMult.unbounded = true - - val globalKeyAttribute = SimpleFactory.eINSTANCE.createAttribute() - globalKeyAttribute.setName("globalKey") - globalKeyAttribute.card = cardSingle - globalKeyAttribute.typeCall = stringType - val externalKeyAttribute = SimpleFactory.eINSTANCE.createAttribute() - externalKeyAttribute.setName("externalKey") - externalKeyAttribute.card = cardSingle - externalKeyAttribute.typeCall = stringType - - val keysType = SimpleFactory.eINSTANCE.createData() - keysType.setName("Key") - keysType.model = RosettaFactory.eINSTANCE.createRosettaModel - keysType.model.name = "com.rosetta.model.lib.meta" - val keysAttribute = SimpleFactory.eINSTANCE.createAttribute() - keysAttribute.setName("key") - keysAttribute.typeCall = keysType.toTypeCall - keysAttribute.card = cardMult - - val filteredTypes = utypes.filter[t|t.name != "key" && t.name != "id" && t.name != "reference"].toSet - val result = filteredTypes.map[toAttribute].toList - result.addAll(#[globalKeyAttribute, externalKeyAttribute, keysAttribute]) - return result - } - - def toAttribute(RosettaMetaType type) { - val newAttribute = SimpleFactory.eINSTANCE.createAttribute() - newAttribute.card = cardSingle - newAttribute.name = type.name - newAttribute.typeCall = type.toTypeCall - return newAttribute - } - - def getMetaAndTemplateFieldTypes(List utypes) { - val templateGlobalReferenceType = RosettaFactoryImpl.eINSTANCE.createRosettaMetaType() - templateGlobalReferenceType.name = "templateGlobalReference" - templateGlobalReferenceType.typeCall = stringType - - val libModel = RosettaFactory.eINSTANCE.createRosettaModel - libModel.name = RosettaScopeProvider.LIB_NAMESPACE - templateGlobalReferenceType.model = libModel - - val plusTypes = new ArrayList(utypes) - plusTypes.add(templateGlobalReferenceType) - val metaFieldTypes = plusTypes.getMetaFieldTypes - return metaFieldTypes - } - - def metaFields(String name, List interfaces, List attributes) { - if (attributes.exists[t|t.name == "scheme"]) { - interfaces.add(MetaDataFields) - } - - val Data d = SimpleFactory.eINSTANCE.createData; - d.name = name - d.model = RosettaFactory.eINSTANCE.createRosettaModel - d.model.name = packages.basicMetafields.withDots - d.attributes.addAll(attributes) - - val scope = new JavaScope(packages.basicMetafields) - - val StringConcatenationClient body = ''' - «d.buildRDataType.classBody(scope, new GeneratedJavaClass(packages.basicMetafields, d.name+'Meta', Object), "1", interfaces)» - - class «name»Meta extends «BasicRosettaMetaData»<«name»>{ - - } - ''' - buildClass(packages.basicMetafields, body, scope) - } - - private def CharSequence fieldWithMeta(RootPackage root, RJavaFieldWithMeta metaJavaType, RType valueType) { - val valueAttribute = new RAttribute( - "value", null, emptyList, valueType.withEmptyMeta, PositiveIntegerInterval.bounded(0, 1), null, null - ) - - val metaType = SimpleFactory.eINSTANCE.createData() - metaType.setName("MetaFields") - metaType.model = RosettaFactory.eINSTANCE.createRosettaModel - metaType.model.name = packages.basicMetafields.withDots - val metaAttribute = SimpleFactory.eINSTANCE.createAttribute() - metaAttribute.setName("meta") - metaAttribute.typeCall = metaType.toTypeCall - metaAttribute.card = cardSingle - - val Data d = SimpleFactory.eINSTANCE.createData; - d.name = metaJavaType.simpleName - d.model = RosettaFactory.eINSTANCE.createRosettaModel - d.model.name = metaJavaType.packageName.withDots - d.attributes.addAll(#[ - metaAttribute - ]) - - val FWMType = JavaParameterizedType.from(new TypeReference>() {}, valueType.toJavaReferenceType) - + private def CharSequence fieldWithMeta(RootPackage root, RJavaFieldWithMeta metaJavaType, RType valueType) { val scope = new JavaScope(metaJavaType.packageName) val StringConcatenationClient body = ''' - «d.buildRDataType(#[valueAttribute]).classBody(scope, new GeneratedJavaClass(metaJavaType.packageName, d.name + "Meta", Object), "1", #[GlobalKey, FWMType])» + «metaJavaType.classBody(scope, new GeneratedJavaClass(metaJavaType.packageName, metaJavaType.simpleName + "Meta", Object), "1")» class «metaJavaType.simpleName»Meta extends «BasicRosettaMetaData»<«metaJavaType.simpleName»>{ @@ -233,44 +71,11 @@ class MetaFieldGenerator { buildClass(metaJavaType.packageName, body, scope) } - private def referenceAttributes() { - val globalRefAttribute = SimpleFactory.eINSTANCE.createAttribute() - globalRefAttribute.setName("globalReference") - globalRefAttribute.card = cardSingle - globalRefAttribute.typeCall = stringType - - val externalRefAttribute = SimpleFactory.eINSTANCE.createAttribute() - externalRefAttribute.setName("externalReference") - externalRefAttribute.card = cardSingle - externalRefAttribute.typeCall = stringType - - val refType = SimpleFactory.eINSTANCE.createData() - refType.setName("Reference") - refType.model = RosettaFactory.eINSTANCE.createRosettaModel - refType.model.name = "com.rosetta.model.lib.meta" - val refAttribute = SimpleFactory.eINSTANCE.createAttribute() - refAttribute.setName("reference") - refAttribute.typeCall = refType.toTypeCall - refAttribute.card = cardSingle - #[globalRefAttribute, externalRefAttribute, refAttribute] - } - - private def referenceWithMeta(RootPackage root, RJavaReferenceWithMeta metaJavaType, RType valueType) { - val valueAttribute = new RAttribute( - "value", null, emptyList, valueType.withEmptyMeta, PositiveIntegerInterval.bounded(0, 1), null, null - ) - - val Data d = SimpleFactory.eINSTANCE.createData; - d.name = metaJavaType.simpleName - d.model = RosettaFactory.eINSTANCE.createRosettaModel - d.model.name = metaJavaType.packageName.withDots - d.attributes.addAll(referenceAttributes()) - val refInterface = JavaParameterizedType.from(new TypeReference>() {}, valueType.toJavaReferenceType) - + private def referenceWithMeta(RootPackage root, RJavaReferenceWithMeta metaJavaType, RType valueType) { val scope = new JavaScope(root.metaField) val StringConcatenationClient body = ''' - «d.buildRDataType(#[valueAttribute]).classBody(scope, new GeneratedJavaClass(root.metaField, d.name + "Meta", Object), "1", #[refInterface])» + «metaJavaType.classBody(scope, new GeneratedJavaClass(root.metaField, metaJavaType.simpleName + "Meta", Object), "1")» class «metaJavaType.simpleName»Meta extends «BasicRosettaMetaData»<«metaJavaType.simpleName»>{ @@ -281,7 +86,7 @@ class MetaFieldGenerator { } /** generate once per resource marker */ - static class MarkerAdapterFactory extends AdapterFactoryImpl { + private static class MarkerAdapterFactory extends AdapterFactoryImpl { final String namespace diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ModelMetaGenerator.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ModelMetaGenerator.xtend index bc91190f8..2a93da9ec 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ModelMetaGenerator.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ModelMetaGenerator.xtend @@ -52,9 +52,9 @@ class ModelMetaGenerator { private def StringConcatenationClient metaClassBody(RDataType t, RootPackage root, String className, String version) { val dataClass = t.toJavaType - val validator = t.toValidatorClass - val typeFormatValidator = t.toTypeFormatValidatorClass - val onlyExistsValidator = t.toOnlyExistsValidatorClass + val validator = dataClass.toValidatorClass + val typeFormatValidator = dataClass.toTypeFormatValidatorClass + val onlyExistsValidator = dataClass.toOnlyExistsValidatorClass val context = t.EObject.eResource.resourceSet val qualifierFuncs = qualifyFuncs(t.EObject, context.resources.map[contents.head as RosettaModel].toSet) val conditions = t.allSuperTypes.map[conditionRules(it.EObject.conditions)].flatten diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ModelObjectBoilerPlate.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ModelObjectBoilerPlate.xtend index e16818bef..e0e54b8a9 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ModelObjectBoilerPlate.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ModelObjectBoilerPlate.xtend @@ -1,81 +1,67 @@ package com.regnosys.rosetta.generator.java.object -import com.regnosys.rosetta.RosettaEcoreUtil import com.regnosys.rosetta.generator.java.JavaScope import com.regnosys.rosetta.generator.java.types.JavaTypeTranslator -import com.regnosys.rosetta.rosetta.simple.Data -import com.regnosys.rosetta.types.RAttribute -import com.regnosys.rosetta.types.RDataType -import com.regnosys.rosetta.types.REnumType -import com.regnosys.rosetta.types.TypeSystem -import com.rosetta.model.lib.GlobalKey -import com.rosetta.model.lib.GlobalKey.GlobalKeyBuilder import com.rosetta.model.lib.RosettaModelObject -import com.rosetta.model.lib.Templatable -import com.rosetta.model.lib.Templatable.TemplatableBuilder import com.rosetta.model.lib.path.RosettaPath import com.rosetta.model.lib.process.AttributeMeta import com.rosetta.model.lib.process.BuilderProcessor import com.rosetta.model.lib.process.Processor import com.rosetta.util.ListEquals -import java.util.List import java.util.Objects import javax.inject.Inject import org.eclipse.xtend2.lib.StringConcatenationClient +import com.regnosys.rosetta.generator.java.types.JavaPojoInterface +import com.regnosys.rosetta.generator.java.types.JavaTypeUtil +import com.regnosys.rosetta.generator.java.types.JavaPojoProperty +import java.util.Collection +import com.rosetta.util.types.JavaClass +import com.regnosys.rosetta.generator.java.types.RJavaEnum class ModelObjectBoilerPlate { - @Inject extension RosettaEcoreUtil @Inject extension ModelObjectBuilderGenerator @Inject extension JavaTypeTranslator - @Inject extension TypeSystem + @Inject extension JavaTypeUtil - val toBuilder = [String s|s + 'Builder'] - val identity = [String s|s] + val toBuilder = [JavaClass t|t.simpleName + "Builder"] + val identity = [JavaClass t|t.simpleName] - def StringConcatenationClient builderBoilerPlate(RDataType c, JavaScope scope) { - val attrs = c.javaAttributes + def StringConcatenationClient builderBoilerPlate(JavaPojoInterface javaType, boolean extended, JavaScope scope) { + val properties = extended ? javaType.ownProperties : javaType.allProperties ''' - «c.contributeEquals(attrs, scope)» - «c.contributeHashCode(attrs, scope)» - «c.contributeToString(toBuilder, scope)» + «javaType.contributeEquals(extended, properties, scope)» + «javaType.contributeHashCode(extended, properties, scope)» + «javaType.contributeToString(extended, properties, toBuilder, scope)» ''' } - def StringConcatenationClient implementsClause(RDataType d, List extraInterfaces) { - val interfaces = newLinkedHashSet - if(d.EObject.hasKeyedAnnotation) - interfaces.add(GlobalKey) - if(d.EObject.hasTemplateAnnotation) - interfaces.add(Templatable) - interfaces.addAll(extraInterfaces) - if (interfaces.empty) null else ''', «FOR i : interfaces.sortBy[class.name] SEPARATOR ', '»«i»«ENDFOR»''' + def String javaAnnotation(JavaPojoProperty prop) { + if (prop.type == REFERENCE) { + return 'address' + } else + return prop.name } - def StringConcatenationClient implementsClauseBuilder(Data d) { - val interfaces = newArrayList - if (d.hasKeyedAnnotation) - interfaces.add('''«GlobalKeyBuilder»''') - if(d.hasTemplateAnnotation) - interfaces.add('''«TemplatableBuilder»''') - if(interfaces.empty) null else ''', «FOR i : interfaces SEPARATOR ', '»«i»«ENDFOR»''' + def StringConcatenationClient implementsClause(JavaPojoInterface javaType) { + '''«FOR i : javaType.interfaces SEPARATOR ', '»«i»«ENDFOR»''' } - def StringConcatenationClient boilerPlate(RDataType t, JavaScope scope) { - val attributes = t.javaAttributes + def StringConcatenationClient boilerPlate(JavaPojoInterface javaType, boolean extended, JavaScope scope) { + val properties = extended ? javaType.ownProperties : javaType.allProperties ''' - «t.contributeEquals(attributes, scope)» - «t.contributeHashCode(attributes, scope)» - «t.contributeToString(identity, scope)» + «javaType.contributeEquals(extended, properties, scope)» + «javaType.contributeHashCode(extended, properties, scope)» + «javaType.contributeToString(extended, properties, identity, scope)» ''' } - private def StringConcatenationClient contributeHashCode(RAttribute attr, JavaScope scope) { - val id = scope.getIdentifierOrThrow(attr) - val rMetaAnnotatedType = attr.RMetaAnnotatedType + private def StringConcatenationClient contributeHashCode(JavaPojoProperty prop, JavaScope scope) { + val id = scope.getIdentifierOrThrow(prop) + val itemType = prop.type.itemType ''' - «IF !rMetaAnnotatedType.hasMeta && rMetaAnnotatedType.RType instanceof REnumType» - «IF attr.isMulti» + «IF itemType instanceof RJavaEnum» + «IF prop.type.isList» _result = 31 * _result + («id» != null ? «id».stream().map(«Object»::getClass).map(«Class»::getName).mapToInt(«String»::hashCode).sum() : 0); «ELSE» _result = 31 * _result + («id» != null ? «id».getClass().getName().hashCode() : 0); @@ -86,14 +72,14 @@ class ModelObjectBoilerPlate { ''' } - private def StringConcatenationClient contributeHashCode(RDataType c, Iterable attributes, JavaScope scope) { + private def StringConcatenationClient contributeHashCode(JavaPojoInterface javaType, boolean extended, Collection properties, JavaScope scope) { val methodScope = scope.methodScope("hashCode") ''' @Override public int hashCode() { - int _result = «c.contribtueSuperHashCode»; - «FOR field : attributes» - «field.contributeHashCode(methodScope)» + int _result = «IF extended»super.hashCode()«ELSE»0«ENDIF»; + «FOR prop : properties» + «prop.contributeHashCode(methodScope)» «ENDFOR» return _result; } @@ -101,35 +87,33 @@ class ModelObjectBoilerPlate { ''' } - private def StringConcatenationClient contributeToString(RDataType t, (String)=>String classNameFunc, JavaScope scope) { + private def StringConcatenationClient contributeToString(JavaPojoInterface javaType, boolean extended, Collection properties, (JavaClass)=>String classNameFunc, JavaScope scope) { val methodScope = scope.methodScope("toString") ''' @Override public «String» toString() { - return "«classNameFunc.apply(t.name)» {" + - «FOR attribute : t.javaAttributes SEPARATOR ' ", " +'» - "«attribute.name»=" + this.«methodScope.getIdentifierOrThrow(attribute)» + + return "«classNameFunc.apply(javaType)» {" + + «FOR prop : properties SEPARATOR ' ", " +'» + "«prop.name»=" + this.«methodScope.getIdentifierOrThrow(prop)» + «ENDFOR» - '}'«IF t.hasSuperDataType» + " " + super.toString()«ENDIF»; + '}'«IF extended» + " " + super.toString()«ENDIF»; } ''' } - private def StringConcatenationClient contributeEquals(RDataType c, Iterable attributes, JavaScope scope) { + private def StringConcatenationClient contributeEquals(JavaPojoInterface javaType, boolean extended, Collection properties, JavaScope scope) { val methodScope = scope.methodScope("equals") ''' @Override public boolean equals(«Object» o) { if (this == o) return true; if (o == null || !(o instanceof «RosettaModelObject») || !getType().equals(((«RosettaModelObject»)o).getType())) return false; - «IF c.hasSuperDataType» - if (!super.equals(o)) return false; - «ENDIF» + «IF extended»if (!super.equals(o)) return false;«ENDIF» - «IF !attributes.empty»«c.name.toFirstUpper» _that = getType().cast(o);«ENDIF» + «IF !properties.empty»«javaType» _that = getType().cast(o);«ENDIF» - «FOR field : attributes» - «field.contributeToEquals(methodScope)» + «FOR prop : properties» + «prop.contributeToEquals(methodScope)» «ENDFOR» return true; } @@ -137,57 +121,45 @@ class ModelObjectBoilerPlate { ''' } - private def StringConcatenationClient contributeToEquals(RAttribute a, JavaScope scope) ''' - «IF a.isMulti» - if (!«ListEquals».listEquals(«scope.getIdentifierOrThrow(a)», _that.get«a.name.toFirstUpper»())) return false; + private def StringConcatenationClient contributeToEquals(JavaPojoProperty prop, JavaScope scope) ''' + «IF prop.type.isList» + if (!«ListEquals».listEquals(«scope.getIdentifierOrThrow(prop)», _that.«prop.getterName»())) return false; «ELSE» - if (!«Objects».equals(«scope.getIdentifierOrThrow(a)», _that.get«a.name.toFirstUpper»())) return false; + if (!«Objects».equals(«scope.getIdentifierOrThrow(prop)», _that.«prop.getterName»())) return false; «ENDIF» ''' - - private def contribtueSuperHashCode(RDataType c) { - if(c.hasSuperDataType) 'super.hashCode()' else '0' - } - def StringConcatenationClient processMethod(RDataType c) ''' + def StringConcatenationClient processMethod(JavaPojoInterface javaType) ''' @Override default void process(«RosettaPath» path, «Processor» processor) { - «FOR a : c.allJavaAttributes» - «IF a.isRosettaModelObject» - processRosetta(path.newSubPath("«a.name»"), processor, «a.toMetaItemJavaType».class, get«a.name.toFirstUpper»()«a.metaFlags»); + «FOR prop : javaType.allProperties» + «IF prop.type.isRosettaModelObject» + processRosetta(path.newSubPath("«prop.name»"), processor, «prop.type.itemType».class, «prop.getterName»()«prop.metaFlags»); «ELSE» - processor.processBasic(path.newSubPath("«a.name»"), «a.toMetaItemJavaType».class, get«a.name.toFirstUpper»(), this«a.metaFlags»); + processor.processBasic(path.newSubPath("«prop.name»"), «prop.type.itemType».class, «prop.getterName»(), this«prop.metaFlags»); «ENDIF» «ENDFOR» } ''' - def StringConcatenationClient builderProcessMethod(RDataType t) ''' + def StringConcatenationClient builderProcessMethod(JavaPojoInterface javaType) ''' @Override default void process(«RosettaPath» path, «BuilderProcessor» processor) { - «FOR a : t.allJavaAttributes» - «IF a.isRosettaModelObject» - processRosetta(path.newSubPath("«a.name»"), processor, «a.toBuilderTypeSingle».class, get«a.name.toFirstUpper»()«a.metaFlags»); + «FOR prop : javaType.allProperties» + «IF prop.type.isRosettaModelObject» + processRosetta(path.newSubPath("«prop.name»"), processor, «prop.toBuilderTypeSingle».class, «prop.getterName»()«prop.metaFlags»); «ELSE» - processor.processBasic(path.newSubPath("«a.name»"), «a.toMetaItemJavaType».class, get«a.name.toFirstUpper»(), this«a.metaFlags»); + processor.processBasic(path.newSubPath("«prop.name»"), «prop.type.itemType».class, «prop.getterName»(), this«prop.metaFlags»); «ENDIF» «ENDFOR» } ''' - private def StringConcatenationClient getMetaFlags(RAttribute attribute) { - if (attribute.isMeta) { - ''', «AttributeMeta».META''' - } - else if (attribute.hasIdAnnotation) { - ''', «AttributeMeta».GLOBAL_KEY_FIELD''' + private def StringConcatenationClient getMetaFlags(JavaPojoProperty prop) { + if (prop.meta !== null) { + ''', «AttributeMeta».«prop.meta»''' } } - - private def boolean hasSuperDataType(RDataType c) { - val s = c.superType - return s !== null && s.stripFromTypeAliases instanceof RDataType - } } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ModelObjectBuilderGenerator.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ModelObjectBuilderGenerator.xtend index a26abf5e0..422b4fcb8 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ModelObjectBuilderGenerator.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ModelObjectBuilderGenerator.xtend @@ -9,45 +9,52 @@ import org.eclipse.xtend2.lib.StringConcatenationClient import com.regnosys.rosetta.generator.java.JavaScope import com.regnosys.rosetta.generator.java.types.JavaTypeTranslator -import com.regnosys.rosetta.types.RDataType import javax.inject.Inject import com.rosetta.model.lib.annotations.RosettaAttribute import com.rosetta.model.lib.RosettaModelObjectBuilder import com.regnosys.rosetta.generator.java.types.JavaTypeUtil -import com.regnosys.rosetta.types.RAttribute -import com.regnosys.rosetta.RosettaEcoreUtil +import com.regnosys.rosetta.generator.java.types.JavaPojoProperty +import com.rosetta.util.types.JavaType +import com.rosetta.util.types.JavaClass +import com.regnosys.rosetta.generator.java.types.JavaPojoInterface +import com.regnosys.rosetta.generator.java.statement.builder.JavaExpression +import com.regnosys.rosetta.generator.java.expression.TypeCoercionService +import com.regnosys.rosetta.generator.java.statement.builder.JavaVariable +import com.regnosys.rosetta.generator.java.types.RJavaWithMetaValue +import com.regnosys.rosetta.generator.java.statement.JavaIfThenStatement +import com.rosetta.util.types.JavaPrimitiveType +import com.regnosys.rosetta.generator.java.statement.builder.JavaThis +import com.regnosys.rosetta.generator.java.statement.JavaEnhancedForLoop +import com.regnosys.rosetta.generator.java.statement.builder.JavaIfThenElseBuilder +import java.util.Collections +import com.regnosys.rosetta.generator.java.statement.builder.JavaConditionalExpression class ModelObjectBuilderGenerator { @Inject extension ModelObjectBoilerPlate - @Inject extension RosettaEcoreUtil @Inject extension JavaTypeTranslator - @Inject extension JavaTypeUtil + @Inject extension JavaTypeUtil typeUtil + @Inject extension TypeCoercionService - def StringConcatenationClient builderClass(RDataType t, JavaScope scope) { - val javaType = t.toJavaType + def StringConcatenationClient builderClass(JavaPojoInterface javaType, JavaScope scope) { val superInterface = javaType.interfaces.head + val extendSuperImpl = superInterface instanceof JavaPojoInterface && javaType.ownProperties.forall[parentProperty === null || parentProperty.type == type] val builderScope = scope.classScope('''«javaType»BuilderImpl''') - val attrs = t.javaAttributes - val allAttrs = t.allJavaAttributes - allAttrs.forEach[ + val properties = extendSuperImpl ? javaType.ownProperties : javaType.allProperties + javaType.allProperties.forEach[ builderScope.createIdentifier(it, it.name.toFirstLower) ] ''' - class «javaType»BuilderImpl«IF superInterface != ROSETTA_MODEL_OBJECT» extends «superInterface.toBuilderImplType» «ENDIF» implements «javaType.toBuilderType»«implementsClauseBuilder(t.EObject)» { + class «javaType»BuilderImpl«IF extendSuperImpl» extends «superInterface.toBuilderImplType»«ENDIF» implements «javaType.toBuilderType» { - «FOR attribute : attrs» - protected «attribute.toBuilderType» «builderScope.getIdentifierOrThrow(attribute)»«IF attribute.isMulti» = new «ArrayList»<>()«ENDIF»; + «FOR prop : properties» + protected «prop.toBuilderType» «builderScope.getIdentifierOrThrow(prop)»«IF prop.type.isList» = new «ArrayList»<>()«ENDIF»; «ENDFOR» - - public «javaType»BuilderImpl() { - } - - «attrs.builderGetters(builderScope)» - «t.setters(builderScope)» + «properties.builderGetters(extendSuperImpl, builderScope)» + «javaType.setters(builderScope)» @Override - public «t.name» build() { + public «javaType» build() { return new «javaType.toImplType»(this); } @@ -59,259 +66,491 @@ class ModelObjectBuilderGenerator { @SuppressWarnings("unchecked") @Override public «javaType.toBuilderType» prune() { - «IF superInterface != ROSETTA_MODEL_OBJECT»super.prune();«ENDIF» - «FOR attribute : attrs» - «IF !attribute.isMulti && attribute.isRosettaModelObject» - if («builderScope.getIdentifierOrThrow(attribute)»!=null && !«builderScope.getIdentifierOrThrow(attribute)».prune().hasData()) «builderScope.getIdentifierOrThrow(attribute)» = null; - «ELSEIF attribute.isMulti && attribute.isRosettaModelObject» - «builderScope.getIdentifierOrThrow(attribute)» = «builderScope.getIdentifierOrThrow(attribute)».stream().filter(b->b!=null).<«attribute.toBuilderTypeSingle»>map(b->b.prune()).filter(b->b.hasData()).collect(«Collectors».toList()); + «IF extendSuperImpl»super.prune();«ENDIF» + «FOR prop : properties» + «IF !prop.type.isList && prop.type.isRosettaModelObject» + if («builderScope.getIdentifierOrThrow(prop)»!=null && !«builderScope.getIdentifierOrThrow(prop)».prune().hasData()) «builderScope.getIdentifierOrThrow(prop)» = null; + «ELSEIF prop.type.isList && prop.type.isRosettaModelObject» + «builderScope.getIdentifierOrThrow(prop)» = «builderScope.getIdentifierOrThrow(prop)».stream().filter(b->b!=null).<«prop.toBuilderTypeSingle»>map(b->b.prune()).filter(b->b.hasData()).collect(«Collectors».toList()); «ENDIF» «ENDFOR» return this; } - «attrs.hasData(superInterface != ROSETTA_MODEL_OBJECT)» + «properties.hasData(extendSuperImpl)» - «attrs.merge(t, superInterface != ROSETTA_MODEL_OBJECT)» + «properties.merge(javaType, extendSuperImpl)» - «t.builderBoilerPlate(builderScope)» + «javaType.builderBoilerPlate(extendSuperImpl, builderScope)» } ''' } - private def StringConcatenationClient merge(Iterable attributes, RDataType type, boolean hasSuperType) { - val builderName = type.toJavaType.toBuilderType - ''' - @SuppressWarnings("unchecked") - @Override - public «builderName» merge(«RosettaModelObjectBuilder» other, «BuilderMerger» merger) { - «IF hasSuperType» - super.merge(other, merger); - - «ENDIF» - «builderName» o = («builderName») other; - - «FOR a : attributes.filter[isRosettaModelObject]» - «val attributeName = a.name.toFirstUpper» - «IF a.isMulti» - merger.mergeRosetta(get«attributeName»(), o.get«attributeName»(), this::getOrCreate«attributeName»); - «ELSE» - merger.mergeRosetta(get«attributeName»(), o.get«attributeName»(), this::set«attributeName»); - «ENDIF» - «ENDFOR» - - «FOR a : attributes.filter[!isRosettaModelObject]» - «val attributeName = a.name.toFirstUpper» - «IF a.isMulti» - merger.mergeBasic(get«attributeName»(), o.get«attributeName»(), («Consumer»<«a.toItemJavaType»>) this::add«attributeName»); - «ELSE» - merger.mergeBasic(get«attributeName»(), o.get«attributeName»(), this::set«attributeName»); + private def StringConcatenationClient merge(Iterable properties, JavaPojoInterface javaType, boolean extended) { + val builderType = javaType.toBuilderType + ''' + @SuppressWarnings("unchecked") + @Override + public «builderType» merge(«RosettaModelObjectBuilder» other, «BuilderMerger» merger) { + «IF extended» + super.merge(other, merger); + «ENDIF» - «ENDFOR» - return this; - } - ''' + «builderType» o = («builderType») other; + + «FOR prop : properties.filter[type.isRosettaModelObject]» + «IF prop.type.isList» + merger.mergeRosetta(«prop.getterName»(), o.«prop.getterName»(), this::«prop.getOrCreateName»); + «ELSE» + merger.mergeRosetta(«prop.getterName»(), o.«prop.getterName»(), this::set«prop.name.toFirstUpper»); + «ENDIF» + «ENDFOR» + + «FOR prop : properties.filter[!type.isRosettaModelObject]» + «IF prop.type.isList» + merger.mergeBasic(«prop.getterName»(), o.«prop.getterName»(), («Consumer»<«prop.type.itemType»>) this::add«prop.name.toFirstUpper»); + «ELSE» + merger.mergeBasic(«prop.getterName»(), o.«prop.getterName»(), this::set«prop.name.toFirstUpper»); + «ENDIF» + «ENDFOR» + return this; + } + ''' } - private def StringConcatenationClient builderGetters(Iterable attributes, JavaScope scope) ''' - «FOR attribute : attributes» + private def StringConcatenationClient builderGetters(Iterable properties, boolean extended, JavaScope scope) ''' + «FOR prop : properties» + «val field = new JavaVariable(scope.getIdentifierOrThrow(prop), prop.type)» + @Override - @«RosettaAttribute»("«attribute.javaAnnotation»") - public «attribute.toBuilderTypeExt» get«attribute.name.toFirstUpper»() { - return «scope.getIdentifierOrThrow(attribute)»; - } - - «IF attribute.isRosettaModelObject» - «IF !attribute.isMulti» + @«RosettaAttribute»("«prop.javaAnnotation»") + public «prop.toBuilderTypeExt» «prop.getterName»() «field.completeAsReturn.toBlock» + «IF prop.type.isRosettaModelObject» + «IF !prop.type.isList» + @Override - public «attribute.toBuilderTypeSingle» getOrCreate«attribute.name.toFirstUpper»() { - «attribute.toBuilderTypeSingle» result; - if («scope.getIdentifierOrThrow(attribute)»!=null) { - result = «scope.getIdentifierOrThrow(attribute)»; + public «prop.toBuilderTypeSingle» «prop.getOrCreateName»() { + «prop.toBuilderTypeSingle» result; + if («field»!=null) { + result = «field»; } else { - result = «scope.getIdentifierOrThrow(attribute)» = «attribute.toMetaItemJavaType».builder(); - «IF !attribute.RMetaAnnotatedType.metaAttributes.filter[m|m.name=="location"].isEmpty» + result = «field» = «prop.type».builder(); + «IF prop.hasLocation» result.getOrCreateMeta().toBuilder().addKey(«Key».builder().setScope("DOCUMENT")); «ENDIF» } return result; } - «ELSE» + @Override - public «attribute.toBuilderTypeSingle» getOrCreate«attribute.name.toFirstUpper»(int _index) { + public «prop.toBuilderTypeSingle» «prop.getOrCreateName»(int _index) { - if («scope.getIdentifierOrThrow(attribute)»==null) { - this.«scope.getIdentifierOrThrow(attribute)» = new «ArrayList»<>(); + if («field»==null) { + this.«field» = new «ArrayList»<>(); } - «attribute.toBuilderTypeSingle» result; - return getIndex(«scope.getIdentifierOrThrow(attribute)», _index, () -> { - «attribute.toBuilderTypeSingle» new«attribute.name.toFirstUpper» = «attribute.toMetaItemJavaType».builder(); - «IF !attribute.RMetaAnnotatedType.metaAttributes.filter[m|m.name=="location"].isEmpty» - new«attribute.name.toFirstUpper».getOrCreateMeta().addKey(«Key».builder().setScope("DOCUMENT")); + «prop.toBuilderTypeSingle» result; + return getIndex(«field», _index, () -> { + «prop.toBuilderTypeSingle» new«prop.name.toFirstUpper» = «prop.type.itemType».builder(); + «IF prop.hasLocation» + new«prop.name.toFirstUpper».getOrCreateMeta().addKey(«Key».builder().setScope("DOCUMENT")); «ENDIF» - return new«attribute.name.toFirstUpper»; + return new«prop.name.toFirstUpper»; }); } - «ENDIF» «ENDIF» + «IF !extended»«derivedIncompatibleGettersForProperty(field, prop, prop, scope)»«ENDIF» «ENDFOR» ''' + private def StringConcatenationClient derivedIncompatibleGettersForProperty(JavaExpression originalField, JavaPojoProperty originalProp, JavaPojoProperty prop, JavaScope scope) { + val parent = prop.parentProperty + if (parent === null) { + return null + } else if (parent.getterName == prop.getterName) { + return derivedIncompatibleGettersForProperty(originalField, originalProp, parent, scope) + } + val getterScope = scope.methodScope(parent.getterName) + ''' + + @Override + public «parent.toBuilderTypeExt» «parent.getterName»() « + (if (parent.type.isList) { + if (originalProp.type.isList) { + originalField + .addCoercions(parent.type, getterScope) + .collapseToSingleExpression(scope) + .mapExpression[ + val lambdaParam = new JavaVariable(getterScope.lambdaScope.createUniqueIdentifier(parent.type.itemType.simpleName.toFirstLower), parent.type.itemType) + JavaExpression.from( + '''«it».stream().map(«lambdaParam» -> «lambdaParam.toBuilder.toLambdaBody»).collect(«Collectors».toList())''', + parent.toBuilderTypeExt + ) + ] + } else { + originalField + .addCoercions(parent.type.itemType, getterScope) + .mapExpression[ + if (it == JavaExpression.NULL) { + JavaExpression.from('''«Collections».<«parent.toBuilderTypeSingle»>emptyList()''', parent.toBuilderTypeExt) + } else { + toBuilder.mapExpression[JavaExpression.from('''«Collections».singletonList(«it»)''', parent.toBuilderTypeExt)] + } + ] + } + } else { + originalField + .addCoercions(parent.type, getterScope) + .mapExpressionIfNotNull[toBuilder] + }).completeAsReturn.toBlock» + «IF parent.type.isRosettaModelObject» + «IF !parent.type.isList» + + @Override + public «parent.toBuilderTypeSingle» «parent.getOrCreateName»() « + JavaExpression.from('''«originalProp.getOrCreateName»()''', originalProp.type.itemType) + .addCoercions(parent.type.itemType, scope) + .mapExpressionIfNotNull[toBuilder] + .completeAsReturn + .toBlock» + «ELSE» + + @Override + public «parent.toBuilderTypeSingle» «parent.getOrCreateName»(int _index) « + JavaExpression.from('''«originalProp.getOrCreateName»(«IF originalProp.type.isList»_index«ENDIF»)''', originalProp.type.itemType) + .addCoercions(parent.type.itemType, scope) + .mapExpressionIfNotNull[toBuilder] + .completeAsReturn + .toBlock» + «ENDIF» + «ENDIF» + «derivedIncompatibleGettersForProperty(originalField, originalProp, parent, scope)» + ''' + } + - private def StringConcatenationClient setters(RDataType t, JavaScope scope) + private def StringConcatenationClient setters(JavaPojoInterface javaType, JavaScope scope) ''' - «FOR attribute : t.allJavaAttributes» - «doSetter(t, attribute, scope)» + «FOR prop : javaType.allProperties» + + «doSetter(javaType, prop, prop, scope)» «ENDFOR» - ''' + ''' - private def StringConcatenationClient doSetter(RDataType t, RAttribute attribute, JavaScope scope) { - val thisName = t.toJavaType.toBuilderType + private def StringConcatenationClient doSetter(JavaPojoInterface javaType, JavaPojoProperty mainProp, JavaPojoProperty currentProp, JavaScope scope) { + val builderType = javaType.toBuilderType + val mainPropType = mainProp.type + val propType = currentProp.type + val addMethodName = "add" + currentProp.name.toFirstUpper + val addValueMethodName = addMethodName + "Value" + val setMethodName = "set" + currentProp.name.toFirstUpper + val setValueMethodName = "set" + currentProp.name.toFirstUpper + "Value" + val isMainProp = mainProp == currentProp + val field = scope.getIdentifierOrThrow(mainProp) + val thisExpr = new JavaThis(builderType) ''' - «IF attribute.isMulti» + «IF propType.isList» + «val itemType = propType.itemType» + «val mainItemType = mainPropType.itemType» + «val addMethodScope = scope.methodScope(addMethodName)» + «val addMethodArg = new JavaVariable(addMethodScope.createUniqueIdentifier(currentProp.name.toFirstLower), itemType)» @Override - @«RosettaAttribute»("«attribute.javaAnnotation»") - public «thisName» add«attribute.name.toFirstUpper»(«attribute.toMetaItemJavaType» «scope.getIdentifierOrThrow(attribute)») { - if («scope.getIdentifierOrThrow(attribute)»!=null) this.«scope.getIdentifierOrThrow(attribute)».add(«attribute.toBuilder(scope)»); - return this; - } + «IF isMainProp»@«RosettaAttribute»("«currentProp.javaAnnotation»")«ENDIF» + public «builderType» «addMethodName»(«itemType» «addMethodArg») « + (if (isMainProp) { + new JavaIfThenStatement( + JavaExpression.from('''«addMethodArg» != null''', JavaPrimitiveType.BOOLEAN), + JavaExpression.from('''this.«field».add(«addMethodArg.toBuilder»)''', JavaPrimitiveType.VOID) + .completeAsExpressionStatement + ).append(thisExpr) + } else { + addMethodArg + .addCoercions(mainItemType, false, addMethodScope) + .collapseToSingleExpression(addMethodScope) + .mapExpression[ + if (mainPropType.isList) { + JavaExpression.from('''«addMethodName»(«it»)''', builderType) + } else { + JavaExpression.from('''«setMethodName»(«it»)''', builderType) + } + ] + }).completeAsReturn.toBlock + » + «val indexedAddMethodScope = scope.methodScope(addMethodName)» + «val indexedAddMethodArg = new JavaVariable(indexedAddMethodScope.createUniqueIdentifier(currentProp.name.toFirstLower), itemType)» @Override - public «thisName» add«attribute.name.toFirstUpper»(«attribute.toMetaItemJavaType» «scope.getIdentifierOrThrow(attribute)», int _idx) { - getIndex(this.«scope.getIdentifierOrThrow(attribute)», _idx, () -> «attribute.toBuilder(scope)»); - return this; - } - «IF attribute.RMetaAnnotatedType.hasMeta» + public «builderType» «addMethodName»(«itemType» «indexedAddMethodArg», int _idx) « + (if (isMainProp) { + JavaExpression.from('''getIndex(this.«field», _idx, () -> «indexedAddMethodArg.toBuilder»)''', JavaPrimitiveType.VOID) + .completeAsExpressionStatement + .append(thisExpr) + } else { + indexedAddMethodArg + .addCoercions(mainItemType, false, addMethodScope) + .collapseToSingleExpression(indexedAddMethodScope) + .mapExpression[ + if (mainPropType.isList) { + JavaExpression.from('''«addMethodName»(«it», _idx)''', builderType) + } else { + JavaExpression.from('''«setMethodName»(«it»)''', builderType) + } + ] + }).completeAsReturn.toBlock + » + «IF itemType instanceof RJavaWithMetaValue» + «val valueType = itemType.valueType» + «val mainValueType = mainItemType instanceof RJavaWithMetaValue ? mainItemType.valueType : mainItemType» + «val addValueMethodScope = scope.methodScope(addValueMethodName)» + «val addValueMethodArg = new JavaVariable(addValueMethodScope.createUniqueIdentifier(currentProp.name.toFirstLower), valueType)» @Override - public «thisName» add«attribute.name.toFirstUpper»Value(«attribute.toItemJavaType» «scope.getIdentifierOrThrow(attribute)») { - this.getOrCreate«attribute.name.toFirstUpper»(-1).setValue(«scope.getIdentifierOrThrow(attribute)»«IF attribute.isValueRosettaModelObject».toBuilder()«ENDIF»); - return this; - } + public «builderType» «addValueMethodName»(«valueType» «addValueMethodArg») « + (if (isMainProp) { + JavaExpression.from('''this.«currentProp.getOrCreateName»(-1).setValue(«addValueMethodArg.toBuilder»)''', JavaPrimitiveType.VOID) + .completeAsExpressionStatement + .append(thisExpr) + } else { + addValueMethodArg + .addCoercions(mainValueType, false, addValueMethodScope) + .collapseToSingleExpression(addValueMethodScope) + .mapExpression[ + if (mainPropType.isList) { + JavaExpression.from('''«IF mainItemType instanceof RJavaWithMetaValue»«addValueMethodName»«ELSE»«addMethodName»«ENDIF»(«it»)''', builderType) + } else { + JavaExpression.from('''«IF mainItemType instanceof RJavaWithMetaValue»«setValueMethodName»«ELSE»«setMethodName»«ENDIF»(«it»)''', builderType) + } + ] + }).completeAsReturn.toBlock + » + «val indexedAddValueMethodScope = scope.methodScope(addValueMethodName)» + «val indexedAddValueMethodArg = new JavaVariable(indexedAddValueMethodScope.createUniqueIdentifier(currentProp.name.toFirstLower), valueType)» @Override - public «thisName» add«attribute.name.toFirstUpper»Value(«attribute.toItemJavaType» «scope.getIdentifierOrThrow(attribute)», int _idx) { - this.getOrCreate«attribute.name.toFirstUpper»(_idx).setValue(«scope.getIdentifierOrThrow(attribute)»«IF attribute.isValueRosettaModelObject».toBuilder()«ENDIF»); - return this; - } + public «builderType» «addValueMethodName»(«valueType» «addValueMethodArg», int _idx) « + (if (isMainProp) { + JavaExpression.from('''this.«currentProp.getOrCreateName»(_idx).setValue(«indexedAddValueMethodArg.toBuilder»)''', JavaPrimitiveType.VOID) + .completeAsExpressionStatement + .append(thisExpr) + } else { + indexedAddValueMethodArg + .addCoercions(mainValueType, false, indexedAddValueMethodScope) + .collapseToSingleExpression(indexedAddValueMethodScope) + .mapExpression[ + if (mainPropType.isList) { + JavaExpression.from('''«IF mainItemType instanceof RJavaWithMetaValue»«addValueMethodName»«ELSE»«addMethodName»«ENDIF»(«it», _idx)''', builderType) + } else { + JavaExpression.from('''«IF mainItemType instanceof RJavaWithMetaValue»«setValueMethodName»«ELSE»«setMethodName»«ENDIF»(«it»)''', builderType) + } + ] + }).completeAsReturn.toBlock + » «ENDIF» + + «val addMultiMethodScope = scope.methodScope(addMethodName)» + «val addMultiMethodArg = new JavaVariable(addMultiMethodScope.createUniqueIdentifier(currentProp.name.toFirstLower + "s"), propType)» @Override - public «thisName» add«attribute.name.toFirstUpper»(«attribute.toMetaJavaType» «scope.getIdentifierOrThrow(attribute)»s) { - if («scope.getIdentifierOrThrow(attribute)»s != null) { - for («attribute.toMetaItemJavaType» toAdd : «scope.getIdentifierOrThrow(attribute)»s) { - this.«scope.getIdentifierOrThrow(attribute)».add(toAdd«IF attribute.isRosettaModelObject».toBuilder()«ENDIF»); - } - } - return this; - } + public «builderType» «addMethodName»(«propType» «addMultiMethodArg») « + (if (isMainProp) { + val forLoopId = addMultiMethodScope.createUniqueIdentifier("toAdd") + val forLoopVar = new JavaVariable(forLoopId, itemType) + new JavaIfThenStatement( + JavaExpression.from('''«addMultiMethodArg» != null''', JavaPrimitiveType.BOOLEAN), + new JavaEnhancedForLoop(true, itemType, forLoopId, addMultiMethodArg, + JavaExpression.from('''this.«field».add(«forLoopVar.toBuilder»)''', JavaPrimitiveType.VOID) + .completeAsExpressionStatement + ) + ).append(thisExpr) + } else { + addMultiMethodArg + .addCoercions(mainPropType, false, addMultiMethodScope) + .collapseToSingleExpression(addMultiMethodScope) + .mapExpression[ + if (mainPropType.isList) { + JavaExpression.from('''«addMethodName»(«it»)''', builderType) + } else { + JavaExpression.from('''«setMethodName»(«it»)''', builderType) + } + ] + }).completeAsReturn.toBlock + » + «val setMultiMethodScope = scope.methodScope(setMethodName)» + «val setMultiMethodArg = new JavaVariable(setMultiMethodScope.createUniqueIdentifier(currentProp.name.toFirstLower + "s"), propType)» @Override - public «thisName» set«attribute.name.toFirstUpper»(«attribute.toMetaJavaType» «scope.getIdentifierOrThrow(attribute)»s) { - if («scope.getIdentifierOrThrow(attribute)»s == null) { - this.«scope.getIdentifierOrThrow(attribute)» = new «ArrayList»<>(); - } - else { - this.«scope.getIdentifierOrThrow(attribute)» = «scope.getIdentifierOrThrow(attribute)»s.stream() - «IF attribute.isRosettaModelObject».map(_a->_a.toBuilder())«ENDIF» - .collect(«Collectors».toCollection(()->new ArrayList<>())); - } - return this; - } - «IF attribute.RMetaAnnotatedType.hasMeta» - - @Override - public «thisName» add«attribute.name.toFirstUpper»Value(«attribute.toJavaType» «scope.getIdentifierOrThrow(attribute)»s) { - if («scope.getIdentifierOrThrow(attribute)»s != null) { - for («attribute.toItemJavaType» toAdd : «scope.getIdentifierOrThrow(attribute)»s) { - this.add«attribute.name.toFirstUpper»Value(toAdd); - } - } - return this; - } - - @Override - public «thisName» set«attribute.name.toFirstUpper»Value(«attribute.toJavaType» «scope.getIdentifierOrThrow(attribute)»s) { - this.«scope.getIdentifierOrThrow(attribute)».clear(); - if («scope.getIdentifierOrThrow(attribute)»s!=null) { - «scope.getIdentifierOrThrow(attribute)»s.forEach(this::add«attribute.name.toFirstUpper»Value); - } - return this; - } - «ENDIF» + public «builderType» «setMethodName»(«propType» «setMultiMethodArg») « + (if (isMainProp) { + new JavaIfThenElseBuilder( + JavaExpression.from('''«setMultiMethodArg» == null''', JavaPrimitiveType.BOOLEAN), + JavaExpression.from('''this.«field» = new «ArrayList»<>()''', JavaPrimitiveType.VOID), + JavaExpression.from(''' + this.«field» = «setMultiMethodArg».stream() + «IF propType.isRosettaModelObject».map(_a->_a.toBuilder())«ENDIF» + .collect(«Collectors».toCollection(()->new ArrayList<>()))''', JavaPrimitiveType.VOID), + typeUtil + ).completeAsExpressionStatement + .append(thisExpr) + } else { + setMultiMethodArg + .addCoercions(mainPropType, false, setMultiMethodScope) + .collapseToSingleExpression(setMultiMethodScope) + .mapExpression[ + JavaExpression.from('''«setMethodName»(«it»)''', builderType) + ] + }).completeAsReturn.toBlock + » + «IF itemType instanceof RJavaWithMetaValue» + «val valueType = itemType.valueType» + «val mainValueType = mainItemType instanceof RJavaWithMetaValue ? mainItemType.valueType : mainItemType» + «val addMultiValueMethodScope = scope.methodScope(addValueMethodName)» + «val addMultiValueMethodArg = new JavaVariable(addMultiValueMethodScope.createUniqueIdentifier(currentProp.name.toFirstLower + "s"), LIST.wrapExtends(valueType))» + @Override + public «builderType» «addValueMethodName»(«addMultiValueMethodArg.expressionType» «addMultiValueMethodArg») « + (if (isMainProp) { + val forLoopId = addMultiValueMethodScope.createUniqueIdentifier("toAdd") + val forLoopVar = new JavaVariable(forLoopId, itemType) + new JavaIfThenStatement( + JavaExpression.from('''«addMultiValueMethodArg» != null''', JavaPrimitiveType.BOOLEAN), + new JavaEnhancedForLoop(true, valueType, forLoopId, addMultiValueMethodArg, + JavaExpression.from('''this.«addValueMethodName»(«forLoopVar»)''', JavaPrimitiveType.VOID) + .completeAsExpressionStatement + ) + ).append(thisExpr) + } else { + addMultiValueMethodArg + .addCoercions(mainPropType.isList ? LIST.wrapExtendsIfNotFinal(mainValueType) : mainValueType, false, addMultiValueMethodScope) + .collapseToSingleExpression(addMultiValueMethodScope) + .mapExpression[ + if (mainPropType.isList) { + JavaExpression.from('''«IF mainItemType instanceof RJavaWithMetaValue»«addValueMethodName»«ELSE»«addMethodName»«ENDIF»(«it»)''', builderType) + } else { + JavaExpression.from('''«IF mainItemType instanceof RJavaWithMetaValue»«setValueMethodName»«ELSE»«setMethodName»«ENDIF»(«it»)''', builderType) + } + ] + }).completeAsReturn.toBlock + » + + «val setMultiValueMethodScope = scope.methodScope(setValueMethodName)» + «val setMultiValueMethodArg = new JavaVariable(setMultiValueMethodScope.createUniqueIdentifier(currentProp.name.toFirstLower + "s"), LIST.wrapExtends(valueType))» + @Override + public «builderType» «setValueMethodName»(«setMultiValueMethodArg.expressionType» «setMultiValueMethodArg») « + (if (isMainProp) { + JavaExpression.from('''this.«field».clear()''', JavaPrimitiveType.VOID).completeAsExpressionStatement + .append(new JavaIfThenStatement( + JavaExpression.from('''«setMultiValueMethodArg» != null''', JavaPrimitiveType.BOOLEAN), + JavaExpression.from('''«setMultiValueMethodArg».forEach(this::«addValueMethodName»)''', JavaPrimitiveType.VOID) + .completeAsExpressionStatement + )).append(thisExpr) + } else { + setMultiValueMethodArg + .addCoercions(mainPropType.isList ? LIST.wrapExtendsIfNotFinal(mainValueType) : mainValueType, false, setMultiValueMethodScope) + .collapseToSingleExpression(setMultiValueMethodScope) + .mapExpression[ + JavaExpression.from('''«IF mainItemType instanceof RJavaWithMetaValue»«setValueMethodName»«ELSE»«setMethodName»«ENDIF»(«it»)''', builderType) + ] + }).completeAsReturn.toBlock + » + «ENDIF» «ELSE» + «val setMethodScope = scope.methodScope(setMethodName)» + «val setMethodArg = new JavaVariable(setMethodScope.createUniqueIdentifier(currentProp.name.toFirstLower), propType)» @Override - @«RosettaAttribute»("«attribute.javaAnnotation»") - public «thisName» set«attribute.name.toFirstUpper»(«attribute.toMetaJavaType» «scope.getIdentifierOrThrow(attribute)») { - this.«scope.getIdentifierOrThrow(attribute)» = «scope.getIdentifierOrThrow(attribute)»==null?null:«attribute.toBuilder(scope)»; - return this; - } - «IF attribute.RMetaAnnotatedType.hasMeta» - @Override - public «thisName» set«attribute.name.toFirstUpper»Value(«attribute.toJavaType» «scope.getIdentifierOrThrow(attribute)») { - this.getOrCreate«attribute.name.toFirstUpper»().setValue(«scope.getIdentifierOrThrow(attribute)»); - return this; - } + «IF isMainProp»@«RosettaAttribute»("«currentProp.javaAnnotation»")«ENDIF» + public «builderType» «setMethodName»(«propType» «setMethodArg») « + (if (isMainProp) { + JavaExpression.from('''this.«field» = «setMethodArg» == null ? null : «setMethodArg.toBuilder»''', JavaPrimitiveType.VOID) + .completeAsExpressionStatement + .append(thisExpr) + } else { + setMethodArg + .addCoercions(mainPropType, false, setMethodScope) + .collapseToSingleExpression(setMethodScope) + .mapExpression[ + JavaExpression.from('''«setMethodName»(«it»)''', builderType) + ] + }).completeAsReturn.toBlock + » + «IF propType instanceof RJavaWithMetaValue» + «val valueType = propType.valueType» + «val mainValueType = mainPropType instanceof RJavaWithMetaValue ? mainPropType.valueType : mainPropType» + + «val setValueMethodScope = scope.methodScope(setValueMethodName)» + «val setValueMethodArg = new JavaVariable(setValueMethodScope.createUniqueIdentifier(currentProp.name.toFirstLower), valueType)» + @Override + public «builderType» «setValueMethodName»(«valueType» «setValueMethodArg») « + (if (isMainProp) { + JavaExpression.from('''this.«currentProp.getOrCreateName»().setValue(«setValueMethodArg»)''', JavaPrimitiveType.VOID) + .completeAsExpressionStatement + .append(thisExpr) + } else { + setValueMethodArg + .addCoercions(mainValueType, false, setValueMethodScope) + .collapseToSingleExpression(setValueMethodScope) + .mapExpression[ + JavaExpression.from('''«IF mainPropType instanceof RJavaWithMetaValue»«setValueMethodName»«ELSE»«setMethodName»«ENDIF»(«it»)''', builderType) + ] + }).completeAsReturn.toBlock + » «ENDIF» «ENDIF» + «IF currentProp.parentProperty !== null» + + «doSetter(javaType, mainProp, currentProp.parentProperty, scope)» + «ENDIF» ''' } - - private def hasData(Iterable attributes, boolean hasSuperType) ''' + private def hasData(Iterable properties, boolean extended) ''' @Override public boolean hasData() { - «IF hasSuperType»if (super.hasData()) return true;«ENDIF» - «FOR attribute:attributes.filter[name!="meta"]» - «IF attribute.isMulti» - «IF attribute.isValueRosettaModelObject» - if (get«attribute.name.toFirstUpper»()!=null && get«attribute.name.toFirstUpper»().stream().filter(Objects::nonNull).anyMatch(a->a.hasData())) return true; + «IF extended»if (super.hasData()) return true;«ENDIF» + «FOR prop : properties.filter[name!="meta"]» + «IF prop.type.isList» + «IF prop.type.isValueRosettaModelObject» + if («prop.getterName»()!=null && «prop.getterName»().stream().filter(Objects::nonNull).anyMatch(a->a.hasData())) return true; «ELSE» - if (get«attribute.name.toFirstUpper»()!=null && !get«attribute.name.toFirstUpper»().isEmpty()) return true; + if («prop.getterName»()!=null && !«prop.getterName»().isEmpty()) return true; «ENDIF» - «ELSEIF attribute.isValueRosettaModelObject» - if (get«attribute.name.toFirstUpper»()!=null && get«attribute.name.toFirstUpper»().hasData()) return true; + «ELSEIF prop.type.isValueRosettaModelObject» + if («prop.getterName»()!=null && «prop.getterName»().hasData()) return true; «ELSE» - if (get«attribute.name.toFirstUpper»()!=null) return true; + if («prop.getterName»()!=null) return true; «ENDIF» «ENDFOR» return false; } ''' - private def StringConcatenationClient toBuilderType(RAttribute attribute) { - if (attribute.isMulti) '''List<«attribute.toBuilderTypeSingle»>''' - else '''«attribute.toBuilderTypeSingle»''' + private def JavaType toBuilderType(JavaPojoProperty prop) { + if (prop.type.isList) LIST.wrap(prop.toBuilderTypeSingle) + else prop.toBuilderTypeSingle } - private def StringConcatenationClient toBuilderTypeExt(RAttribute attribute) { - if (attribute.isMulti) '''List<«IF attribute.isRosettaModelObject»? extends «ENDIF»«attribute.toBuilderTypeSingle»>''' - else '''«attribute.toBuilderTypeSingle»''' + private def JavaType toBuilderTypeExt(JavaPojoProperty prop) { + if (prop.type.isList) (prop.type.isRosettaModelObject ? LIST.wrapExtends(prop.toBuilderTypeSingle) : LIST.wrap(prop.toBuilderTypeSingle)) + else prop.toBuilderTypeSingle } - def StringConcatenationClient toBuilderTypeSingle(RAttribute attribute) { - if (attribute.RMetaAnnotatedType.hasMeta) { - '''«attribute.toMetaItemJavaType.toBuilderType»''' + def JavaType toBuilderTypeSingle(JavaPojoProperty prop) { + val itemType = prop.type.itemType + if (prop.type.isRosettaModelObject) { + (itemType as JavaClass).toBuilderType } else { - '''«attribute.toBuilderTypeUnderlying»''' + itemType } } - private def StringConcatenationClient toBuilderTypeUnderlying(RAttribute attribute) { - if (attribute.isRosettaModelObject) '''«attribute.RMetaAnnotatedType.RType.name».«attribute.RMetaAnnotatedType.RType.name»Builder''' - else '''«attribute.toMetaItemJavaType»''' - } - - private def StringConcatenationClient toBuilder(RAttribute attribute, JavaScope scope) { - if(attribute.isRosettaModelObject) { - '''«scope.getIdentifierOrThrow(attribute)».toBuilder()''' + private def JavaExpression toBuilder(JavaExpression expr) { + val t = expr.expressionType + if(t.isRosettaModelObject) { + JavaExpression.from('''«expr».toBuilder()''', (t as JavaClass).toBuilderType) } else { - '''«scope.getIdentifierOrThrow(attribute)»''' + expr } } } \ No newline at end of file diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ModelObjectGenerator.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ModelObjectGenerator.xtend index 644a51e01..7b6be8e90 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ModelObjectGenerator.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ModelObjectGenerator.xtend @@ -9,29 +9,24 @@ import com.regnosys.rosetta.generator.java.RosettaJavaPackages.RootPackage import com.regnosys.rosetta.generator.java.types.JavaTypeTranslator import com.regnosys.rosetta.generator.java.util.ImportManagerExtension import com.regnosys.rosetta.types.RDataType -import com.rosetta.model.lib.RosettaModelObject import com.rosetta.model.lib.annotations.RosettaAttribute import com.rosetta.model.lib.annotations.RosettaDataType import com.rosetta.model.lib.meta.RosettaMetaData -import com.rosetta.util.DottedPath import com.rosetta.util.types.JavaClass -import com.rosetta.util.types.JavaParameterizedType -import java.util.Collection -import java.util.Collections import java.util.List import java.util.Objects import java.util.Optional import org.eclipse.xtend2.lib.StringConcatenationClient import org.eclipse.xtext.generator.IFileSystemAccess2 -import static com.regnosys.rosetta.generator.java.util.ModelGeneratorUtil.* - import com.rosetta.util.types.generated.GeneratedJavaClass -import com.rosetta.util.types.generated.GeneratedJavaGenericTypeDeclaration -import org.eclipse.xtext.EcoreUtil2 -import com.regnosys.rosetta.rosetta.RosettaModel -import com.regnosys.rosetta.types.RAttribute -import com.regnosys.rosetta.RosettaEcoreUtil +import com.regnosys.rosetta.generator.java.types.JavaPojoInterface +import com.regnosys.rosetta.generator.java.types.JavaTypeUtil +import com.regnosys.rosetta.generator.java.types.RJavaWithMetaValue +import com.regnosys.rosetta.generator.java.types.JavaPojoProperty +import com.regnosys.rosetta.generator.java.statement.builder.JavaExpression +import com.regnosys.rosetta.generator.java.expression.TypeCoercionService +import com.regnosys.rosetta.generator.java.statement.builder.JavaVariable class ModelObjectGenerator { @@ -39,7 +34,8 @@ class ModelObjectGenerator { @Inject extension ModelObjectBuilderGenerator @Inject extension ImportManagerExtension @Inject extension JavaTypeTranslator - @Inject extension RosettaEcoreUtil + @Inject extension JavaTypeUtil + @Inject extension TypeCoercionService def generate(RootPackage root, IFileSystemAccess2 fsa, RDataType t, String version) { fsa.generateFile(root.child(t.name + '.java').withForwardSlashes, @@ -48,89 +44,120 @@ class ModelObjectGenerator { private def generateRosettaClass(RootPackage root, RDataType t, String version) { val scope = new JavaScope(root) - buildClass(root, t.classBody(scope, new GeneratedJavaClass(root.meta, t.name+'Meta', Object), version), scope) - } - - def StringConcatenationClient classBody(RDataType t, JavaScope scope, JavaClass metaType, String version) { - classBody(t, scope, metaType, version, Collections.emptyList) + val javaType = t.toJavaReferenceType + buildClass(root, javaType.classBody(scope, new GeneratedJavaClass(root.meta, t.name+'Meta', Object), version), scope) } - def StringConcatenationClient classBody(RDataType t, JavaScope scope, JavaClass metaType, String version, List interfaces) { - val javaType = t.toJavaType - val superInterface = javaType.interfaces.head + def StringConcatenationClient classBody(JavaPojoInterface javaType, JavaScope scope, JavaClass metaType, String version) { + val superInterface = javaType.superPojo + val extendSuperImpl = superInterface !== null && javaType.ownProperties.forall[isCompatibleWithParent] val interfaceScope = scope.classScope(javaType.toString) val metaDataIdentifier = interfaceScope.createUniqueIdentifier("metaData"); val builderScope = interfaceScope.classScope('''«javaType»Builder''') val implScope = interfaceScope.classScope('''«javaType»Impl''') ''' - «javadoc(t.EObject, version)» - @«RosettaDataType»(value="«t.name»", builder=«javaType.toBuilderImplType».class, version="«EcoreUtil2.getContainerOfType(t.EObject, RosettaModel).version»") - public interface «javaType» extends «superInterface»«implementsClause(t, interfaces)» { + «javaType.javadoc» + @«RosettaDataType»(value="«javaType.rosettaName»", builder=«javaType.toBuilderImplType».class, version="«javaType.version»") + public interface «javaType» extends «implementsClause(javaType)» { «metaType» «metaDataIdentifier» = new «metaType»(); «startComment('Getter Methods')» - «pojoInterfaceGetterMethods(javaType, t)» + «pojoInterfaceGetterMethods(javaType)» «startComment('Build Methods')» - «pojoInterfaceBuilderMethods(javaType, t)» + «pojoInterfaceBuilderMethods(javaType)» «startComment('Utility Methods')» - «pojoInterfaceDefaultOverridenMethods(javaType, metaDataIdentifier, interfaces, t)» + «pojoInterfaceDefaultOverridenMethods(javaType, metaDataIdentifier)» «startComment('Builder Interface')» - interface «javaType»Builder extends «t.name», «superInterface.toBuilderType»«FOR inter:interfaces BEFORE ', ' SEPARATOR ', '»«buildify(inter)»«ENDFOR» { - «pojoBuilderInterfaceGetterMethods(t, javaType, builderScope)» + interface «javaType»Builder extends «javaType»«FOR inter : javaType.interfaces BEFORE ', ' SEPARATOR ', '»«inter.toBuilderType»«ENDFOR» { + «javaType.pojoBuilderInterfaceGetterMethods(builderScope)» + «javaType.pojoBuilderInterfaceSetterMethods(javaType, builderScope)» - «t.builderProcessMethod» + «javaType.builderProcessMethod» «javaType.toBuilderType» prune(); } - «startComment('''Immutable Implementation of «t.name»''')» - class «javaType»Impl «IF superInterface != JavaClass.from(RosettaModelObject)»extends «superInterface.toImplType» «ENDIF»implements «t.name» { - «t.rosettaClass(implScope)» + «startComment('''Immutable Implementation of «javaType.simpleName»''')» + class «javaType»Impl «IF extendSuperImpl»extends «superInterface.toImplType» «ENDIF»implements «javaType» { + «javaType.rosettaClass(extendSuperImpl, implScope)» - «t.boilerPlate(implScope)» + «javaType.boilerPlate(extendSuperImpl, implScope)» } - «startComment('''Builder Implementation of «t.name»''')» - «t.builderClass(interfaceScope)» + «startComment('''Builder Implementation of «javaType.simpleName»''')» + «javaType.builderClass(interfaceScope)» } ''' } - protected def StringConcatenationClient pojoBuilderInterfaceGetterMethods(RDataType t, JavaClass javaType, JavaScope builderScope) ''' - «FOR attribute : t.javaAttributes» - «IF attribute.isRosettaModelObject» - «IF !attribute.isMulti» - «attribute.toBuilderTypeSingle» getOrCreate«attribute.name.toFirstUpper»(); - «attribute.toBuilderTypeSingle» get«attribute.name.toFirstUpper»(); + protected def StringConcatenationClient pojoBuilderInterfaceGetterMethods(JavaPojoInterface javaType, JavaScope builderScope) { + ''' + «FOR prop : javaType.ownProperties» + «IF prop.type.isRosettaModelObject» + «IF !prop.type.isList» + «prop.toBuilderTypeSingle» «prop.getOrCreateName»(); + @Override + «prop.toBuilderTypeSingle» «prop.getterName»(); «ELSE» - «attribute.toBuilderTypeSingle» getOrCreate«attribute.name.toFirstUpper»(int _index); - «List» get«attribute.name.toFirstUpper»(); + «prop.toBuilderTypeSingle» «prop.getOrCreateName»(int _index); + @Override + «List» «prop.getterName»(); «ENDIF» «ENDIF» «ENDFOR» - «FOR attribute : t.allJavaAttributes» - «IF !attribute.isMulti» - «javaType.toBuilderType» set«attribute.name.toFirstUpper»(«attribute.toMetaJavaType» «builderScope.createUniqueIdentifier(attribute.name)»); - «IF attribute.RMetaAnnotatedType.hasMeta»«javaType.toBuilderType» set«attribute.name.toFirstUpper»Value(«attribute.toJavaType» «builderScope.createUniqueIdentifier(attribute.name)»);«ENDIF» + ''' + } + protected def StringConcatenationClient pojoBuilderInterfaceSetterMethods(JavaPojoInterface mainType, JavaPojoInterface currentType, JavaScope builderScope) { + val isMainPojo = mainType == currentType + val builderType = mainType.toBuilderType + ''' + «IF currentType.superPojo !== null»«pojoBuilderInterfaceSetterMethods(mainType, currentType.superPojo, builderScope)»«ENDIF» + «FOR prop : currentType.ownProperties» + «val setMethodName = "set" + prop.name.toFirstUpper» + «val setValueMethodName = setMethodName + "Value"» + «val propType = prop.type» + «IF !propType.isList» + «IF !isMainPojo»@Override«ENDIF» + «builderType» «setMethodName»(«propType» «builderScope.methodScope(setMethodName).createUniqueIdentifier(prop.name)»); + «IF propType instanceof RJavaWithMetaValue» + «IF !isMainPojo»@Override«ENDIF» + «builderType» «setValueMethodName»(«propType.valueType» «builderScope.methodScope(setValueMethodName).createUniqueIdentifier(prop.name)»); + «ENDIF» «ELSE» - «javaType.toBuilderType» add«attribute.name.toFirstUpper»(«attribute.toMetaItemJavaType» «builderScope.createUniqueIdentifier(attribute.name)»); - «javaType.toBuilderType» add«attribute.name.toFirstUpper»(«attribute.toMetaItemJavaType» «builderScope.createUniqueIdentifier(attribute.name)», int _idx); - «IF attribute.RMetaAnnotatedType.hasMeta»«javaType.toBuilderType» add«attribute.name.toFirstUpper»Value(«attribute.toItemJavaType» «builderScope.createUniqueIdentifier(attribute.name)»); - «javaType.toBuilderType» add«attribute.name.toFirstUpper»Value(«attribute.toItemJavaType» «builderScope.createUniqueIdentifier(attribute.name)», int _idx);«ENDIF» - «javaType.toBuilderType» add«attribute.name.toFirstUpper»(«attribute.toMetaJavaType» «builderScope.createUniqueIdentifier(attribute.name)»); - «javaType.toBuilderType» set«attribute.name.toFirstUpper»(«attribute.toMetaJavaType» «builderScope.createUniqueIdentifier(attribute.name)»); - «IF attribute.RMetaAnnotatedType.hasMeta»«javaType.toBuilderType» add«attribute.name.toFirstUpper»Value(«attribute.toJavaType» «builderScope.createUniqueIdentifier(attribute.name)»); - «javaType.toBuilderType» set«attribute.name.toFirstUpper»Value(«attribute.toJavaType» «builderScope.createUniqueIdentifier(attribute.name)»);«ENDIF» + «val addMethodName = "add" + prop.name.toFirstUpper» + «val addValueMethodName = addMethodName + "Value"» + «val itemType = propType.itemType» + «IF !isMainPojo»@Override«ENDIF» + «builderType» «addMethodName»(«itemType» «builderScope.methodScope(addMethodName).createUniqueIdentifier(prop.name)»); + «IF !isMainPojo»@Override«ENDIF» + «builderType» «addMethodName»(«itemType» «builderScope.methodScope(addMethodName).createUniqueIdentifier(prop.name)», int _idx); + «IF itemType instanceof RJavaWithMetaValue» + «IF !isMainPojo»@Override«ENDIF» + «builderType» «addValueMethodName»(«itemType.valueType» «builderScope.methodScope(addValueMethodName).createUniqueIdentifier(prop.name)»); + «IF !isMainPojo»@Override«ENDIF» + «builderType» «addValueMethodName»(«itemType.valueType» «builderScope.methodScope(addValueMethodName).createUniqueIdentifier(prop.name)», int _idx); + «ENDIF» + «IF !isMainPojo»@Override«ENDIF» + «builderType» «addMethodName»(«propType» «builderScope.methodScope(addMethodName).createUniqueIdentifier(prop.name)»); + «IF !isMainPojo»@Override«ENDIF» + «builderType» «setMethodName»(«propType» «builderScope.methodScope(setMethodName).createUniqueIdentifier(prop.name)»); + «IF itemType instanceof RJavaWithMetaValue» + «IF !isMainPojo»@Override«ENDIF» + «builderType» «addValueMethodName»(«LIST.wrapExtends(itemType.valueType)» «builderScope.methodScope(addValueMethodName).createUniqueIdentifier(prop.name)»); + «IF !isMainPojo»@Override«ENDIF» + «builderType» «setValueMethodName»(«LIST.wrapExtends(itemType.valueType)» «builderScope.methodScope(setValueMethodName).createUniqueIdentifier(prop.name)»); + «ENDIF» «ENDIF» «ENDFOR» ''' + } - protected def StringConcatenationClient pojoInterfaceDefaultOverridenMethods(JavaClass javaType, GeneratedIdentifier metaDataIdentifier, Collection interfaces, RDataType t) + protected def StringConcatenationClient pojoInterfaceDefaultOverridenMethods(JavaPojoInterface javaType, GeneratedIdentifier metaDataIdentifier) ''' @Override default «RosettaMetaData» metaData() { @@ -141,27 +168,28 @@ class ModelObjectGenerator { default Class getType() { return «javaType».class; } - - «FOR pt :interfaces.filter(JavaParameterizedType).filter[simpleName=="ReferenceWithMeta" || simpleName=="FieldWithMeta"]» + «IF javaType instanceof RJavaWithMetaValue» + @Override - default Class<«pt.getArguments.head»> getValueType() { - return «pt.getArguments.head».class; + default Class<«javaType.valueType»> getValueType() { + return «javaType.valueType».class; } - «ENDFOR» + «ENDIF» - «t.processMethod» + «javaType.processMethod» ''' - protected def StringConcatenationClient pojoInterfaceGetterMethods(JavaClass javaType, RDataType t) ''' - «FOR attribute : t.javaAttributes» - «javadoc(attribute.definition, attribute.docReferences, null)» - «attribute.toMetaJavaType» get«attribute.name.toFirstUpper»(); + protected def StringConcatenationClient pojoInterfaceGetterMethods(JavaPojoInterface javaType) ''' + «FOR prop : javaType.ownProperties» + «prop.getJavadoc» + «IF prop.parentProperty !== null && prop.getterName == prop.parentProperty.getterName»@Override«ENDIF» + «prop.getType» «prop.getGetterName»(); «ENDFOR» ''' - protected def StringConcatenationClient pojoInterfaceBuilderMethods(JavaClass javaType, RDataType t) ''' - «t.name» build(); + protected def StringConcatenationClient pojoInterfaceBuilderMethods(JavaClass javaType) ''' + «javaType» build(); «javaType.toBuilderType» toBuilder(); @@ -170,22 +198,8 @@ class ModelObjectGenerator { } ''' - - def dispatch buildify(Object object) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } - - def dispatch buildify(Class clazz) { - new GeneratedJavaClass(DottedPath.splitOnDots(clazz.packageName), clazz.simpleName+"."+clazz.simpleName+"Builder", Object) - } - def dispatch buildify(JavaParameterizedType clazz) { - val builderClass = new GeneratedJavaClass(clazz.packageName, clazz.simpleName+"."+clazz.simpleName+"Builder", Object) - val builderDeclaration = new GeneratedJavaGenericTypeDeclaration(builderClass, "T") - JavaParameterizedType.from(builderDeclaration, clazz.getArguments) - } - def boolean globalKeyRecursive(RDataType class1) { - if (class1.EObject.hasKeyedAnnotation) { + if (class1.hasMetaAttribute('key')) { return true } val s = class1.superType @@ -195,34 +209,30 @@ class ModelObjectGenerator { return false } - private def StringConcatenationClient rosettaClass(RDataType t, JavaScope scope) { - val attributes = t.javaAttributes - val javaType = t.toJavaType - val superInterface = javaType.interfaces.head + private def StringConcatenationClient rosettaClass(JavaPojoInterface javaType, boolean extended, JavaScope scope) { + val properties = extended ? javaType.ownProperties : javaType.allProperties ''' - «FOR attribute : attributes» - private final «attribute.toMetaJavaType» «scope.createIdentifier(attribute, attribute.name.toFirstLower)»; + «FOR prop : properties» + private final «prop.type» «scope.createIdentifier(prop, prop.name.toFirstLower)»; «ENDFOR» protected «javaType»Impl(«javaType.toBuilderType» builder) { - «IF superInterface != JavaClass.from(RosettaModelObject)» - super(builder); - «ENDIF» - «FOR attribute : attributes» - this.«scope.getIdentifierOrThrow(attribute)» = «attribute.attributeFromBuilder»; + «IF extended»super(builder);«ENDIF» + «FOR prop : properties» + this.«scope.getIdentifierOrThrow(prop)» = «prop.propertyFromBuilder»; «ENDFOR» } - «FOR attribute : attributes» + «FOR prop : properties» + «val field = new JavaVariable(scope.getIdentifierOrThrow(prop), prop.type)» @Override - @«RosettaAttribute»("«attribute.javaAnnotation»") - public «attribute.toMetaJavaType» get«attribute.name.toFirstUpper»() { - return «scope.getIdentifierOrThrow(attribute)»; - } + @«RosettaAttribute»("«prop.javaAnnotation»") + public «prop.type» «prop.getterName»() «field.completeAsReturn.toBlock» + «IF !extended»«derivedIncompatibleGettersForProperty(field, prop, scope)»«ENDIF» «ENDFOR» @Override - public «t.name» build() { + public «javaType» build() { return this; } @@ -234,36 +244,45 @@ class ModelObjectGenerator { } protected void setBuilderFields(«javaType.toBuilderType» builder) { - «IF (superInterface != JavaClass.from(RosettaModelObject))» - super.setBuilderFields(builder); - «ENDIF» - «FOR attribute : attributes» - «method(Optional, "ofNullable")»(get«attribute.name.toFirstUpper»()).ifPresent(builder::set«attribute.name.toFirstUpper»); + «IF extended»super.setBuilderFields(builder);«ENDIF» + «FOR prop : properties» + «method(Optional, "ofNullable")»(«prop.getterName»()).ifPresent(builder::set«prop.name.toFirstUpper»); «ENDFOR» } ''' } + private def StringConcatenationClient derivedIncompatibleGettersForProperty(JavaExpression originalField, JavaPojoProperty prop, JavaScope scope) { + val parent = prop.parentProperty + if (parent === null) { + return null + } else if (parent.getterName == prop.getterName) { + return derivedIncompatibleGettersForProperty(originalField, parent, scope) + } + val getterScope = scope.methodScope(parent.getterName) + ''' + @Override + public «parent.type» «parent.getterName»() «originalField.addCoercions(parent.type, getterScope).completeAsReturn.toBlock» + + «derivedIncompatibleGettersForProperty(originalField, parent, scope)» + ''' + } - private def StringConcatenationClient attributeFromBuilder(RAttribute attribute) { - if(attribute.isRosettaModelObject) { - if (attribute.isMulti) - '''ofNullable(builder.get«attribute.name.toFirstUpper»()).filter(_l->!_l.isEmpty()).map(«attribute.buildRosettaObject»).orElse(null)''' + private def StringConcatenationClient propertyFromBuilder(JavaPojoProperty prop) { + if(prop.type.isRosettaModelObject) { + if (prop.type.isList) + '''ofNullable(builder.«prop.getterName»()).filter(_l->!_l.isEmpty()).map(«prop.buildRosettaObjectList»).orElse(null)''' else - '''ofNullable(builder.get«attribute.name.toFirstUpper»()).map(«attribute.buildRosettaObject»).orElse(null)''' + '''ofNullable(builder.«prop.getterName»()).map(f->f.build()).orElse(null)''' } else { - if (!attribute.isMulti) - '''builder.get«attribute.name.toFirstUpper»()''' + if (!prop.type.isList) + '''builder.«prop.getterName»()''' else - '''ofNullable(builder.get«attribute.name.toFirstUpper»()).filter(_l->!_l.isEmpty()).map(«ImmutableList»::copyOf).orElse(null)''' + '''ofNullable(builder.«prop.getterName»()).filter(_l->!_l.isEmpty()).map(«ImmutableList»::copyOf).orElse(null)''' } } - private def StringConcatenationClient buildRosettaObject(RAttribute attribute) { - if(attribute.isMulti) { - '''list -> list.stream().filter(«Objects»::nonNull).map(f->f.build()).filter(«Objects»::nonNull).collect(«ImmutableList».toImmutableList())''' - } else { - '''f->f.build()''' - } + private def StringConcatenationClient buildRosettaObjectList(JavaPojoProperty prop) { + '''list -> list.stream().filter(«Objects»::nonNull).map(f->f.build()).filter(«Objects»::nonNull).collect(«ImmutableList».toImmutableList())''' } private def StringConcatenationClient startComment(String msg) ''' diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ValidatorsGenerator.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ValidatorsGenerator.xtend index 9c6367506..7f2284b7e 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ValidatorsGenerator.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/object/ValidatorsGenerator.xtend @@ -34,6 +34,9 @@ import javax.inject.Inject import com.regnosys.rosetta.generator.java.types.JavaTypeUtil import java.util.List import com.regnosys.rosetta.types.RAttribute +import com.regnosys.rosetta.types.RCardinality +import com.regnosys.rosetta.generator.java.types.JavaPojoInterface +import com.regnosys.rosetta.generator.java.statement.builder.JavaExpression class ValidatorsGenerator { @@ -44,42 +47,44 @@ class ValidatorsGenerator { @Inject extension JavaTypeUtil def generate(RootPackage root, IFileSystemAccess2 fsa, RDataType type, String version) { - fsa.generateFile(type.toValidatorClass.canonicalName.withForwardSlashes + ".java", - generateClass(root, type, version)) - fsa.generateFile(type.toTypeFormatValidatorClass.canonicalName.withForwardSlashes + ".java", - generateTypeFormatValidator(root, type, version)) - fsa.generateFile(type.toOnlyExistsValidatorClass.canonicalName.withForwardSlashes + ".java", - generateOnlyExistsValidator(root, type, version)) + val javaType = type.toJavaReferenceType + val attrs = type.allAttributes + fsa.generateFile(javaType.toValidatorClass.canonicalName.withForwardSlashes + ".java", + generateClass(root, javaType, attrs, version)) + fsa.generateFile(javaType.toTypeFormatValidatorClass.canonicalName.withForwardSlashes + ".java", + generateTypeFormatValidator(root, javaType, attrs, version)) + fsa.generateFile(javaType.toOnlyExistsValidatorClass.canonicalName.withForwardSlashes + ".java", + generateOnlyExistsValidator(root, javaType, attrs, version)) } - private def generateClass(RootPackage root, RDataType t, String version) { + private def generateClass(RootPackage root, JavaPojoInterface javaType, Iterable attributes, String version) { val scope = new JavaScope(root.typeValidation) - buildClass(root.typeValidation, t.classBody(version, t.allNonOverridenAttributes), scope) + buildClass(root.typeValidation, javaType.classBody(version, attributes), scope) } - private def generateTypeFormatValidator(RootPackage root, RDataType t, String version) { + private def generateTypeFormatValidator(RootPackage root, JavaPojoInterface javaType, Iterable attributes, String version) { val scope = new JavaScope(root.typeValidation) - buildClass(root.typeValidation, t.typeFormatClassBody(version, t.allNonOverridenAttributes), scope) + buildClass(root.typeValidation, javaType.typeFormatClassBody(version, attributes), scope) } - private def generateOnlyExistsValidator(RootPackage root, RDataType t, String version) { + private def generateOnlyExistsValidator(RootPackage root, JavaPojoInterface javaType, Iterable attributes, String version) { val scope = new JavaScope(root.existsValidation) - buildClass(root.existsValidation, t.onlyExistsClassBody(version, t.allNonOverridenAttributes), scope) + buildClass(root.existsValidation, javaType.onlyExistsClassBody(version, attributes), scope) } - def private StringConcatenationClient classBody(RDataType t, String version, Iterable attributes) ''' - public class «t.toValidatorClass» implements «Validator»<«t.toJavaType»> { + def private StringConcatenationClient classBody(JavaPojoInterface javaType, String version, Iterable attributes) ''' + public class «javaType.toValidatorClass» implements «Validator»<«javaType»> { - private «List»<«ComparisonResult»> getComparisonResults(«t.toJavaType» o) { + private «List»<«ComparisonResult»> getComparisonResults(«javaType» o) { return «Lists».<«ComparisonResult»>newArrayList( - «FOR attrCheck : attributes.map[checkCardinality(it)].filter[it !== null] SEPARATOR ", "» + «FOR attrCheck : attributes.map[checkCardinality(javaType, it)].filter[it !== null] SEPARATOR ", "» «attrCheck» «ENDFOR» ); } @Override - public «ValidationResult»<«t.toJavaType»> validate(«RosettaPath» path, «t.toJavaType» o) { + public «ValidationResult»<«javaType»> validate(«RosettaPath» path, «javaType» o) { String error = getComparisonResults(o) .stream() .filter(res -> !res.get()) @@ -87,20 +92,20 @@ class ValidatorsGenerator { .collect(«method(Collectors, "joining")»("; ")); if (!«method(Strings, "isNullOrEmpty")»(error)) { - return «method(ValidationResult, "failure")»("«t.name»", «ValidationResult.ValidationType».CARDINALITY, "«t.name»", path, "", error); + return «method(ValidationResult, "failure")»("«javaType.rosettaName»", «ValidationResult.ValidationType».CARDINALITY, "«javaType.rosettaName»", path, "", error); } - return «method(ValidationResult, "success")»("«t.name»", «ValidationResult.ValidationType».CARDINALITY, "«t.name»", path, ""); + return «method(ValidationResult, "success")»("«javaType.rosettaName»", «ValidationResult.ValidationType».CARDINALITY, "«javaType.rosettaName»", path, ""); } @Override - public «List»<«ValidationResult»> getValidationResults(«RosettaPath» path, «t.toJavaType» o) { + public «List»<«ValidationResult»> getValidationResults(«RosettaPath» path, «javaType» o) { return getComparisonResults(o) .stream() .map(res -> { if (!«method(Strings, "isNullOrEmpty")»(res.getError())) { - return «method(ValidationResult, "failure")»("«t.name»", «ValidationResult.ValidationType».CARDINALITY, "«t.name»", path, "", res.getError()); + return «method(ValidationResult, "failure")»("«javaType.rosettaName»", «ValidationResult.ValidationType».CARDINALITY, "«javaType.rosettaName»", path, "", res.getError()); } - return «method(ValidationResult, "success")»("«t.name»", «ValidationResult.ValidationType».CARDINALITY, "«t.name»", path, ""); + return «method(ValidationResult, "success")»("«javaType.rosettaName»", «ValidationResult.ValidationType».CARDINALITY, "«javaType.rosettaName»", path, ""); }) .collect(«method(Collectors, "toList")»()); } @@ -108,19 +113,19 @@ class ValidatorsGenerator { } ''' - def private StringConcatenationClient typeFormatClassBody(RDataType t, String version, Iterable attributes) ''' - public class «t.toTypeFormatValidatorClass» implements «Validator»<«t.toJavaType»> { + def private StringConcatenationClient typeFormatClassBody(JavaPojoInterface javaType, String version, Iterable attributes) ''' + public class «javaType.toTypeFormatValidatorClass» implements «Validator»<«javaType»> { - private «List»<«ComparisonResult»> getComparisonResults(«t.toJavaType» o) { + private «List»<«ComparisonResult»> getComparisonResults(«javaType» o) { return «Lists».<«ComparisonResult»>newArrayList( - «FOR attrCheck : attributes.map[checkTypeFormat].filter[it !== null] SEPARATOR ", "» + «FOR attrCheck : attributes.map[checkTypeFormat(javaType, it)].filter[it !== null] SEPARATOR ", "» «attrCheck» «ENDFOR» ); } @Override - public «ValidationResult»<«t.toJavaType»> validate(«RosettaPath» path, «t.toJavaType» o) { + public «ValidationResult»<«javaType»> validate(«RosettaPath» path, «javaType» o) { String error = getComparisonResults(o) .stream() .filter(res -> !res.get()) @@ -128,20 +133,20 @@ class ValidatorsGenerator { .collect(«method(Collectors, "joining")»("; ")); if (!«method(Strings, "isNullOrEmpty")»(error)) { - return «method(ValidationResult, "failure")»("«t.name»", «ValidationResult.ValidationType».TYPE_FORMAT, "«t.name»", path, "", error); + return «method(ValidationResult, "failure")»("«javaType.rosettaName»", «ValidationResult.ValidationType».TYPE_FORMAT, "«javaType.rosettaName»", path, "", error); } - return «method(ValidationResult, "success")»("«t.name»", «ValidationResult.ValidationType».TYPE_FORMAT, "«t.name»", path, ""); + return «method(ValidationResult, "success")»("«javaType.rosettaName»", «ValidationResult.ValidationType».TYPE_FORMAT, "«javaType.rosettaName»", path, ""); } @Override - public «List»<«ValidationResult»> getValidationResults(«RosettaPath» path, «t.toJavaType» o) { + public «List»<«ValidationResult»> getValidationResults(«RosettaPath» path, «javaType» o) { return getComparisonResults(o) .stream() .map(res -> { if (!«method(Strings, "isNullOrEmpty")»(res.getError())) { - return «method(ValidationResult, "failure")»("«t.name»", «ValidationResult.ValidationType».TYPE_FORMAT, "«t.name»", path, "", res.getError()); + return «method(ValidationResult, "failure")»("«javaType.rosettaName»", «ValidationResult.ValidationType».TYPE_FORMAT, "«javaType.rosettaName»", path, "", res.getError()); } - return «method(ValidationResult, "success")»("«t.name»", «ValidationResult.ValidationType».TYPE_FORMAT, "«t.name»", path, ""); + return «method(ValidationResult, "success")»("«javaType.rosettaName»", «ValidationResult.ValidationType».TYPE_FORMAT, "«javaType.rosettaName»", path, ""); }) .collect(«method(Collectors, "toList")»()); } @@ -149,15 +154,19 @@ class ValidatorsGenerator { } ''' - def private StringConcatenationClient onlyExistsClassBody(RDataType t, String version, Iterable attributes) ''' - public class «t.toOnlyExistsValidatorClass» implements «ValidatorWithArg»<«t.toJavaType», «Set»> { + def private StringConcatenationClient onlyExistsClassBody(JavaPojoInterface javaType, String version, Iterable attributes) { + + ''' + public class «javaType.toOnlyExistsValidatorClass» implements «ValidatorWithArg»<«javaType», «Set»> { /* Casting is required to ensure types are output to ensure recompilation in Rosetta */ @Override - public «ValidationResult»<«t.toJavaType»> validate(«RosettaPath» path, T2 o, «Set» fields) { + public «ValidationResult»<«javaType»> validate(«RosettaPath» path, T2 o, «Set» fields) { «Map» fieldExistenceMap = «ImmutableMap».builder() «FOR attr : attributes» - .put("«attr.name»", «ExistenceChecker».isSet((«attr.toMetaJavaType») o.get«attr.name?.toFirstUpper»())) + «val prop = javaType.findProperty(attr.name)» + «val propCode = prop.applyGetter(JavaExpression.from('''o''', javaType))» + .put("«prop.name»", «ExistenceChecker».isSet((«prop.type») «propCode»)) «ENDFOR» .build(); @@ -168,30 +177,33 @@ class ValidatorsGenerator { .collect(«Collectors».toSet()); if (setFields.equals(fields)) { - return «method(ValidationResult, "success")»("«t.name»", «ValidationType».ONLY_EXISTS, "«t.name»", path, ""); + return «method(ValidationResult, "success")»("«javaType.rosettaName»", «ValidationType».ONLY_EXISTS, "«javaType.rosettaName»", path, ""); } - return «method(ValidationResult, "failure")»("«t.name»", «ValidationType».ONLY_EXISTS, "«t.name»", path, "", + return «method(ValidationResult, "failure")»("«javaType.rosettaName»", «ValidationType».ONLY_EXISTS, "«javaType.rosettaName»", path, "", String.format("[%s] should only be set. Set fields: %s", fields, setFields)); } } - ''' + ''' + } - private def StringConcatenationClient checkCardinality(RAttribute attr) { - if (attr.cardinality.minBound === 0 && attr.cardinality.unboundedRight) { + private def StringConcatenationClient checkCardinality(JavaPojoInterface javaType, RAttribute attr) { + if (attr.cardinality == RCardinality.UNBOUNDED) { null } else { + val prop = javaType.findProperty(attr.name) + val propCode = prop.applyGetter(JavaExpression.from('''o''', javaType)); /* Casting is required to ensure types are output to ensure recompilation in Rosetta */ ''' «IF attr.isMulti» - «method(ExpressionOperators, "checkCardinality")»("«attr.name»", («attr.toMetaJavaType») o.get«attr.name?.toFirstUpper»() == null ? 0 : ((«attr.toMetaJavaType») o.get«attr.name?.toFirstUpper»()).size(), «attr.cardinality.minBound», «attr.cardinality.max.orElse(0)») + «method(ExpressionOperators, "checkCardinality")»("«attr.name»", («prop.type») «propCode» == null ? 0 : «propCode».size(), «attr.cardinality.min», «attr.cardinality.max.orElse(0)») «ELSE» - «method(ExpressionOperators, "checkCardinality")»("«attr.name»", («attr.toMetaJavaType») o.get«attr.name?.toFirstUpper»() != null ? 1 : 0, «attr.cardinality.minBound», «attr.cardinality.max.orElse(0)») + «method(ExpressionOperators, "checkCardinality")»("«attr.name»", («prop.type») «propCode» != null ? 1 : 0, «attr.cardinality.min», «attr.cardinality.max.orElse(0)») «ENDIF» ''' } } - private def StringConcatenationClient checkTypeFormat(RAttribute attr) { + private def StringConcatenationClient checkTypeFormat(JavaPojoInterface javaType, RAttribute attr) { val t = attr.RMetaAnnotatedType.RType.stripFromTypeAliases if (t instanceof RStringType) { if (t != UNCONSTRAINED_STRING) { @@ -199,7 +211,7 @@ class ValidatorsGenerator { val max = t.interval.max.optional val pattern = t.pattern.optionalPattern - return '''«method(ExpressionOperators, "checkString")»("«attr.name»", «attr.attributeValue», «min», «max», «pattern»)''' + return '''«method(ExpressionOperators, "checkString")»("«attr.name»", «javaType.getAttributeValue(attr)», «min», «max», «pattern»)''' } } else if (t instanceof RNumberType) { if (t != UNCONSTRAINED_NUMBER) { @@ -208,22 +220,24 @@ class ValidatorsGenerator { val min = t.interval.min.optionalBigDecimal val max = t.interval.max.optionalBigDecimal - return '''«method(ExpressionOperators, "checkNumber")»("«attr.name»", «attr.attributeValue», «digits», «fractionalDigits», «min», «max»)''' + return '''«method(ExpressionOperators, "checkNumber")»("«attr.name»", «javaType.getAttributeValue(attr)», «digits», «fractionalDigits», «min», «max»)''' } } return null } - private def StringConcatenationClient getAttributeValue(RAttribute attr) { + private def StringConcatenationClient getAttributeValue(JavaPojoInterface javaType, RAttribute attr) { + val prop = javaType.findProperty(attr.name) + val propCode = prop.applyGetter(JavaExpression.from('''o''', javaType)); if (!attr.RMetaAnnotatedType.hasMeta) { - '''o.get«attr.name?.toFirstUpper»()''' + '''«propCode»''' } else { - val jt = attr.toMetaJavaType + val jt = prop.type if (jt.isList) { val itemType = jt.itemType - '''o.get«attr.name?.toFirstUpper»().stream().map(«itemType»::getValue).collect(«Collectors».toList())''' + '''«propCode».stream().map(«itemType»::getValue).collect(«Collectors».toList())''' } else { - '''o.get«attr.name?.toFirstUpper»().getValue()''' + '''«propCode».getValue()''' } } } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/reports/TabulatorGenerator.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/reports/TabulatorGenerator.xtend index 0d45afc57..f7be71ef1 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/reports/TabulatorGenerator.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/reports/TabulatorGenerator.xtend @@ -41,6 +41,7 @@ import org.apache.commons.text.StringEscapeUtils import org.eclipse.xtend2.lib.StringConcatenationClient import org.eclipse.xtext.generator.IFileSystemAccess2 import com.regnosys.rosetta.types.RChoiceType +import com.regnosys.rosetta.generator.java.types.JavaPojoInterface class TabulatorGenerator { private interface TabulatorContext { @@ -243,7 +244,7 @@ class TabulatorGenerator { fsa.generateFile(tabulatorClass.canonicalName.withForwardSlashes + ".java", content) type - .allNonOverridenAttributes + .allAttributes .map[RMetaAnnotatedType] .map[RType] .map[it instanceof RChoiceType ? asRDataType : it] @@ -353,7 +354,7 @@ class TabulatorGenerator { public interface «tabulatorClass» extends «Tabulator»<«inputClass»> { @«Singleton» class Impl implements «tabulatorClass» { - «FOR attr : inputType.allNonOverridenAttributes» + «FOR attr : inputType.allAttributes» «IF context.isTabulated(attr)» «val fieldId = classScope.getIdentifierOrThrow(attr)» private final «Field» «fieldId»; @@ -386,7 +387,7 @@ class TabulatorGenerator { private def List findTabulatedFieldsAndCreateIdentifiers(RDataType type, TabulatorContext context, JavaScope scope) { type - .allNonOverridenAttributes + .allAttributes .filter[context.isTabulated(it)] .map[ scope.createIdentifier(it, name + "Field") @@ -395,7 +396,7 @@ class TabulatorGenerator { } private def StringConcatenationClient initializeFields(RDataType type, TabulatorContext context, JavaScope scope) { ''' - «FOR attr : type.allNonOverridenAttributes» + «FOR attr : type.allAttributes» «IF context.isTabulated(attr)» «val fieldId = scope.getIdentifierOrThrow(attr)» «val rule = context.getRule(attr)» @@ -412,7 +413,7 @@ class TabulatorGenerator { } private def Set findNestedTabulatorsAndCreateIdentifiers(RDataType type, TabulatorContext context, JavaScope scope) { - val result = type.allNonOverridenAttributes + val result = type.allAttributes .filter[context.isTabulated(it)] .map[RMetaAnnotatedType] .map[RType] @@ -426,15 +427,15 @@ class TabulatorGenerator { private def StringConcatenationClient computeFieldValues(RDataType type, GeneratedIdentifier inputParam, TabulatorContext context, JavaScope scope) { ''' - «FOR attr : type.allNonOverridenAttributes» + «FOR attr : type.allAttributes» «IF context.isTabulated(attr)» - «fieldValue(attr, inputParam, scope)» + «fieldValue(type.toJavaReferenceType, attr, inputParam, scope)» «ENDIF» «ENDFOR» ''' } - private def StringConcatenationClient fieldValue(RAttribute attr, GeneratedIdentifier inputParam, JavaScope scope) { + private def StringConcatenationClient fieldValue(JavaPojoInterface javaType, RAttribute attr, GeneratedIdentifier inputParam, JavaScope scope) { val rawAttr = attr.RMetaAnnotatedType.RType val rType = if (rawAttr instanceof RChoiceType) { rawAttr.asRDataType @@ -450,10 +451,11 @@ class TabulatorGenerator { val nestedLambdaScope = lambdaScope.lambdaScope val nestedLambdaParam = nestedLambdaScope.createUniqueIdentifier("x") + val getter = javaType.findProperty(attr.name).getterName if (rType instanceof RDataType) { val nestedTabulator = scope.getIdentifierOrThrow(rType.toNestedTabulatorInstance) ''' - «FieldValue» «resultId» = «Optional».ofNullable(«inputParam».get«attr.name.toFirstUpper»()) + «FieldValue» «resultId» = «Optional».ofNullable(«inputParam».«getter»()) «IF attr.isMulti» .map(«lambdaParam» -> «lambdaParam».stream() «IF attr.RMetaAnnotatedType.hasMeta» @@ -473,15 +475,15 @@ class TabulatorGenerator { } else { ''' «IF !attr.RMetaAnnotatedType.hasMeta» - «FieldValue» «resultId» = new «FieldValueImpl»(«scope.getIdentifierOrThrow(attr)», «Optional».ofNullable(«inputParam».get«attr.name.toFirstUpper»())); + «FieldValue» «resultId» = new «FieldValueImpl»(«scope.getIdentifierOrThrow(attr)», «Optional».ofNullable(«inputParam».«getter»())); «ELSEIF attr.isMulti» - «FieldValue» «resultId» = new «FieldValueImpl»(«scope.getIdentifierOrThrow(attr)», «Optional».ofNullable(«inputParam».get«attr.name.toFirstUpper»()) + «FieldValue» «resultId» = new «FieldValueImpl»(«scope.getIdentifierOrThrow(attr)», «Optional».ofNullable(«inputParam».«getter»()) .map(«lambdaParam» -> «lambdaParam».stream() .map(«nestedLambdaParam» -> «nestedLambdaParam».getValue()) .filter(«Objects»::nonNull) .collect(«Collectors».toList()))); «ELSE» - «FieldValue» «resultId» = new «FieldValueImpl»(«scope.getIdentifierOrThrow(attr)», «Optional».ofNullable(«inputParam».get«attr.name.toFirstUpper»()) + «FieldValue» «resultId» = new «FieldValueImpl»(«scope.getIdentifierOrThrow(attr)», «Optional».ofNullable(«inputParam».«getter»()) .map(«lambdaParam» -> «lambdaParam».getValue())); «ENDIF» ''' @@ -491,7 +493,7 @@ class TabulatorGenerator { private def StringConcatenationClient fieldValuesAsList(RDataType type, TabulatorContext context, JavaScope scope) { ''' «Arrays».asList( - «FOR attr : type.allNonOverridenAttributes.filter[context.isTabulated(it)] SEPARATOR ","» + «FOR attr : type.allAttributes.filter[context.isTabulated(it)] SEPARATOR ","» «scope.getIdentifier(attr.toComputedField)» «ENDFOR» )''' diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/statement/JavaEnhancedForLoop.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/statement/JavaEnhancedForLoop.java new file mode 100644 index 000000000..d33d87e31 --- /dev/null +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/statement/JavaEnhancedForLoop.java @@ -0,0 +1,52 @@ +package com.regnosys.rosetta.generator.java.statement; + +import org.eclipse.xtend2.lib.StringConcatenationClient.TargetStringConcatenation; + +import com.regnosys.rosetta.generator.GeneratedIdentifier; +import com.regnosys.rosetta.generator.java.statement.builder.JavaExpression; +import com.rosetta.util.types.JavaType; + +/** + * Based on the Java specification: https://docs.oracle.com/javase/specs/jls/se11/html/jls-14.html#jls-EnhancedForStatement + * + * Example: + * ``` + * for (Foo foo : fooList) { + * processFoo(foo); + * } + * ``` + * + * See `JavaStatementBuilder` for more documentation. + */ +public class JavaEnhancedForLoop extends JavaStatement { + private final boolean isFinal; + private final JavaType variableType; + private final GeneratedIdentifier variableId; + private final JavaExpression iterableExpression; + private final JavaStatement forBody; + + public JavaEnhancedForLoop(boolean isFinal, JavaType variableType, GeneratedIdentifier variableId, JavaExpression iterableExpression, JavaStatement forBody) { + this.isFinal = isFinal; + this.variableType = variableType; + this.variableId = variableId; + this.iterableExpression = iterableExpression; + this.forBody = forBody; + } + + @Override + public void appendTo(TargetStringConcatenation target) { + target.append("for ("); + if (isFinal) { + target.append("final "); + } + target.append(variableType); + target.append(" "); + target.append(variableId); + target.append(" : "); + target.append(iterableExpression); + target.append(") "); + // Calling `toBlock()` will make sure that the body is always enclosed in curly braces. + // This is a style preference, and is technically not necessary. + target.append(forBody.toBlock()); + } +} diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/statement/builder/JavaVariable.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/statement/builder/JavaVariable.java index 7978f8048..0ad937ea5 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/statement/builder/JavaVariable.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/statement/builder/JavaVariable.java @@ -37,7 +37,9 @@ public JavaVariable(GeneratedIdentifier id, JavaType type) { @Override public JavaStatementBuilder declareAsVariable(boolean isFinal, String variableId, JavaScope scope) { - scope.createSynonym(this, id); + if (scope.getIdentifier(this).map(scopeId -> !scopeId.equals(id)).orElse(true)) { + scope.createSynonym(this, id); + } return this; } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/JavaPojoInterface.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/JavaPojoInterface.java new file mode 100644 index 000000000..0622c40b6 --- /dev/null +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/JavaPojoInterface.java @@ -0,0 +1,82 @@ +/* + * Copyright 2024 REGnosys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.regnosys.rosetta.generator.java.types; + +import java.util.Collection; +import java.util.NoSuchElementException; + +import com.rosetta.model.lib.RosettaModelObject; +import com.rosetta.util.types.JavaClass; +import com.rosetta.util.types.JavaType; +import com.rosetta.util.types.JavaTypeDeclaration; + +public abstract class JavaPojoInterface extends JavaClass { + public abstract String getJavadoc(); + public abstract String getRosettaName(); + public abstract String getVersion(); + + public abstract Collection getOwnProperties(); + public abstract Collection getAllProperties(); + + public abstract JavaPojoInterface getSuperPojo(); + + public JavaPojoProperty findProperty(String propertyName, JavaType desiredType) { + JavaPojoProperty prop = findProperty(propertyName); + JavaPojoProperty currentProp = prop; + while (currentProp != null) { + if (desiredType.isSubtypeOf(currentProp.getType())) { + return currentProp; + } + currentProp = currentProp.getParentProperty(); + } + // Fallback: no compatible type found + return prop; + } + public JavaPojoProperty findProperty(String propertyName) { + return getAllProperties().stream().filter(prop -> prop.getName().equals(propertyName)) + .findAny() + .orElseThrow(() -> new NoSuchElementException("No property named " + propertyName + " in pojo " + this)); + } + + @Override + public JavaClass getSuperclassDeclaration() { + return JavaClass.OBJECT; + } + + @Override + public JavaClass getSuperclass() { + return getSuperclassDeclaration(); + } + + @Override + public boolean extendsDeclaration(JavaTypeDeclaration other) { + if (other instanceof JavaClass) { + return this.isSubtypeOf((JavaClass)other); + } + return false; + } + + @Override + public boolean isFinal() { + return false; + } + + @Override + public Class loadClass(ClassLoader classLoader) throws ClassNotFoundException { + return Class.forName(getCanonicalName().toString(), true, classLoader).asSubclass(RosettaModelObject.class); + } +} diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/JavaPojoProperty.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/JavaPojoProperty.java new file mode 100644 index 000000000..473cb43df --- /dev/null +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/JavaPojoProperty.java @@ -0,0 +1,115 @@ +/* + * Copyright 2024 REGnosys + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.regnosys.rosetta.generator.java.types; + +import java.util.Objects; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.xtend2.lib.StringConcatenationClient; + +import com.regnosys.rosetta.generator.java.statement.builder.JavaExpression; +import com.rosetta.model.lib.process.AttributeMeta; +import com.rosetta.util.types.JavaType; + +public class JavaPojoProperty { + private final String name; + private final String compatibilityName; + private final JavaType type; + private final String javadoc; + private final JavaPojoProperty parentProperty; + private final AttributeMeta meta; // used in `process` method + private final boolean hasLocation; // used in builder `getOrCreate` + + public JavaPojoProperty(String name, String compatibilityName, JavaType type, String javadoc, AttributeMeta meta, boolean hasLocation) { + this(name, compatibilityName, type, javadoc, meta, hasLocation, null); + } + private JavaPojoProperty(String name, String compatibilityName, JavaType type, String javadoc, AttributeMeta meta, boolean hasLocation, JavaPojoProperty parentProperty) { + this.name = name; + this.compatibilityName = compatibilityName; + this.type = type; + this.javadoc = javadoc; + this.meta = meta; + this.hasLocation = hasLocation; + this.parentProperty = parentProperty; + } + public JavaPojoProperty specialize(String compatibilityName, JavaType newType, String newJavadoc, AttributeMeta newMeta, boolean newHasLocation) { + return new JavaPojoProperty(name, compatibilityName, newType, newJavadoc, newMeta, newHasLocation, this); + } + + public boolean isCompatibleWithParent() { + return parentProperty == null || type.isSubtypeOf(parentProperty.type); + } + + public String getName() { + return name; + } + public String getGetterName() { + return "get" + StringUtils.capitalize(compatibilityName); + } + public String getGetOrCreateName() { + return "getOrCreate" + StringUtils.capitalize(compatibilityName); + } + public JavaType getType() { + return type; + } + public String getJavadoc() { + return javadoc; + } + public AttributeMeta getMeta() { + return meta; + } + public boolean hasLocation() { + return hasLocation; + } + public JavaPojoProperty getParentProperty() { + return parentProperty; + } + + public JavaExpression applyGetter(JavaExpression expr) { + return JavaExpression.from(new StringConcatenationClient() { + @Override + protected void appendTo(TargetStringConcatenation target) { + target.append(expr); + target.append('.'); + target.append(getGetterName()); + target.append("()"); + } + }, type); + } + + @Override + public String toString() { + return JavaPojoProperty.class.getSimpleName() + "[" + type.getSimpleName() + " " + getGetterName() + "()]"; + } + @Override + public int hashCode() { + return Objects.hash(compatibilityName, hasLocation, javadoc, meta, name, parentProperty, type); + } + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + JavaPojoProperty other = (JavaPojoProperty) obj; + return Objects.equals(compatibilityName, other.compatibilityName) && hasLocation == other.hasLocation + && Objects.equals(javadoc, other.javadoc) && meta == other.meta && Objects.equals(name, other.name) + && Objects.equals(parentProperty, other.parentProperty) && Objects.equals(type, other.type); + } +} diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/JavaTypeTranslator.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/JavaTypeTranslator.java index aec3d1a0d..298d5c881 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/JavaTypeTranslator.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/JavaTypeTranslator.java @@ -26,12 +26,10 @@ import javax.inject.Inject; -import com.regnosys.rosetta.RosettaEcoreUtil; import com.regnosys.rosetta.generator.java.RosettaJavaPackages; import com.regnosys.rosetta.rosetta.RosettaExternalFunction; import com.regnosys.rosetta.rosetta.RosettaExternalRuleSource; import com.regnosys.rosetta.rosetta.RosettaReport; -import com.regnosys.rosetta.rosetta.RosettaRootElement; import com.regnosys.rosetta.rosetta.simple.Attribute; import com.regnosys.rosetta.rosetta.simple.Data; import com.regnosys.rosetta.rosetta.simple.Function; @@ -72,6 +70,7 @@ import com.rosetta.util.types.JavaType; import com.rosetta.util.types.generated.GeneratedJavaClass; import com.rosetta.util.types.generated.GeneratedJavaClassService; +import com.rosetta.util.types.generated.GeneratedJavaGenericTypeDeclaration; public class JavaTypeTranslator extends RosettaTypeSwitch { @Inject @@ -91,18 +90,29 @@ public JavaTypeTranslator(RBuiltinTypeService builtins) { @Inject private ModelIdProvider modelIdProvider; - private DottedPath getModelPackage(RosettaRootElement object) { - return modelIdProvider.toDottedPath(object.getModel()); - } - + @Deprecated public boolean isRosettaModelObject(RAttribute attr) { RMetaAnnotatedType rMetaAnnotatedType = attr.getRMetaAnnotatedType(); return isValueRosettaModelObject(attr) || rMetaAnnotatedType.hasMeta(); } + @Deprecated public boolean isValueRosettaModelObject(RAttribute attr) { RType t = attr.getRMetaAnnotatedType().getRType(); return t instanceof RDataType || t instanceof RChoiceType; } + public boolean isRosettaModelObject(JavaType type) { + return typeUtil.getItemType(type).isSubtypeOf(typeUtil.ROSETTA_MODEL_OBJECT); + } + public boolean isValueRosettaModelObject(JavaType type) { + JavaType itemType = typeUtil.getItemType(type); + if (itemType instanceof RJavaWithMetaValue) { + return isValueRosettaModelObject((RJavaWithMetaValue)itemType); + } + return itemType.isSubtypeOf(typeUtil.ROSETTA_MODEL_OBJECT); + } + public boolean isValueRosettaModelObject(RJavaWithMetaValue t) { + return t.getValueType().isSubtypeOf(typeUtil.ROSETTA_MODEL_OBJECT); + } public JavaParameterizedType> toPolymorphicList(JavaReferenceType t) { return typeUtil.wrapExtends(typeUtil.LIST, t); @@ -279,7 +289,7 @@ public JavaClass toJavaReferenceType(RType type) { throw new UnsupportedOperationException("Cannot convert type " + getTypeDebugInfo(type) + " to a Java reference type."); } } - public RJavaPojoInterface toJavaReferenceType(RDataType type) { + public JavaPojoInterface toJavaReferenceType(RDataType type) { return toJavaType(type); } public RJavaEnum toJavaReferenceType(REnumType type) { @@ -305,7 +315,7 @@ public JavaType toJavaType(RMetaAnnotatedType type) { private JavaType toJavaType(RType type) { return doSwitch(type, null); } - public RJavaPojoInterface toJavaType(RDataType type) { + public JavaPojoInterface toJavaType(RDataType type) { return caseDataType(type, null); } public RJavaEnum toJavaType(REnumType type) { @@ -350,20 +360,24 @@ public JavaClass toBuilderType(JavaClass type) { if (type.equals(JavaClass.from(RosettaModelObject.class))) { return JavaClass.from(RosettaModelObjectBuilder.class); } - return new GeneratedJavaClass<>(type.getPackageName(), type.getSimpleName() + "." + type.getSimpleName() + "Builder", Object.class); + GeneratedJavaClass base = new GeneratedJavaClass<>(type.getPackageName(), type.getSimpleName() + "." + type.getSimpleName() + "Builder", Object.class); + if (type instanceof JavaParameterizedType) { + return JavaParameterizedType.from(new GeneratedJavaGenericTypeDeclaration<>(base, "T"), ((JavaParameterizedType)type).getArguments()); + } + return base; } public JavaClass toBuilderImplType(JavaClass type) { return new GeneratedJavaClass<>(type.getPackageName(), type.getSimpleName() + "." + type.getSimpleName() + "BuilderImpl", Object.class); } - public JavaClass toValidatorClass(RDataType t) { - return new GeneratedJavaClass<>(validation(getModelPackage(t.getEObject())), t.getName() + "Validator", Object.class); + public JavaClass toValidatorClass(JavaPojoInterface t) { + return new GeneratedJavaClass<>(validation(t.getPackageName()), t.getSimpleName() + "Validator", Object.class); } - public JavaClass toTypeFormatValidatorClass(RDataType t) { - return new GeneratedJavaClass<>(validation(getModelPackage(t.getEObject())), t.getName() + "TypeFormatValidator", Object.class); + public JavaClass toTypeFormatValidatorClass(JavaPojoInterface t) { + return new GeneratedJavaClass<>(validation(t.getPackageName()), t.getSimpleName() + "TypeFormatValidator", Object.class); } - public JavaClass toOnlyExistsValidatorClass(RDataType t) { - return new GeneratedJavaClass<>(existsValidation(getModelPackage(t.getEObject())), t.getName() + "OnlyExistsValidator", Object.class); + public JavaClass toOnlyExistsValidatorClass(JavaPojoInterface t) { + return new GeneratedJavaClass<>(existsValidation(t.getPackageName()), t.getSimpleName() + "OnlyExistsValidator", Object.class); } private DottedPath metaField(DottedPath p) { @@ -381,11 +395,11 @@ protected JavaType caseErrorType(RErrorType type, Void context) { throw new IllegalArgumentException("Cannot convert an error type to a Java type."); } @Override - protected RJavaPojoInterface caseDataType(RDataType type, Void context) { - return new RJavaPojoInterface(type, typeSystem); + protected JavaPojoInterface caseDataType(RDataType type, Void context) { + return new RJavaPojoInterface(type, typeSystem, this, typeUtil); } @Override - protected RJavaPojoInterface caseChoiceType(RChoiceType type, Void context) { + protected JavaPojoInterface caseChoiceType(RChoiceType type, Void context) { return caseDataType(type.asRDataType(), context); } @Override diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/JavaTypeUtil.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/JavaTypeUtil.java index 336c213b4..6bce5260a 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/JavaTypeUtil.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/JavaTypeUtil.java @@ -31,13 +31,17 @@ import com.regnosys.rosetta.types.RosettaTypeProvider; import com.rosetta.model.lib.GlobalKey; import com.rosetta.model.lib.RosettaModelObject; +import com.rosetta.model.lib.Templatable; import com.rosetta.model.lib.expression.ComparisonResult; import com.rosetta.model.lib.mapper.Mapper; import com.rosetta.model.lib.mapper.MapperC; import com.rosetta.model.lib.mapper.MapperListOfLists; import com.rosetta.model.lib.mapper.MapperS; import com.rosetta.model.lib.meta.FieldWithMeta; +import com.rosetta.model.lib.meta.Reference; import com.rosetta.model.lib.meta.ReferenceWithMeta; +import com.rosetta.model.metafields.MetaAndTemplateFields; +import com.rosetta.model.metafields.MetaFields; import com.rosetta.util.types.JavaClass; import com.rosetta.util.types.JavaGenericTypeDeclaration; import com.rosetta.util.types.JavaParameterizedType; @@ -67,6 +71,10 @@ public class JavaTypeUtil { public final JavaClass LOCAL_DATE_TIME = JavaClass.from(LocalDateTime.class); public final JavaClass ZONED_DATE_TIME = JavaClass.from(ZonedDateTime.class); public final JavaClass GLOBAL_KEY = JavaClass.from(GlobalKey.class); + public final JavaClass TEMPLATABLE = JavaClass.from(Templatable.class); + public final JavaClass REFERENCE = JavaClass.from(Reference.class); + public final JavaClass META_FIELDS = JavaClass.from(MetaFields.class); + public final JavaClass META_AND_TEMPLATE_FIELDS = JavaClass.from(MetaAndTemplateFields.class); public final JavaClass OBJECT = JavaClass.OBJECT; public final JavaClass CLONEABLE = JavaClass.CLONEABLE; @@ -114,7 +122,7 @@ public JavaParameterizedType wrapExtends(JavaGenericTypeDeclaration wr } public JavaParameterizedType wrapExtendsIfNotFinal(JavaGenericTypeDeclaration wrapperType, JavaType itemType) { - if (itemType instanceof RJavaPojoInterface) { + if (itemType instanceof JavaPojoInterface) { return wrapExtends(wrapperType, itemType); } else { return wrap(wrapperType, itemType); diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/RJavaFieldWithMeta.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/RJavaFieldWithMeta.java index 1fad8f5ea..fd7ac19ff 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/RJavaFieldWithMeta.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/RJavaFieldWithMeta.java @@ -1,8 +1,8 @@ package com.regnosys.rosetta.generator.java.types; +import java.util.Collection; import java.util.List; -import com.rosetta.model.lib.RosettaModelObject; import com.rosetta.model.lib.meta.FieldWithMeta; import com.rosetta.util.DottedPath; import com.rosetta.util.types.JavaClass; @@ -13,15 +13,14 @@ public class RJavaFieldWithMeta extends RJavaWithMetaValue { private final DottedPath namespace; - private final JavaTypeUtil javaTypeUtil; + private final JavaTypeUtil typeUtil; private final JavaParameterizedType> fieldWithMetaParameterisedType; - - public RJavaFieldWithMeta(JavaReferenceType valueType, DottedPath namespace, JavaTypeUtil javaTypeUtil) { + public RJavaFieldWithMeta(JavaReferenceType valueType, DottedPath namespace, JavaTypeUtil typeUtil) { super(valueType); this.namespace = namespace; - this.javaTypeUtil = javaTypeUtil; - fieldWithMetaParameterisedType = javaTypeUtil.wrap(javaTypeUtil.FIELD_WITH_META, valueType); + this.typeUtil = typeUtil; + fieldWithMetaParameterisedType = typeUtil.wrap(typeUtil.FIELD_WITH_META, valueType); } @Override @@ -29,10 +28,10 @@ public boolean isSubtypeOf(JavaType other) { if (fieldWithMetaParameterisedType.isSubtypeOf(other)) { return true; } - if (javaTypeUtil.ROSETTA_MODEL_OBJECT.isSubtypeOf(other)) { + if (typeUtil.ROSETTA_MODEL_OBJECT.isSubtypeOf(other)) { return true; } - if (javaTypeUtil.GLOBAL_KEY.isSubtypeOf(other)) { + if (typeUtil.GLOBAL_KEY.isSubtypeOf(other)) { return true; } return false; @@ -43,32 +42,9 @@ public String getSimpleName() { return "FieldWithMeta" + valueType.getSimpleName(); } - @Override - public JavaTypeDeclaration getSuperclassDeclaration() { - return JavaClass.OBJECT; - } - @Override public List> getInterfaceDeclarations() { - return List.of(javaTypeUtil.ROSETTA_MODEL_OBJECT, javaTypeUtil.FIELD_WITH_META, javaTypeUtil.GLOBAL_KEY); - } - - @Override - public boolean extendsDeclaration(JavaTypeDeclaration other) { - if (other instanceof JavaClass) { - return this.isSubtypeOf((JavaClass)other); - } - return false; - } - - @Override - public boolean isFinal() { - return false; - } - - @Override - public Class loadClass(ClassLoader classLoader) throws ClassNotFoundException { - return Class.forName(getCanonicalName().toString(), true, classLoader).asSubclass(RosettaModelObject.class); + return List.of(typeUtil.ROSETTA_MODEL_OBJECT, typeUtil.FIELD_WITH_META, typeUtil.GLOBAL_KEY); } @Override @@ -76,10 +52,16 @@ public DottedPath getPackageName() { return namespace; } - @Override public List> getInterfaces() { - return List.of(javaTypeUtil.ROSETTA_MODEL_OBJECT,fieldWithMetaParameterisedType, javaTypeUtil.GLOBAL_KEY); + return List.of(typeUtil.ROSETTA_MODEL_OBJECT, fieldWithMetaParameterisedType, typeUtil.GLOBAL_KEY); + } + + @Override + public Collection getOwnProperties() { + return List.of( + new JavaPojoProperty("value", "value", valueType, null, null, false), + new JavaPojoProperty("meta", "meta", typeUtil.META_FIELDS, null, null, false) + ); } - } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/RJavaPojoInterface.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/RJavaPojoInterface.java index 0ad9fbc79..6b7aa8925 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/RJavaPojoInterface.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/RJavaPojoInterface.java @@ -16,42 +16,132 @@ package com.regnosys.rosetta.generator.java.types; -import java.util.Collections; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import com.regnosys.rosetta.generator.java.util.ModelGeneratorUtil; import com.regnosys.rosetta.types.RDataType; import com.regnosys.rosetta.types.TypeSystem; -import com.rosetta.model.lib.RosettaModelObject; +import com.rosetta.model.lib.process.AttributeMeta; import com.rosetta.util.DottedPath; import com.rosetta.util.types.JavaClass; -import com.rosetta.util.types.JavaPrimitiveType; import com.rosetta.util.types.JavaType; -import com.rosetta.util.types.JavaTypeDeclaration; -public class RJavaPojoInterface extends JavaClass { - private static JavaClass ROSETTA_MODEL_OBJECT = JavaClass.from(RosettaModelObject.class); - +public class RJavaPojoInterface extends JavaPojoInterface { private final RDataType type; + private RJavaPojoInterface superPojo = null; + private Map ownProperties = null; + private Map allProperties = null; private final TypeSystem typeSystem; + private final JavaTypeTranslator typeTranslator; + private final JavaTypeUtil typeUtil; - public RJavaPojoInterface(RDataType type, TypeSystem typeSystem) { + public RJavaPojoInterface(RDataType type, TypeSystem typeSystem, JavaTypeTranslator typeTranslator, JavaTypeUtil typeUtil) { this.type = type; this.typeSystem = typeSystem; + this.typeTranslator = typeTranslator; + this.typeUtil = typeUtil; + } + + @Override + public String getJavadoc() { + return ModelGeneratorUtil.javadoc(type.getEObject().getDefinition(), type.getEObject().getReferences(), getVersion()); + } + @Override + public String getRosettaName() { + return type.getName(); + } + @Override + public String getVersion() { + return type.getEObject().getModel().getVersion(); } - public RDataType getRType() { - return type; + @Override + public Collection getOwnProperties() { + initializeProperties(); + return ownProperties.values(); + } + @Override + public Collection getAllProperties() { + initializeProperties(); + return allProperties.values(); + } + private void initializeProperties() { + if (ownProperties == null) { + RJavaPojoInterface superPojo = getSuperPojo(); + if (superPojo == null) { + allProperties = new LinkedHashMap<>(); + } else { + superPojo.initializeProperties(); + allProperties = new LinkedHashMap<>(superPojo.allProperties); + } + ownProperties = new LinkedHashMap<>(); + type.getOwnAttributes().forEach(attr -> { + String name = attr.getName(); + JavaType type = typeTranslator.toMetaJavaType(attr); + addPropertyIfNecessary(name, type, ModelGeneratorUtil.javadoc(attr.getDefinition(), attr.getDocReferences(), null), attr.getRMetaAnnotatedType().hasMetaAttribute("id") ? AttributeMeta.GLOBAL_KEY_FIELD : null, attr.getRMetaAnnotatedType().hasMetaAttribute("location")); + }); + if (type.hasMetaAttribute("key")) { + JavaType metaFieldsType = type.hasMetaAttribute("template") ? typeUtil.META_AND_TEMPLATE_FIELDS : typeUtil.META_FIELDS; + addPropertyIfNecessary("meta", metaFieldsType, null, null, false); + } + } + } + private void addPropertyIfNecessary(String name, JavaType type, String javadoc, AttributeMeta meta, boolean hasLocation) { + JavaPojoProperty parentProperty = allProperties.get(name); + if (parentProperty == null) { + JavaPojoProperty newProperty = new JavaPojoProperty( + name, + name, + type, + javadoc, + meta, + hasLocation); + ownProperties.put(name, newProperty); + allProperties.put(name, newProperty); + } else { + JavaType parentType = parentProperty.getType(); + if (!type.equals(parentType)) { + String compatibilityName; + if (type.isSubtypeOf(parentType)) { + // Specialize existing property => reuse getter of parent + compatibilityName = parentProperty.getName(); + } else { + // Incompatible specialization => need new getter + compatibilityName = getIncompatiblePropertyName(name, parentType, type); + } + JavaPojoProperty newProperty = parentProperty.specialize(compatibilityName, type, javadoc, meta, hasLocation); + ownProperties.put(name, newProperty); + allProperties.put(name, newProperty); + } + } + } + private String getIncompatiblePropertyName(String propertyName, JavaType parentType, JavaType specializedType) { + if (typeUtil.isList(parentType) && typeUtil.isList(specializedType)) { + // List to list + return getIncompatiblePropertyName(propertyName, typeUtil.getItemType(parentType), typeUtil.getItemType(specializedType)); + } else if (typeUtil.isList(parentType)) { + // List to single + JavaType parentItemType = typeUtil.getItemType(parentType); + if (parentItemType.equals(specializedType)) { + return propertyName + "OverriddenAsSingle"; + } + return propertyName + "OverriddenAsSingle" + specializedType.getSimpleName(); + } else { + // Type to other type + return propertyName + "OverriddenAs" + specializedType.getSimpleName(); + } } @Override public boolean isSubtypeOf(JavaType other) { - //TODO: is this first check needed? - if (other instanceof JavaPrimitiveType) { - return false; - } - if (ROSETTA_MODEL_OBJECT.isSubtypeOf(other)) { + // TODO: also check other interfaces + if (typeUtil.ROSETTA_MODEL_OBJECT.isSubtypeOf(other)) { return true; } if (other instanceof RJavaPojoInterface) { @@ -64,24 +154,35 @@ public boolean isSubtypeOf(JavaType other) { public String getSimpleName() { return type.getName(); } - - @Override - public JavaClass getSuperclassDeclaration() { - return JavaClass.OBJECT; - } @Override - public JavaClass getSuperclass() { - return getSuperclassDeclaration(); + public RJavaPojoInterface getSuperPojo() { + if (superPojo == null) { + RDataType superType = type.getSuperType(); + if (superType != null) { + superPojo = new RJavaPojoInterface(superType, typeSystem, typeTranslator, typeUtil); + } + } + return superPojo; } @Override public List> getInterfaceDeclarations() { - RDataType superType = type.getSuperType(); - if (superType != null) { - return Collections.singletonList(new RJavaPojoInterface(superType, typeSystem)); + List> interfaces = new ArrayList<>(); + + JavaClass superPojo = getSuperPojo(); + if (superPojo == null) { + interfaces.add(typeUtil.ROSETTA_MODEL_OBJECT); + } else { + interfaces.add(superPojo); } - return Collections.singletonList(ROSETTA_MODEL_OBJECT); + if (type.hasMetaAttribute("key")) { + interfaces.add(typeUtil.GLOBAL_KEY); + } + if (type.hasMetaAttribute("template")) { + interfaces.add(typeUtil.TEMPLATABLE); + } + return interfaces; } @Override @@ -89,24 +190,6 @@ public List> getInterfaces() { return getInterfaceDeclarations(); } - @Override - public boolean extendsDeclaration(JavaTypeDeclaration other) { - if (other instanceof JavaClass) { - return this.isSubtypeOf((JavaClass)other); - } - return false; - } - - @Override - public boolean isFinal() { - return false; - } - - @Override - public Class loadClass(ClassLoader classLoader) throws ClassNotFoundException { - return Class.forName(getCanonicalName().toString(), true, classLoader).asSubclass(RosettaModelObject.class); - } - @Override public DottedPath getPackageName() { return type.getNamespace(); diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/RJavaReferenceWithMeta.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/RJavaReferenceWithMeta.java index dd55ac2cf..1ca8326bb 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/RJavaReferenceWithMeta.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/RJavaReferenceWithMeta.java @@ -1,9 +1,10 @@ package com.regnosys.rosetta.generator.java.types; +import java.util.Collection; import java.util.List; -import com.rosetta.model.lib.RosettaModelObject; import com.rosetta.model.lib.meta.ReferenceWithMeta; +import com.rosetta.model.lib.process.AttributeMeta; import com.rosetta.util.DottedPath; import com.rosetta.util.types.JavaClass; import com.rosetta.util.types.JavaParameterizedType; @@ -43,33 +44,9 @@ public String getSimpleName() { return "ReferenceWithMeta" + valueType.getSimpleName(); } - @Override - public JavaTypeDeclaration getSuperclassDeclaration() { - return JavaClass.OBJECT; - } - @Override public List> getInterfaceDeclarations() { - return List.of(javaTypeUtil.ROSETTA_MODEL_OBJECT, javaTypeUtil.FIELD_WITH_META); - - } - - @Override - public boolean extendsDeclaration(JavaTypeDeclaration other) { - if (other instanceof JavaClass) { - return this.isSubtypeOf((JavaClass)other); - } - return false; - } - - @Override - public boolean isFinal() { - return false; - } - - @Override - public Class loadClass(ClassLoader classLoader) throws ClassNotFoundException { - return Class.forName(getCanonicalName().toString(), true, classLoader).asSubclass(RosettaModelObject.class); + return List.of(javaTypeUtil.ROSETTA_MODEL_OBJECT, javaTypeUtil.REFERENCE_WITH_META); } @Override @@ -79,8 +56,16 @@ public DottedPath getPackageName() { @Override public List> getInterfaces() { - return List.of(javaTypeUtil.ROSETTA_MODEL_OBJECT,referenceWithMetaParameterisedType); - + return List.of(javaTypeUtil.ROSETTA_MODEL_OBJECT, referenceWithMetaParameterisedType); } + @Override + public Collection getOwnProperties() { + return List.of( + new JavaPojoProperty("value", "value", valueType, null, null, false), + new JavaPojoProperty("globalReference", "globalReference", javaTypeUtil.STRING, null, AttributeMeta.META, false), + new JavaPojoProperty("externalReference", "externalReference", javaTypeUtil.STRING, null, AttributeMeta.META, false), + new JavaPojoProperty("reference", "reference", javaTypeUtil.REFERENCE, null, null, false) + ); + } } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/RJavaWithMetaValue.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/RJavaWithMetaValue.java index c9005a57b..d4e414644 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/RJavaWithMetaValue.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/types/RJavaWithMetaValue.java @@ -1,13 +1,13 @@ package com.regnosys.rosetta.generator.java.types; -import com.rosetta.model.lib.RosettaModelObject; -import com.rosetta.util.types.JavaClass; +import java.util.Collection; +import java.util.Collections; + +import com.regnosys.rosetta.generator.java.util.ModelGeneratorUtil; import com.rosetta.util.types.JavaReferenceType; -public abstract class RJavaWithMetaValue extends JavaClass{ +public abstract class RJavaWithMetaValue extends JavaPojoInterface { protected final JavaReferenceType valueType; - - public RJavaWithMetaValue(JavaReferenceType valueType) { this.valueType = valueType; @@ -18,8 +18,27 @@ public JavaReferenceType getValueType() { } @Override - public JavaClass getSuperclass() { - return JavaClass.OBJECT; + public Collection getAllProperties() { + return getOwnProperties(); + } + + @Override + public JavaPojoInterface getSuperPojo() { + return null; + } + + @Override + public String getJavadoc() { + return ModelGeneratorUtil.javadoc(null, Collections.emptyList(), "1"); } + @Override + public String getRosettaName() { + return getSimpleName(); + } + + @Override + public String getVersion() { + return "0.0.0"; + } } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/util/ModelGeneratorUtil.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/util/ModelGeneratorUtil.xtend index 36b4f98a8..cedef5a80 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/util/ModelGeneratorUtil.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/util/ModelGeneratorUtil.xtend @@ -13,7 +13,7 @@ class ModelGeneratorUtil { «javadoc(named, null)» ''' - static def javadoc(RosettaNamed named, String version) { + private static def javadoc(RosettaNamed named, String version) { val definition = if (named instanceof RosettaDefinable) named.definition else "" val docRef = if (named instanceof References) named.references else emptyList javadoc(definition, docRef, version) @@ -21,7 +21,7 @@ class ModelGeneratorUtil { static def javadoc(String definition, List docRef, String version) { return if (definition === null && docRef.isEmpty && version === null) - '' + null else ''' /** diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/validator/ValidatorGenerator.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/validator/ValidatorGenerator.xtend index e9de6a8d6..158e1a189 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/validator/ValidatorGenerator.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/validator/ValidatorGenerator.xtend @@ -32,6 +32,7 @@ import com.rosetta.util.types.generated.GeneratedJavaClass import com.rosetta.model.lib.validation.ElementValidationResult import com.regnosys.rosetta.types.RAttribute import com.regnosys.rosetta.RosettaEcoreUtil +import com.regnosys.rosetta.types.RCardinality class ValidatorGenerator { @Inject extension ImportManagerExtension @@ -68,7 +69,7 @@ class ValidatorGenerator { «ModelSymbolId» modelSymbolId = new «ModelSymbolId»(packageName, simpleName); «List»<«AttributeValidation»> attributeValidations = new «ArrayList»<>(); - «FOR attribute : type.allNonOverridenAttributes» + «FOR attribute : type.allAttributes» attributeValidations.add(validate«attribute.name.toFirstUpper»(«attribute.attributeValue», path)); «ENDFOR» @@ -80,7 +81,7 @@ class ValidatorGenerator { return new «TypeValidation»(modelSymbolId, attributeValidations, conditionValidations); } - «FOR attribute : type.allNonOverridenAttributes» + «FOR attribute : type.allAttributes» public «AttributeValidation» validate«attribute.name.toFirstUpper»(«attribute.toJavaType» atr, «RosettaPath» path) { «List»<«ElementValidationResult»> validationResults = new «ArrayList»<>(); «val cardinalityCheck = checkCardinality(attribute)» @@ -114,13 +115,13 @@ class ValidatorGenerator { } private def StringConcatenationClient checkCardinality(RAttribute attr) { - if (attr.cardinality.minBound === 0 && attr.cardinality.unboundedRight) { + if (attr.cardinality == RCardinality.UNBOUNDED) { null } else { if (attr.isMulti) { - '''«method(ValidationUtil, "checkCardinality")»("«attr.name.toString»", atr == null ? 0 : atr.size(), «attr.cardinality.minBound», «attr.cardinality.max.orElse(0)» , path)''' + '''«method(ValidationUtil, "checkCardinality")»("«attr.name.toString»", atr == null ? 0 : atr.size(), «attr.cardinality.min», «attr.cardinality.max.orElse(0)» , path)''' } else { - '''«method(ValidationUtil, "checkCardinality")»("«attr.name.toString»", atr != null ? 1 : 0, «attr.cardinality.minBound», «attr.cardinality.max.orElse(0)», path)''' + '''«method(ValidationUtil, "checkCardinality")»("«attr.name.toString»", atr != null ? 1 : 0, «attr.cardinality.min», «attr.cardinality.max.orElse(0)», path)''' } } } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/scoping/RosettaScopeProvider.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/scoping/RosettaScopeProvider.xtend index 34e53fc37..972bd0f93 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/scoping/RosettaScopeProvider.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/scoping/RosettaScopeProvider.xtend @@ -48,14 +48,12 @@ import org.eclipse.emf.ecore.EObject import org.eclipse.emf.ecore.EReference import org.eclipse.xtext.EcoreUtil2 import org.eclipse.xtext.naming.QualifiedName -import org.eclipse.xtext.resource.EObjectDescription import org.eclipse.xtext.resource.IEObjectDescription import org.eclipse.xtext.scoping.IScope import org.eclipse.xtext.scoping.Scopes import org.eclipse.xtext.scoping.impl.FilteringScope import org.eclipse.xtext.scoping.impl.ImportNormalizer import org.eclipse.xtext.scoping.impl.ImportedNamespaceAwareLocalScopeProvider -import org.eclipse.xtext.scoping.impl.SimpleScope import org.eclipse.xtext.util.Strings import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -65,7 +63,7 @@ import static com.regnosys.rosetta.rosetta.expression.ExpressionPackage.Literals import static com.regnosys.rosetta.rosetta.simple.SimplePackage.Literals.* import static extension com.regnosys.rosetta.types.RMetaAnnotatedType.withEmptyMeta -import com.regnosys.rosetta.rosetta.RosettaFeature +import com.regnosys.rosetta.rosetta.simple.Attribute /** * This class contains custom scoping description. @@ -217,7 +215,7 @@ class RosettaScopeProvider extends ImportedNamespaceAwareLocalScopeProvider { if (context instanceof RosettaExternalRegularAttribute) { val classRef = (context.eContainer as RosettaExternalClass).typeRef if (classRef instanceof Data) - return Scopes.scopeFor(classRef.buildRDataType.allNonOverridenAttributes.map[EObject]) + return Scopes.scopeFor(classRef.buildRDataType.allAttributes.map[EObject].filter(Attribute)) } return IScope.NULLSCOPE } @@ -255,10 +253,8 @@ class RosettaScopeProvider extends ImportedNamespaceAwareLocalScopeProvider { } } return IScope.NULLSCOPE - } } - // LOGGER.warn('''No scope defined for «context.class.simpleName» referencing «reference.name».''') return defaultScope(context, reference) } catch (Exception e) { @@ -378,15 +374,7 @@ class RosettaScopeProvider extends ImportedNamespaceAwareLocalScopeProvider { } } - val List foo = metaReceiverType.allFeatures(receiver).toList - - val List allPosibilities = newArrayList - allPosibilities.addAll( - foo - .map[new EObjectDescription(QualifiedName.create(name), it, null)] - ) - - return new SimpleScope(allPosibilities) + return Scopes.scopeFor(metaReceiverType.allFeatures(receiver)) } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RAttribute.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RAttribute.java index 7333f36e8..806f9cb0a 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RAttribute.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RAttribute.java @@ -16,43 +16,50 @@ package com.regnosys.rosetta.types; +import java.util.ArrayList; import java.util.List; import java.util.Objects; import com.regnosys.rosetta.rosetta.RosettaDocReference; import com.regnosys.rosetta.rosetta.RosettaRule; import com.regnosys.rosetta.rosetta.simple.Attribute; -import com.regnosys.rosetta.utils.PositiveIntegerInterval; public class RAttribute implements RAssignedRoot { + private final boolean isOverride; private final String name; private final String definition; private final List docReferences; private final RMetaAnnotatedType rMetaAnnotatedType; - private final PositiveIntegerInterval cardinality; - private final boolean isMeta; + private final RCardinality cardinality; private final RosettaRule ruleReference; private final Attribute origin; + + private final RObjectFactory rObjectFactory; + private RAttribute parentAttribute = null; - public RAttribute(String name, String definition, List docReferences, RMetaAnnotatedType rMetaAnnotatedType, PositiveIntegerInterval cardinality, RosettaRule ruleReference, Attribute origin) { - this(name, definition, docReferences, rMetaAnnotatedType, cardinality, false, ruleReference, origin); - } - public RAttribute(String name, String definition, List docReferences, RMetaAnnotatedType rMetaAnnotatedType, PositiveIntegerInterval cardinality, boolean isMeta, RosettaRule ruleReference, Attribute origin) { + public RAttribute(boolean isOverride, String name, String definition, List docReferences, + RMetaAnnotatedType rMetaAnnotatedType, RCardinality cardinality, + RosettaRule ruleReference, Attribute origin, RObjectFactory rObjectFactory) { + this.isOverride = isOverride; this.name = name; this.definition = definition; this.docReferences = docReferences; this.rMetaAnnotatedType = rMetaAnnotatedType; this.cardinality = cardinality; - this.isMeta = isMeta; this.ruleReference = ruleReference; this.origin = origin; + this.rObjectFactory = rObjectFactory; + } + + public boolean isOverride() { + return isOverride; } @Override - public String getName() { + public String getName() { return name; } - + public Attribute getEObject() { return origin; } @@ -60,31 +67,48 @@ public Attribute getEObject() { public RMetaAnnotatedType getRMetaAnnotatedType() { return rMetaAnnotatedType; } - + @Override public boolean isMulti() { - return cardinality.getMax().map(m -> m > 1).orElse(true); + return cardinality.isMulti(); } - - public PositiveIntegerInterval getCardinality() { + + public RCardinality getCardinality() { return cardinality; } - + public String getDefinition() { return definition; } - + public List getDocReferences() { - return docReferences; + RAttribute p = getParentAttribute(); + List parentDocRefs; + if (p == null || (parentDocRefs = p.getDocReferences()).isEmpty()) { + return docReferences; + } + List docRefs = new ArrayList<>(docReferences.size() + parentDocRefs.size()); + docRefs.addAll(docReferences); + docRefs.addAll(parentDocRefs); + return docRefs; } - public RosettaRule getRuleReference() { - return ruleReference; + if (ruleReference != null) { + return ruleReference; + } + RAttribute p = getParentAttribute(); + if (p != null) { + return p.getRuleReference(); + } + return null; } - public boolean isMeta() { - return isMeta; + public RAttribute getParentAttribute() { + if (parentAttribute == null && origin.isOverride()) { + parentAttribute = rObjectFactory.buildRAttributeOfParent(origin); + } + return parentAttribute; } @Override @@ -102,8 +126,7 @@ public boolean equals(Object obj) { return false; RAttribute other = (RAttribute) obj; return Objects.equals(definition, other.definition) && Objects.equals(cardinality, other.cardinality) - && Objects.equals(name, other.name) - && Objects.equals(rMetaAnnotatedType, other.rMetaAnnotatedType) + && Objects.equals(name, other.name) && Objects.equals(rMetaAnnotatedType, other.rMetaAnnotatedType) && Objects.equals(origin, other.origin); } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RCardinality.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RCardinality.java new file mode 100644 index 000000000..c38acd659 --- /dev/null +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RCardinality.java @@ -0,0 +1,120 @@ +package com.regnosys.rosetta.types; + +import java.util.Objects; +import java.util.Optional; + +import com.regnosys.rosetta.utils.PositiveIntegerInterval; + +public class RCardinality { + /** + * (1..1) + */ + public static RCardinality SINGLE = bounded(1, 1); + /** + * (0..1) + */ + public static RCardinality OPTIONAL = bounded(0, 1); + /** + * (0..*) + */ + public static RCardinality UNBOUNDED = unbounded(0); + + private final PositiveIntegerInterval interval; + + private RCardinality(PositiveIntegerInterval interval) { + this.interval = interval; + } + public static RCardinality bounded(int min, int max) { + if (max < min) { + // Invalid cardinality + return new RCardinality(null) { + @Override + public int getMin() { + return min; + } + @Override + public boolean isMulti() { + return max > 1; + } + @Override + public boolean isOptional() { + return min == 0; + } + + @Override + public boolean includes(int x) { + return false; + } + @Override + public boolean includes(RCardinality other) { + return false; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append('('); + builder.append(min); + builder.append(".."); + builder.append(max); + builder.append(')'); + return builder.toString(); + } + }; + } + return new RCardinality(PositiveIntegerInterval.bounded(min, max)); + } + public static RCardinality unbounded(int min) { + return new RCardinality(PositiveIntegerInterval.boundedLeft(min)); + } + + public int getMin() { + return interval.getMinBound(); + } + public Optional getMax() { + return interval.getMax(); + } + public boolean isMulti() { + return interval.getMax().map(m -> m > 1).orElse(true); + } + public boolean isOptional() { + return interval.getMinBound() == 0; + } + + public boolean includes(int x) { + return interval.includes(x); + } + public boolean includes(RCardinality other) { + return interval.includes(other.interval); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append('('); + builder.append(interval.getMinBound()); + builder.append(".."); + interval.getMax().ifPresentOrElse( + b -> builder.append(b), + () -> builder.append('*')); + builder.append(')'); + return builder.toString(); + } + + @Override + public int hashCode() { + return Objects.hash(interval); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RCardinality other = (RCardinality) obj; + return Objects.equals(interval, other.interval); + } +} diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RDataType.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RDataType.java index 3d4d00a6a..558818447 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RDataType.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RDataType.java @@ -26,7 +26,6 @@ import java.util.Objects; import java.util.stream.Collectors; -import com.google.common.collect.Streams; import com.regnosys.rosetta.rosetta.simple.Data; import com.regnosys.rosetta.utils.ModelIdProvider; import com.rosetta.model.lib.ModelSymbolId; @@ -37,45 +36,50 @@ public class RDataType extends RType implements RObject { private RDataType superType = null; private ModelSymbolId symbolId = null; private List ownAttributes = null; + private List metaAttributes = null; private final ModelIdProvider modelIdProvider; private final RObjectFactory objectFactory; - - // TODO: remove this hack - private List additionalAttributes = null; + private final RosettaTypeProvider typeProvider; - public RDataType(final Data data, final ModelIdProvider modelIdProvider, final RObjectFactory objectFactory) { + public RDataType(final Data data, final ModelIdProvider modelIdProvider, final RObjectFactory objectFactory, final RosettaTypeProvider typeProvider) { super(); this.data = data; this.modelIdProvider = modelIdProvider; this.objectFactory = objectFactory; - } - // TODO: remove this hack - public RDataType(final Data data, final ModelIdProvider modelIdProvider, final RObjectFactory objectFactory, final List additionalAttributes) { - this(data, modelIdProvider, objectFactory); - this.additionalAttributes = additionalAttributes; + this.typeProvider = typeProvider; } @Override public Data getEObject() { - return this.data; + return data; } @Override public ModelSymbolId getSymbolId() { - if (this.symbolId == null) { - this.symbolId = modelIdProvider.getSymbolId(data);; + if (symbolId == null) { + symbolId = modelIdProvider.getSymbolId(data);; + } + return symbolId; + } + + public List getMetaAttributes() { + if (metaAttributes == null) { + metaAttributes = typeProvider.getRMetaAttributes(data.getAnnotations()); } - return this.symbolId; + return metaAttributes; + } + public boolean hasMetaAttribute(String name) { + return getMetaAttributes().stream().anyMatch(m -> m.getName().equals(name)); } public RDataType getSuperType() { if (data.hasSuperType()) { - if (this.superType == null) { - this.superType = new RDataType(data.getSuperType(), modelIdProvider, objectFactory); + if (superType == null) { + superType = new RDataType(data.getSuperType(), modelIdProvider, objectFactory, typeProvider); } - return this.superType; + return superType; } return null; } @@ -101,15 +105,12 @@ private void doGetAllSuperTypes(RDataType current, LinkedHashSet supe } /** - * Get a list of the attributes defined in this data type. This does not include attributes of any super types. + * Get a list of the attributes defined in this data type. This does not include attributes of any super types, + * except if the attribute is overridden by this data type. */ public List getOwnAttributes() { if (ownAttributes == null) { - if (additionalAttributes != null) { - this.ownAttributes = Streams.concat(additionalAttributes.stream(), data.getAttributes().stream().map(attr -> objectFactory.buildRAttribute(attr))).collect(Collectors.toList()); - } else { - this.ownAttributes = data.getAttributes().stream().map(attr -> objectFactory.buildRAttribute(attr)).collect(Collectors.toList()); - } + ownAttributes = data.getAttributes().stream().map(s -> objectFactory.buildRAttribute(s)).collect(Collectors.toList()); } return ownAttributes; } @@ -118,20 +119,11 @@ public List getOwnAttributes() { * Get a list of all attributes of this data type, including all attributes of its super types. * * The list starts with the attributes of the top-most super type, and ends with the attributes of itself. + * Attribute overrides replace their respective parent attributes, respecting the original order. */ - public List getAllAttributes() { - return getAllSuperTypes().stream().flatMap(s -> s.getOwnAttributes().stream()).collect(Collectors.toList()); - } - - /** - * Get an ordered collection of all attributes of this data type, including all attributes of its super types. - * If multiple attributes have the same name, only the last one is kept. - * - * The collection starts with the attributes of the top-most super type, and ends with the attributes of itself. - */ - public Collection getAllNonOverridenAttributes() { + public Collection getAllAttributes() { Map result = new LinkedHashMap<>(); - getAllAttributes().stream().forEach(a -> result.put(a.getName(), a)); + getAllSuperTypes().stream().flatMap(s -> s.getOwnAttributes().stream()).forEach(a -> result.put(a.getName(), a)); return result.values(); } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RMetaAnnotatedType.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RMetaAnnotatedType.java index 5899d01c3..68f01f7aa 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RMetaAnnotatedType.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RMetaAnnotatedType.java @@ -34,6 +34,10 @@ public boolean hasMeta() { public List getMetaAttributes() { return metaAttributes; } + + public boolean hasMetaAttribute(String name) { + return metaAttributes.stream().anyMatch(m -> m.getName().equals(name)); + } @Override public int hashCode() { diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RObjectFactory.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RObjectFactory.java index 657d4fe2f..19ca76e1b 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RObjectFactory.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RObjectFactory.java @@ -21,17 +21,16 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.stream.Collectors; import javax.inject.Inject; import org.eclipse.xtext.EcoreUtil2; +import com.regnosys.rosetta.RosettaEcoreUtil; import com.regnosys.rosetta.rosetta.RosettaCardinality; import com.regnosys.rosetta.rosetta.RosettaEnumeration; import com.regnosys.rosetta.rosetta.RosettaFactory; -import com.regnosys.rosetta.rosetta.RosettaMetaType; import com.regnosys.rosetta.rosetta.RosettaReport; import com.regnosys.rosetta.rosetta.RosettaRule; import com.regnosys.rosetta.rosetta.expression.ExpressionFactory; @@ -46,7 +45,6 @@ import com.regnosys.rosetta.rosetta.simple.SimpleFactory; import com.regnosys.rosetta.utils.ExternalAnnotationUtil; import com.regnosys.rosetta.utils.ModelIdProvider; -import com.regnosys.rosetta.utils.PositiveIntegerInterval; public class RObjectFactory { @Inject @@ -59,6 +57,8 @@ public class RObjectFactory { private ModelIdProvider modelIdProvider; @Inject private ExternalAnnotationUtil externalAnnotationUtil; + @Inject + private RosettaEcoreUtil ecoreUtil; public RFunction buildRFunction(Function function) { return new RFunction( @@ -73,10 +73,9 @@ public RFunction buildRFunction(Function function) { function.getAnnotations()); } - // TODO: should be private - public RAttribute createArtificialAttribute(String name, RType type, boolean isMulti) { - RMetaAnnotatedType rAnnotatedType = new RMetaAnnotatedType(type, List.of()); - return new RAttribute(name, null, Collections.emptyList(), rAnnotatedType, isMulti ? PositiveIntegerInterval.boundedLeft(0) : PositiveIntegerInterval.bounded(0, 1), null, null); + private RAttribute createArtificialAttribute(String name, RType type, boolean isMulti) { + RMetaAnnotatedType rAnnotatedType = RMetaAnnotatedType.withEmptyMeta(type); + return new RAttribute(false, name, null, Collections.emptyList(), rAnnotatedType, isMulti ? RCardinality.UNBOUNDED : RCardinality.OPTIONAL, null, null, this); } public RFunction buildRFunction(RosettaRule rule) { RType inputRType = typeSystem.typeCallToRType(rule.getInput()); @@ -137,7 +136,7 @@ public RFunction buildRFunction(RosettaReport report) { } private List generateReportOperations(RDataType reportDataType, Map attributeToRuleMap, Attribute inputAttribute, List assignPath) { - Collection attributes = reportDataType.getAllNonOverridenAttributes(); + Collection attributes = reportDataType.getAllAttributes(); List operations = new ArrayList<>(); for (RAttribute attribute : attributes) { @@ -171,17 +170,37 @@ private ROperation generateOperationForRuleReference(Attribute inputAttribute, R return new ROperation(ROperationType.SET, pathHead, pathTail, symbolRef); } - - public RAttribute buildRAttribute(Attribute attribute) { - RMetaAnnotatedType rAnnotatedType = typeProvider.getRTypeOfSymbol(attribute); - boolean isMeta = attribute.getTypeCall().getType() instanceof RosettaMetaType; - PositiveIntegerInterval card = new PositiveIntegerInterval( - attribute.getCard().getInf(), - attribute.getCard().isUnbounded() ? Optional.empty() : Optional.of(attribute.getCard().getSup())); - RosettaRuleReference ruleRef = attribute.getRuleReference(); - - return new RAttribute(attribute.getName(), attribute.getDefinition(), attribute.getReferences(), rAnnotatedType, - card, isMeta, ruleRef != null ? ruleRef.getReportingRule() : null, attribute); + + public RAttribute buildRAttribute(Attribute attr) { + RMetaAnnotatedType rAnnotatedType = typeProvider.getRTypeOfFeature(attr, null); + RCardinality card = buildRCardinality(attr.getCard()); + RosettaRuleReference ruleRef = attr.getRuleReference(); + + return new RAttribute(attr.isOverride(), attr.getName(), attr.getDefinition(), attr.getReferences(), rAnnotatedType, + card, ruleRef != null ? ruleRef.getReportingRule() : null, attr, this); + } + public RAttribute buildRAttributeOfParent(Attribute attr) { + Attribute parent = ecoreUtil.getParentAttribute(attr); + if (parent == null) { + return null; + } + return buildRAttribute(parent); + } + public RCardinality buildRCardinality(RosettaCardinality card) { + if (card.isUnbounded()) { + if (card.getInf() == 0) { + return RCardinality.UNBOUNDED; + } + return RCardinality.unbounded(card.getInf()); + } + if (card.getSup() == 1) { + if (card.getInf() == 1) { + return RCardinality.SINGLE; + } else if (card.getInf() == 0) { + return RCardinality.OPTIONAL; + } + } + return RCardinality.bounded(card.getInf(), card.getSup()); } public RShortcut buildRShortcut(ShortcutDeclaration shortcut) { @@ -206,11 +225,7 @@ public ROperation buildROperation(Operation operation) { } public RDataType buildRDataType(Data data) { - return new RDataType(data, modelIdProvider, this); - } - // TODO: remove this hack - public RDataType buildRDataType(Data data, List additionalAttributes) { - return new RDataType(data, modelIdProvider, this, additionalAttributes); + return new RDataType(data, modelIdProvider, this, typeProvider); } public RChoiceType buildRChoiceType(Choice choice) { return new RChoiceType(choice, modelIdProvider, typeProvider, this); diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/types/Rosetta.xsemantics b/rosetta-lang/src/main/java/com/regnosys/rosetta/types/Rosetta.xsemantics index 1cf0e47c4..752e8ad87 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/types/Rosetta.xsemantics +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/types/Rosetta.xsemantics @@ -253,6 +253,9 @@ auxiliary typeCallToRType(TypeCall call, RosettaInterpreterContext context) { val refersTo = t.typeCall.typeCallToRType(RosettaInterpreterContext.of(args)) new RAliasType(t.typeFunctionOfTypeAlias, args, refersTo) } + default: { + NOTHING + } } } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RosettaAuxiliary.xsemantics b/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RosettaAuxiliary.xsemantics index d669a2721..89938171d 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RosettaAuxiliary.xsemantics +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/types/RosettaAuxiliary.xsemantics @@ -31,6 +31,7 @@ import com.regnosys.rosetta.rosetta.RosettaEnumValue import com.regnosys.rosetta.utils.ModelIdProvider import com.regnosys.rosetta.types.TypeSystem import com.regnosys.rosetta.types.RChoiceType +import com.regnosys.rosetta.rosetta.simple.Attribute inject extension TypeFactory typeFactory inject extension TypeValidationUtil util @@ -100,7 +101,7 @@ auxiliary allEnumValues(RosettaEnumeration e) { } auxiliary mayBeEmpty(RDataType t) { t.allAttributes.forall[ - cardinality.minBound === 0 + cardinality.isOptional ] } @@ -143,7 +144,7 @@ auxiliary keepTypeAliasIfPossible(RType t1, RType t2, BiFunction> { public static String EXPRESSION_RTYPE_CACHE_KEY = RosettaTypeProvider.canonicalName + ".EXPRESSION_RTYPE" @@ -136,6 +137,11 @@ class RosettaTypeProvider extends RosettaExpressionSwitch getRMetaAttributesOfSymbol(RosettaSymbol symbol) { + if (symbol instanceof Attribute) { + if (symbol.isOverride) { + return (extensions.getParentAttribute(symbol).RMetaAttributesOfSymbol + symbol.annotations.RMetaAttributes).toList + } + } if (symbol instanceof Annotated) { return symbol.annotations.RMetaAttributes } @@ -143,6 +149,9 @@ class RosettaTypeProvider extends RosettaExpressionSwitch getRMetaAttributesOfFeature(RosettaFeature feature) { + if (feature instanceof RosettaSymbol) { + return feature.RMetaAttributesOfSymbol + } if (feature instanceof Annotated) { return feature.annotations.RMetaAttributes } @@ -156,7 +165,6 @@ class RosettaTypeProvider extends RosettaExpressionSwitch cycleTracker) { if (!extensions.isResolved(symbol)) { return NOTHING.withEmptyMeta diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/BigDecimalInterval.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/BigDecimalInterval.java index 17a724a09..410298ffd 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/BigDecimalInterval.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/BigDecimalInterval.java @@ -42,6 +42,7 @@ public static BigDecimalInterval unbounded() { @Override public boolean equals(Object object) { + if (this == object) return true; if (object == null) return false; if (getClass() != object.getClass()) return false; @@ -50,6 +51,8 @@ public boolean equals(Object object) { && boundEquals(getMax(), other.getMax()); } private boolean boundEquals(Optional a, Optional b) { + // When checking equality between `BigDecimal`s, we should ignore precision, + // so we check equality using `x.compareTo(y) == 0` instead. return Objects.equals(a, b) || OptionalUtil.zipWith(a, b, (x, y) -> x.compareTo(y) == 0).orElse(false); } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/DeepFeatureCallUtil.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/DeepFeatureCallUtil.java index ad5f4214c..c6f5c2c76 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/DeepFeatureCallUtil.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/DeepFeatureCallUtil.java @@ -4,12 +4,12 @@ import java.util.HashMap; import java.util.Map; -import com.regnosys.rosetta.rosetta.RosettaCardinality; import com.regnosys.rosetta.rosetta.expression.OneOfOperation; import com.regnosys.rosetta.rosetta.expression.RosettaExpression; import com.regnosys.rosetta.rosetta.expression.RosettaImplicitVariable; import com.regnosys.rosetta.rosetta.simple.Data; import com.regnosys.rosetta.types.RAttribute; +import com.regnosys.rosetta.types.RCardinality; import com.regnosys.rosetta.types.RChoiceType; import com.regnosys.rosetta.types.RDataType; import com.regnosys.rosetta.types.RType; @@ -26,11 +26,11 @@ public Map findDeepFeatureMap(RDataType type) { Map deepIntersection = null; Map result = new HashMap<>(); - Collection allNonOverridenAttributes = type.getAllNonOverridenAttributes(); - for (RAttribute attr : allNonOverridenAttributes) { + Collection allAttributes = type.getAllAttributes(); + for (RAttribute attr : allAttributes) { result.put(attr.getName(), attr); } - for (RAttribute attr : allNonOverridenAttributes) { + for (RAttribute attr : allAttributes) { RType attrType = attr.getRMetaAnnotatedType().getRType(); if (attrType instanceof RChoiceType) { @@ -40,7 +40,7 @@ public Map findDeepFeatureMap(RDataType type) { if (attrType instanceof RDataType) { RDataType attrDataType = (RDataType)attrType; attrDeepFeatureMap = findDeepFeatureMap(attrDataType); - for (RAttribute attrFeature : attrDataType.getAllNonOverridenAttributes()) { + for (RAttribute attrFeature : attrDataType.getAllAttributes()) { attrDeepFeatureMap.put(attrFeature.getName(), attrFeature); } } else { @@ -118,8 +118,9 @@ public boolean isEligibleForDeepFeatureCall(RDataType type) { // 3. Type has at least one attribute. Data data = type.getEObject(); if (data.getConditions().stream().anyMatch(cond -> isOneOfItem(cond.getExpression()))) { - if (data.getAttributes().stream().allMatch(a -> isSingularOptional(a.getCard()))) { - if (!data.getAttributes().isEmpty()) { + Collection allAttributes = type.getAllAttributes(); + if (allAttributes.stream().allMatch(a -> isSingularOptional(a.getCardinality()))) { + if (!allAttributes.isEmpty()) { return true; } } @@ -134,7 +135,7 @@ private boolean isOneOfItem(RosettaExpression expr) { } return false; } - private boolean isSingularOptional(RosettaCardinality card) { - return !card.isUnbounded() && card.getInf() == 0 && card.getSup() == 1; + private boolean isSingularOptional(RCardinality card) { + return card.equals(RCardinality.OPTIONAL); } } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/ExternalAnnotationUtil.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/ExternalAnnotationUtil.java index 0ce0f2ae7..4dfef3f95 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/ExternalAnnotationUtil.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/ExternalAnnotationUtil.java @@ -150,7 +150,7 @@ public Map getAllRuleReferencesForType(Optional T collectAllRuleReferencesForType(Optional maybeSource, RDataType type, T visitor) { // collect inline rule reference - type.getAllNonOverridenAttributes() + type.getAllAttributes() .forEach(attr -> Optional.ofNullable(attr.getRuleReference()).ifPresent(rule -> visitor.add(attr, rule))); @@ -237,7 +237,7 @@ public Map getAllReportingRules(RDataType type, Opti private void collectReportingRules(RDataType dataType, RosettaPath path, Optional ruleSource, Map visitor, Set collectedTypes) { Map attrRules = getAllRuleReferencesForType(ruleSource, dataType); - dataType.getAllNonOverridenAttributes().forEach(attr -> { + dataType.getAllAttributes().forEach(attr -> { RType attrType = attr.getRMetaAnnotatedType().getRType(); if (attrType instanceof RChoiceType) { attrType = ((RChoiceType) attrType).asRDataType(); diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/Interval.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/Interval.java index 49e164c8d..a40caf27b 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/Interval.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/Interval.java @@ -22,7 +22,7 @@ import org.apache.commons.lang3.Validate; /** - * A class representing an interval between two numbers. + * A class representing an interval between two comparable objects. * * The bounds are inclusive, an may be unbounded. The following forms are allowed: * - [min, max] @@ -30,13 +30,13 @@ * - [min, +infinity[ * - ]-infinity, +infinity[ */ -public abstract class Interval> { +public abstract class Interval> { private final Optional min; private final Optional max; public Interval(Optional min, Optional max) { if (min.isPresent() && max.isPresent()) { - Validate.isTrue(min.get().compareTo(max.get()) <= 0); + Validate.isTrue(min.get().compareTo(max.get()) <= 0, "The minimum (" + min.get() + ") must be less than the maximum (" + max.get() + ")"); } this.min = min; this.max = max; @@ -59,6 +59,24 @@ public boolean isUnboundedRight() { } public boolean includes(T x) { + if (min.map(b -> b.compareTo(x) > 0).orElse(false)) { + return false; + } + if (max.map(b -> b.compareTo(x) < 0).orElse(false)) { + return false; + } + return true; + } + public boolean includes(Interval other) { + if (min.map(b -> other.min.map(ob -> b.compareTo(ob) > 0).orElse(true)).orElse(false)) { + return false; + } + if (max.map(b -> other.max.map(ob -> b.compareTo(ob) < 0).orElse(true)).orElse(false)) { + return false; + } + return true; + } + public boolean strictlyIncludes(T x) { if (min.map(b -> b.compareTo(x) >= 0).orElse(false)) { return false; } @@ -67,11 +85,11 @@ public boolean includes(T x) { } return true; } - public boolean strictlyIncludes(T x) { - if (min.map(b -> b.compareTo(x) > 0).orElse(false)) { + public boolean strictlyIncludes(Interval other) { + if (min.map(b -> other.min.map(ob -> b.compareTo(ob) >= 0).orElse(true)).orElse(false)) { return false; } - if (max.map(b -> b.compareTo(x) < 0).orElse(false)) { + if (max.map(b -> other.max.map(ob -> b.compareTo(ob) <= 0).orElse(true)).orElse(false)) { return false; } return true; @@ -94,16 +112,14 @@ public int hashCode() { return Objects.hash(min, max); } @Override - public boolean equals(Object object) { - if (this == object) { + public boolean equals(Object obj) { + if (this == obj) return true; - } - if (getClass() != object.getClass()) { + if (obj == null) return false; - } - - Interval other = (Interval)object; - return Objects.equals(min, other.min) - && Objects.equals(max, other.max); + if (getClass() != obj.getClass()) + return false; + Interval other = (Interval) obj; + return Objects.equals(max, other.max) && Objects.equals(min, other.min); } } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/AbstractDeclarativeRosettaValidator.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/AbstractDeclarativeRosettaValidator.java index f7a25cf2d..d295cb469 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/AbstractDeclarativeRosettaValidator.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/AbstractDeclarativeRosettaValidator.java @@ -4,9 +4,12 @@ import java.util.ArrayList; import java.util.List; +import javax.inject.Inject; + import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.xtext.Action; import org.eclipse.xtext.Assignment; import org.eclipse.xtext.Keyword; @@ -20,10 +23,18 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.regnosys.rosetta.RosettaEcoreUtil; +import com.regnosys.rosetta.rosetta.RosettaNamed; +import com.regnosys.rosetta.rosetta.simple.Annotated; +import com.regnosys.rosetta.rosetta.simple.Attribute; + public abstract class AbstractDeclarativeRosettaValidator extends AbstractDeclarativeValidator { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractDeclarativeRosettaValidator.class); + @Inject + private RosettaEcoreUtil ecoreUtil; + @Override protected List getEPackages() { List result = new ArrayList(); @@ -117,4 +128,22 @@ protected INode findDirectKeyword(ICompositeNode node, String keyword) { } return null; } + + protected void checkDeprecatedAnnotation(Annotated annotated, EObject owner, EStructuralFeature ref, int index) { + if (annotated.getAnnotations().stream().anyMatch(ann -> ann.getAnnotation() != null && ann.getAnnotation().getName().equals("deprecated"))) { + String msg; + if (annotated instanceof RosettaNamed) { + msg = ((RosettaNamed)annotated).getName() + " is deprecated"; + } else { + msg = "Deprecated"; + } + warning(msg, owner, ref, index); + } else if (annotated instanceof Attribute) { + // Check if deprecated annotation is inherited + Attribute parent = ecoreUtil.getParentAttribute((Attribute) annotated); + if (parent != null) { + checkDeprecatedAnnotation(parent, owner, ref, index); + } + } + } } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/AttributeValidator.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/AttributeValidator.java new file mode 100644 index 000000000..b8e480f9c --- /dev/null +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/AttributeValidator.java @@ -0,0 +1,121 @@ +package com.regnosys.rosetta.validation; + +import javax.inject.Inject; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.validation.Check; + +import com.regnosys.rosetta.RosettaEcoreUtil; +import com.regnosys.rosetta.rosetta.RosettaCardinality; +import com.regnosys.rosetta.rosetta.RosettaRule; +import com.regnosys.rosetta.rosetta.simple.Annotation; +import com.regnosys.rosetta.rosetta.simple.Attribute; +import com.regnosys.rosetta.rosetta.simple.ChoiceOption; +import com.regnosys.rosetta.rosetta.simple.Data; +import com.regnosys.rosetta.types.RAttribute; +import com.regnosys.rosetta.types.RChoiceType; +import com.regnosys.rosetta.types.RDataType; +import com.regnosys.rosetta.types.RFunction; +import com.regnosys.rosetta.types.RMetaAnnotatedType; +import com.regnosys.rosetta.types.RObjectFactory; +import com.regnosys.rosetta.types.RType; +import com.regnosys.rosetta.types.RosettaTypeProvider; +import com.regnosys.rosetta.types.TypeSystem; + +import static com.regnosys.rosetta.rosetta.RosettaPackage.Literals.*; +import static com.regnosys.rosetta.rosetta.simple.SimplePackage.Literals.*; +import static com.regnosys.rosetta.validation.RosettaIssueCodes.*; + +public class AttributeValidator extends AbstractDeclarativeRosettaValidator { + @Inject + private RObjectFactory rObjectFactory; + @Inject + private RosettaTypeProvider typeProvider; + @Inject + private RosettaEcoreUtil ecoreUtil; + @Inject + private TypeSystem typeSystem; + + @Check + public void checkAttributeNameStartsWithLowerCase(Attribute attribute) { + if (!(attribute instanceof ChoiceOption) + && !(attribute.eContainer() instanceof Annotation) + && Character.isUpperCase(attribute.getName().charAt(0))) { + warning("Attribute name should start with a lower case", attribute, ROSETTA_NAMED__NAME, INVALID_CASE); + } + } + + @Check + public void checkAttribute(Attribute ele) { + RType attrType = typeProvider.getRTypeOfSymbol(ele).getRType(); + + if (attrType instanceof RChoiceType) { + attrType = ((RChoiceType)attrType).asRDataType(); + } + if (attrType instanceof RDataType) { + RDataType attrDataType = (RDataType) attrType; + if (ecoreUtil.hasReferenceAnnotation(ele) + && !(attrDataType.hasMetaAttribute("key") || attrDataType.getAllSuperTypes().stream().anyMatch(st -> st.hasMetaAttribute("key")))) { + // TODO: make error instead + warning(attrDataType.getName() + " must be annotated with [metadata key] as reference annotation is used", ele, + ROSETTA_TYPED__TYPE_CALL); + } + } + } + + @Check + public void checkAttributeOverride(Attribute attr) { + if (attr.isOverride()) { + EObject container = attr.eContainer(); + if (!(container instanceof Data)) { + error("You can only override the attribute of a type", attr, ATTRIBUTE__OVERRIDE); + } else { + RAttribute attribute = rObjectFactory.buildRAttribute(attr); + RAttribute parentAttribute = attribute.getParentAttribute(); + if (parentAttribute != null) { + // If parent is deprecated, mark name of attribute as deprecated + checkDeprecatedAnnotation(parentAttribute.getEObject(), attr, ROSETTA_NAMED__NAME, INSIGNIFICANT_INDEX); + // Check types + RMetaAnnotatedType overriddenType = attribute.getRMetaAnnotatedType(); + RMetaAnnotatedType parentAttrType = parentAttribute.getRMetaAnnotatedType(); + if (!typeSystem.isSubtypeOf(overriddenType, parentAttrType)) { + error("The overridden type should be a subtype of the parent type " + parentAttrType, attr, ROSETTA_TYPED__TYPE_CALL); + } + // Check cardinality + if (!parentAttribute.getCardinality().includes(attribute.getCardinality())) { + error("Cardinality may not be broader than the cardinality of the parent attribute " + parentAttribute.getCardinality(), attr, ATTRIBUTE__CARD); + } + // Check inherited rule reference is compatible + if (attr.getRuleReference() == null) { + RosettaRule r = parentAttribute.getRuleReference(); + if (r != null) { + RFunction rule = rObjectFactory.buildRFunction(r); + + // check type + RMetaAnnotatedType ruleType = rule.getOutput().getRMetaAnnotatedType(); + if (!typeSystem.isSubtypeOf(ruleType, overriddenType)) { + error("The overridden type is incompatible with the inherited rule reference `" + r.getName() + "`. Either change the type or override the rule reference", attr, ROSETTA_TYPED__TYPE_CALL); + } + + // check cardinality + if (!attribute.isMulti() && rule.getOutput().isMulti()) { + error("Cardinality is incompatible with the inherited rule reference `" + r.getName() + "`. Either change the cardinality or override the rule reference", attr, ATTRIBUTE__CARD); + } + } + } + } else { + error("Attribute " + attr.getName() + " does not exist in supertype", attr, ROSETTA_NAMED__NAME); + } + } + } + } + + @Check + public void checkCardinality(RosettaCardinality card) { + if (!card.isUnbounded()) { + if (card.getInf() > card.getSup()) { + error("The upper bound must be greater than the lower bound", card, null); + } + } + } +} diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/ChoiceValidator.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/ChoiceValidator.java index 54ecfd214..5c61709ae 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/ChoiceValidator.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/ChoiceValidator.java @@ -18,7 +18,6 @@ import com.regnosys.rosetta.types.RChoiceType; import com.regnosys.rosetta.types.RMetaAnnotatedType; import com.regnosys.rosetta.types.RObjectFactory; -import com.regnosys.rosetta.types.RType; import static com.regnosys.rosetta.rosetta.RosettaPackage.Literals.*; diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/EnumValidator.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/EnumValidator.java index e815d1d5e..2005c764f 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/EnumValidator.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/EnumValidator.java @@ -10,16 +10,23 @@ import org.eclipse.xtext.validation.Check; +import com.regnosys.rosetta.RosettaEcoreUtil; import com.regnosys.rosetta.rosetta.RosettaEnumValue; import com.regnosys.rosetta.rosetta.RosettaEnumeration; -import com.regnosys.rosetta.types.REnumType; -import com.regnosys.rosetta.types.RObjectFactory; import static com.regnosys.rosetta.rosetta.RosettaPackage.Literals.*; +import static com.regnosys.rosetta.validation.RosettaIssueCodes.*; public class EnumValidator extends AbstractDeclarativeRosettaValidator { @Inject - private RObjectFactory rObjectFactory; + private RosettaEcoreUtil ecoreUtil; + + @Check + public void checkEnumNameIsCapitalized(RosettaEnumeration enumeration) { + if (Character.isLowerCase(enumeration.getName().charAt(0))) { + warning("Enumeration name should start with a capital", ROSETTA_NAMED__NAME, INVALID_CASE); + } + } @Check public void checkCyclicExtensions(RosettaEnumeration enumeration) { @@ -52,12 +59,11 @@ private boolean hasCyclicExtension(RosettaEnumeration current, List usedNames = new HashSet<>(); - if (t.getParent() != null) { - t.getParent().getAllEnumValues().forEach(v -> usedNames.add(v.getName())); + if (enumeration.getParent() != null) { + ecoreUtil.getAllEnumValues(enumeration.getParent()).forEach(v -> usedNames.add(v.getName())); } - for (RosettaEnumValue value: t.getOwnEnumValues()) { + for (RosettaEnumValue value: enumeration.getEnumValues()) { if (!usedNames.add(value.getName())) { error("Duplicate enum value '" + value.getName() + "'", value, ROSETTA_NAMED__NAME); } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/RosettaSimpleValidator.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/RosettaSimpleValidator.xtend index f60a47cc5..9c282a6e8 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/RosettaSimpleValidator.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/RosettaSimpleValidator.xtend @@ -15,7 +15,6 @@ import com.regnosys.rosetta.rosetta.RosettaEnumeration import com.regnosys.rosetta.rosetta.RosettaExternalRegularAttribute import com.regnosys.rosetta.rosetta.RosettaExternalRuleSource import com.regnosys.rosetta.rosetta.RosettaExternalSynonymSource -import com.regnosys.rosetta.rosetta.RosettaFeatureOwner import com.regnosys.rosetta.rosetta.RosettaMapPathValue import com.regnosys.rosetta.rosetta.RosettaMapping import com.regnosys.rosetta.rosetta.RosettaModel @@ -157,9 +156,9 @@ class RosettaSimpleValidator extends AbstractDeclarativeRosettaValidator { op.args .filter(RosettaFeatureCall) - .filter[it.feature instanceof RosettaMetaType] + .filter[feature instanceof RosettaMetaType] .forEach[ - error('''«message» «it.feature.name»''', it, ROSETTA_FEATURE_CALL__FEATURE) + error('''«message» «feature.name»''', it, ROSETTA_FEATURE_CALL__FEATURE) ] op.args @@ -190,16 +189,6 @@ class RosettaSimpleValidator extends AbstractDeclarativeRosettaValidator { } } } - private def void checkDeprecatedAnnotation(Annotated annotated, EObject owner, EReference ref, int index) { - if (annotated.annotations.exists[annotation?.name == "deprecated"]) { - val msg = if (annotated instanceof RosettaNamed) { - '''«annotated.name» is deprecated''' - } else { - "Deprecated" - } - warning(msg, owner, ref, index) - } - } @Check def void checkSwitch(SwitchOperation op) { @@ -574,13 +563,6 @@ class RosettaSimpleValidator extends AbstractDeclarativeRosettaValidator { } } - @Check - def void checkClassNameStartsWithCapital(Data classe) { - if (Character.isLowerCase(classe.name.charAt(0))) { - warning("Type name should start with a capital", ROSETTA_NAMED__NAME, INVALID_CASE) - } - } - @Check def void checkConditionName(Condition condition) { if (condition.name === null && !condition.isConstraintCondition) { @@ -605,22 +587,6 @@ class RosettaSimpleValidator extends AbstractDeclarativeRosettaValidator { } } - @Check - def void checkEnumerationNameStartsWithCapital(RosettaEnumeration enumeration) { - if (Character.isLowerCase(enumeration.name.charAt(0))) { - warning("Enumeration name should start with a capital", ROSETTA_NAMED__NAME, INVALID_CASE) - } - } - - @Check - def void checkAttributeNameStartsWithLowerCase(Attribute attribute) { - val annotationAttribute = attribute.eContainer instanceof Annotation - val choiceOption = attribute instanceof ChoiceOption - if (!choiceOption && !annotationAttribute && Character.isUpperCase(attribute.name.charAt(0))) { - warning("Attribute name should start with a lower case", ROSETTA_NAMED__NAME, INVALID_CASE) - } - } - @Check def void checkConditionalExpression(RosettaConditionalExpression expr) { checkType(BOOLEAN.withEmptyMeta, expr.^if, expr, ROSETTA_CONDITIONAL_EXPRESSION__IF, INSIGNIFICANT_INDEX) @@ -646,10 +612,11 @@ class RosettaSimpleValidator extends AbstractDeclarativeRosettaValidator { @Check def checkAttributes(Data clazz) { val name2attr = HashMultimap.create - clazz.buildRDataType.allAttributes.forEach [ + clazz.buildRDataType.allAttributes.filter[!isOverride].forEach [ name2attr.put(name, it) ] - for (name : clazz.attributes.map[name]) { + // TODO: remove once `override` keyword is mandatory + for (name : clazz.attributes.filter[!isOverride].map[name]) { val attrByName = name2attr.get(name) if (attrByName.size > 1) { val attrFromClazzes = attrByName.filter[EObject.eContainer == clazz] @@ -680,26 +647,13 @@ class RosettaSimpleValidator extends AbstractDeclarativeRosettaValidator { attrFromClazzes.forEach [ childAttr | attrFromSuperClasses.forEach [ parentAttr | if (childAttr.cardinality != parentAttr.cardinality) { - error('''Overriding attribute '«name»' with cardinality («childAttr.cardRepr») must match the cardinality of the attribute it overrides («parentAttr.cardRepr»)''', + error('''Overriding attribute '«name»' with cardinality («childAttr.cardinality») must match the cardinality of the attribute it overrides («parentAttr.cardinality»)''', childAttr.EObject, ROSETTA_NAMED__NAME, CARDINALITY_ERROR) } ] ] } - private def cardRepr(RAttribute attr) '''«attr.cardinality.minBound»..«attr.cardinality.max.map[toString].orElse('*')»''' - - @Check - def checkFeatureNamesAreUnique(RosettaFeatureOwner ele) { - ele.features.groupBy[name].forEach [ k, v | - if (v.size > 1) { - v.forEach [ - error('''Duplicate feature "«k»"''', it, ROSETTA_NAMED__NAME) - ] - } - ] - } - @Check def checkFunctionElementNamesAreUnique(Function ele) { (ele.inputs + ele.shortcuts + #[ele.output]).filterNull.groupBy[name].forEach [ k, v | @@ -1043,7 +997,7 @@ class RosettaSimpleValidator extends AbstractDeclarativeRosettaValidator { binOp, ROSETTA_OPERATION__OPERATOR) } } else if (binOp.cardMod !== CardinalityModifier.NONE) { - warning('''«binOp.cardMod» is only aplicable when the sides have differing cardinality''', binOp, + warning('''«binOp.cardMod» is only applicable when the sides have differing cardinality''', binOp, ROSETTA_OPERATION__OPERATOR) } } @@ -1077,22 +1031,6 @@ class RosettaSimpleValidator extends AbstractDeclarativeRosettaValidator { } } - @Check - def checkAttribute(Attribute ele) { - var eleType = ele.RTypeOfSymbol.RType - - if (eleType instanceof RChoiceType) { - eleType = eleType.asRDataType - } - if (eleType instanceof RDataType) { - if (ele.hasReferenceAnnotation && !(hasKeyedAnnotation(eleType.EObject) || eleType.allSuperTypes.exists[EObject.hasKeyedAnnotation])) { - //TODO turn to error if it's okay - warning('''«ele.typeCall.type.name» must be annotated with [metadata key] as reference annotation is used''', - ROSETTA_TYPED__TYPE_CALL) - } - } - } - @Check def checkDispatch(Function ele) { if (ele instanceof FunctionDispatch) @@ -1162,45 +1100,44 @@ class RosettaSimpleValidator extends AbstractDeclarativeRosettaValidator { @Check def checkConstructorExpression(RosettaConstructorExpression ele) { - val rType = ele.RMetaAnnotatedType?.RType - if (rType !== null) { - var baseRType = rType.stripFromTypeAliases - if (baseRType instanceof RChoiceType) { - baseRType = baseRType.asRDataType + val rType = ele.RMetaAnnotatedType.RType + + var baseRType = rType.stripFromTypeAliases + if (baseRType instanceof RChoiceType) { + baseRType = baseRType.asRDataType + } + if (!(baseRType instanceof RDataType || baseRType instanceof RRecordType)) { + error('''Cannot construct an instance of type `«rType.name»`.''', ele.typeCall, null) + } + + val seenFeatures = newHashSet + for (pair : ele.values) { + val feature = pair.key + val expr = pair.value + if (!seenFeatures.add(feature)) { + error('''Duplicate attribute `«feature.name»`.''', pair, CONSTRUCTOR_KEY_VALUE_PAIR__KEY) } - if (!(baseRType instanceof RDataType || baseRType instanceof RRecordType)) { - error('''Cannot construct an instance of type `«rType.name»`.''', ele.typeCall, null) + checkType(feature.getRTypeOfFeature(null), expr, pair, CONSTRUCTOR_KEY_VALUE_PAIR__VALUE, INSIGNIFICANT_INDEX) + if(!cardinality.isFeatureMulti(feature) && cardinality.isMulti(expr)) { + error('''Expecting single cardinality for attribute `«feature.name»`.''', pair, + CONSTRUCTOR_KEY_VALUE_PAIR__VALUE) } - - val seenFeatures = newHashSet - for (pair : ele.values) { - val feature = pair.key - val expr = pair.value - if (!seenFeatures.add(feature)) { - error('''Duplicate attribute `«feature.name»`.''', pair, CONSTRUCTOR_KEY_VALUE_PAIR__KEY) - } - checkType(feature.getRTypeOfFeature(null), expr, pair, CONSTRUCTOR_KEY_VALUE_PAIR__VALUE, INSIGNIFICANT_INDEX) - if(!cardinality.isFeatureMulti(feature) && cardinality.isMulti(expr)) { - error('''Expecting single cardinality for attribute `«feature.name»`.''', pair, - CONSTRUCTOR_KEY_VALUE_PAIR__VALUE) - } + } + val absentAttributes = rType + .allFeatures(ele) + .filter[!seenFeatures.contains(it)] + val requiredAbsentAttributes = absentAttributes + .filter[!(it instanceof Attribute) || (it as Attribute).card.inf !== 0] + if (ele.implicitEmpty) { + if (!requiredAbsentAttributes.empty) { + error('''Missing attributes «FOR attr : requiredAbsentAttributes SEPARATOR ', '»`«attr.name»`«ENDFOR».''', ele.typeCall, null) } - val absentAttributes = rType - .allFeatures(ele) - .filter[!seenFeatures.contains(it)] - val requiredAbsentAttributes = absentAttributes - .filter[!(it instanceof Attribute) || (it as Attribute).card.inf !== 0] - if (ele.implicitEmpty) { - if (!requiredAbsentAttributes.empty) { - error('''Missing attributes «FOR attr : requiredAbsentAttributes SEPARATOR ', '»`«attr.name»`«ENDFOR».''', ele.typeCall, null) - } - if (absentAttributes.size === requiredAbsentAttributes.size) { - error('''There are no optional attributes left.''', ele, ROSETTA_CONSTRUCTOR_EXPRESSION__IMPLICIT_EMPTY) - } - } else { - if (!absentAttributes.empty) { - error('''Missing attributes «FOR attr : absentAttributes SEPARATOR ', '»`«attr.name»`«ENDFOR».«IF requiredAbsentAttributes.empty» Perhaps you forgot a `...` at the end of the constructor?«ENDIF»''', ele.typeCall, null) - } + if (absentAttributes.size === requiredAbsentAttributes.size) { + error('''There are no optional attributes left.''', ele, ROSETTA_CONSTRUCTOR_EXPRESSION__IMPLICIT_EMPTY) + } + } else { + if (!absentAttributes.empty) { + error('''Missing attributes «FOR attr : absentAttributes SEPARATOR ', '»`«attr.name»`«ENDFOR».«IF requiredAbsentAttributes.empty» Perhaps you forgot a `...` at the end of the constructor?«ENDIF»''', ele.typeCall, null) } } } @@ -1333,7 +1270,7 @@ class RosettaSimpleValidator extends AbstractDeclarativeRosettaValidator { if (attrRef.attribute.isResolved) { checkForLocation(attrRef.attribute, it) val targetType = attrRef.attribute.typeCall.typeCallToRType - val thisType = ele.RTypeOfSymbol.RType + val thisType = ele.getRTypeOfFeature(null).RType if (!thisType.isSubtypeOf(targetType)) error('''Expected address target type of '«thisType.name»' but was '«targetType?.name ?: 'null'»'«»''', it, ANNOTATION_QUALIFIER__QUAL_PATH, TYPE_ERROR) } @@ -1352,7 +1289,7 @@ class RosettaSimpleValidator extends AbstractDeclarativeRosettaValidator { ] } - def checkForLocation(Attribute attribute, AnnotationQualifier checked) { + private def checkForLocation(Attribute attribute, AnnotationQualifier checked) { var locationFound = !attribute.metadataAnnotations.filter[it.attribute?.name == "location"].empty if (!locationFound) { error('''Target of address must be annotated with metadata location''', checked, @@ -1391,7 +1328,7 @@ class RosettaSimpleValidator extends AbstractDeclarativeRosettaValidator { val funcOutputDataType = funcOutputType as RDataType val funcOutputSuperTypes = funcOutputDataType.allSuperTypes.toSet - val annotationAttributeTypes = annotationDataType.EObject.attributes.map[RTypeOfSymbol].toList + val annotationAttributeTypes = annotationDataType.allAttributes.map[RType].toList if (annotationDataType != funcOutputDataType && !funcOutputSuperTypes.contains(annotationDataType) // annotation type is a super type of output type diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/RosettaValidator.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/RosettaValidator.xtend index 912311578..25f6946ed 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/RosettaValidator.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/RosettaValidator.xtend @@ -10,7 +10,14 @@ import org.eclipse.xtext.validation.ComposedChecks * * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation */ -@ComposedChecks(validators = #[RosettaSimpleValidator, StandaloneRosettaTypingValidator, EnumValidator, ChoiceValidator]) +@ComposedChecks(validators = #[ + RosettaSimpleValidator, + StandaloneRosettaTypingValidator, + TypeValidator, + AttributeValidator, + EnumValidator, + ChoiceValidator +]) class RosettaValidator extends AbstractRosettaValidator { diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/StandaloneRosettaTypingValidator.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/StandaloneRosettaTypingValidator.java index 5bd867483..8246c665e 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/StandaloneRosettaTypingValidator.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/StandaloneRosettaTypingValidator.java @@ -159,19 +159,18 @@ public void checkReportType(Data data) { } else { current = builtins.ANY; } - for (Attribute attr: data.getAttributes()) { - RosettaRuleReference ref = attr.getRuleReference(); - if (ref != null) { - RosettaRule rule = ref.getReportingRule(); + for (RAttribute attr: rData.getOwnAttributes()) { + RosettaRule rule = attr.getRuleReference(); + if (rule != null) { RType inputType = ts.typeCallToRType(rule.getInput()); RType newCurrent = ts.meet(current, inputType); if (newCurrent.equals(builtins.NOTHING)) { - error("Rule `" + rule.getName() + "` expects an input of type `" + inputType + "`, while previous rules expect an input of type `" + current + "`.", ref, ROSETTA_RULE_REFERENCE__REPORTING_RULE); + error("Rule `" + rule.getName() + "` expects an input of type `" + inputType + "`, while previous rules expect an input of type `" + current + "`.", attr.getEObject().getRuleReference(), ROSETTA_RULE_REFERENCE__REPORTING_RULE); } else { current = newCurrent; } } else { - RType attrType = ts.stripFromTypeAliases(ts.typeCallToRType(attr.getTypeCall())); + RType attrType = ts.stripFromTypeAliases(attr.getRMetaAnnotatedType().getRType()); if (attrType instanceof RChoiceType) { attrType = ((RChoiceType) attrType).asRDataType(); } @@ -181,7 +180,7 @@ public void checkReportType(Data data) { if (!inputType.equals(builtins.NOTHING)) { RType newCurrent = ts.meet(current, inputType); if (newCurrent.equals(builtins.NOTHING)) { - error("Attribute `" + attr.getName() + "` contains rules that expect an input of type `" + inputType + "`, while previous rules expect an input of type `" + current + "`.", attr, null); + error("Attribute `" + attr.getName() + "` contains rules that expect an input of type `" + inputType + "`, while previous rules expect an input of type `" + current + "`.", attr.getEObject(), null); } else { current = newCurrent; } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/TypeValidator.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/TypeValidator.java new file mode 100644 index 000000000..65de7d2d1 --- /dev/null +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/validation/TypeValidator.java @@ -0,0 +1,103 @@ +package com.regnosys.rosetta.validation; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.inject.Inject; + +import org.eclipse.xtext.validation.Check; + +import com.regnosys.rosetta.RosettaEcoreUtil; +import com.regnosys.rosetta.rosetta.simple.Attribute; +import com.regnosys.rosetta.rosetta.simple.Choice; +import com.regnosys.rosetta.rosetta.simple.Data; + +import static com.regnosys.rosetta.rosetta.RosettaPackage.Literals.*; +import static com.regnosys.rosetta.rosetta.simple.SimplePackage.Literals.*; +import static com.regnosys.rosetta.validation.RosettaIssueCodes.*; + +public class TypeValidator extends AbstractDeclarativeRosettaValidator { + @Inject + private RosettaEcoreUtil ecoreUtil; + + @Check + public void checkTypeNameIsCapitalized(Data data) { + // TODO: also enforce on Choice's once Choice does not extend Data anymore + if (Character.isLowerCase(data.getName().charAt(0))) { + warning("Type name should start with a capital", ROSETTA_NAMED__NAME, INVALID_CASE); + } + } + + @Check + public void checkDoNotExtendChoice(Data data) { + // TODO: remove once Choice does not extend Data anymore + if (data.getSuperType() instanceof Choice) { + warning("Extending a choice type is deprecated", data, DATA__SUPER_TYPE); + } + } + + @Check + public void checkCyclicExtensions(Data data) { + Data p = data.getSuperType(); + if (p != null) { + List path = new ArrayList<>(); + path.add(data); + Set visited = new HashSet<>(); + visited.add(data); + if (hasCyclicExtension(p, path, visited)) { + String pathString = path.stream().map(e -> e.getName()).collect(Collectors.joining(" extends ")); + error("Cyclic extension: " + pathString, data, DATA__SUPER_TYPE); + } + } + } + private boolean hasCyclicExtension(Data current, List path, Set visited) { + path.add(current); + if (visited.add(current) && current.getSuperType() != null) { + if (hasCyclicExtension(current.getSuperType(), path, visited)) { + return true; + } + } else { + if (path.get(0).equals(path.get(path.size() - 1))) { + return true; + } + } + path.remove(path.size() - 1); + return false; + } + + @Check + public void checkAttributeNamesAreUnique(Data data) { + Set usedNames = new HashSet<>(); + if (data.getSuperType() != null) { + ecoreUtil.getAllAttributes(data.getSuperType()).forEach(attr -> usedNames.add(attr.getName())); + } + Set usedOverrides = new HashSet<>(); + for (Attribute attr: data.getAttributes()) { + if (!attr.isOverride()) { + if (!usedNames.add(attr.getName())) { + // TODO: make this an error + warning("Duplicate attribute '" + attr.getName() + "'. To override the type, cardinality or annotations of this attribute, use the keyword `override`.", attr, ROSETTA_NAMED__NAME); + } + } else { + if (!usedOverrides.add(attr.getName())) { + error("Duplicate attribute override for '" + attr.getName() + "'.", attr, ROSETTA_NAMED__NAME); + } + } + } + } + + @Check + public void checkAttributeOverridesShouldComeFirst(Data data) { + boolean newAttrEncountered = false; + for (Attribute attr: data.getAttributes()) { + if (!attr.isOverride()) { + newAttrEncountered = true; + } else if (newAttrEncountered) { + error("Attribute overrides should come before any new attributes.", attr, null); + } + } + } +} diff --git a/rosetta-runtime/src/main/java/com/rosetta/model/metafields/MetaAndTemplateFields.java b/rosetta-runtime/src/main/java/com/rosetta/model/metafields/MetaAndTemplateFields.java new file mode 100644 index 000000000..04a913745 --- /dev/null +++ b/rosetta-runtime/src/main/java/com/rosetta/model/metafields/MetaAndTemplateFields.java @@ -0,0 +1,504 @@ +package com.rosetta.model.metafields; + +import com.google.common.collect.ImmutableList; +import com.rosetta.model.lib.RosettaModelObject; +import com.rosetta.model.lib.RosettaModelObjectBuilder; +import com.rosetta.model.lib.annotations.RosettaAttribute; +import com.rosetta.model.lib.annotations.RosettaDataType; +import com.rosetta.model.lib.meta.BasicRosettaMetaData; +import com.rosetta.model.lib.meta.GlobalKeyFields; +import com.rosetta.model.lib.meta.GlobalKeyFields.GlobalKeyFieldsBuilder; +import com.rosetta.model.lib.meta.Key; +import com.rosetta.model.lib.meta.MetaDataFields; +import com.rosetta.model.lib.meta.MetaDataFields.MetaDataFieldsBuilder; +import com.rosetta.model.lib.meta.RosettaMetaData; +import com.rosetta.model.lib.meta.TemplateFields; +import com.rosetta.model.lib.meta.TemplateFields.TemplateFieldsBuilder; +import com.rosetta.model.lib.path.RosettaPath; +import com.rosetta.model.lib.process.AttributeMeta; +import com.rosetta.model.lib.process.BuilderMerger; +import com.rosetta.model.lib.process.BuilderProcessor; +import com.rosetta.model.lib.process.Processor; +import com.rosetta.util.ListEquals; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import static java.util.Optional.ofNullable; + +/** + * @version 1 + */ +@RosettaDataType(value="MetaAndTemplateFields", builder=MetaAndTemplateFields.MetaAndTemplateFieldsBuilderImpl.class, version="0.0.0") +public interface MetaAndTemplateFields extends RosettaModelObject, GlobalKeyFields, TemplateFields, MetaDataFields { + + MetaAndTemplateFieldsMeta metaData = new MetaAndTemplateFieldsMeta(); + + /*********************** Getter Methods ***********************/ + String getScheme(); + String getTemplate(); + String getLocation(); + String getAddress(); + String getTemplateGlobalReference(); + String getGlobalKey(); + String getExternalKey(); + List getKey(); + + /*********************** Build Methods ***********************/ + MetaAndTemplateFields build(); + + MetaAndTemplateFields.MetaAndTemplateFieldsBuilder toBuilder(); + + static MetaAndTemplateFields.MetaAndTemplateFieldsBuilder builder() { + return new MetaAndTemplateFields.MetaAndTemplateFieldsBuilderImpl(); + } + + /*********************** Utility Methods ***********************/ + @Override + default RosettaMetaData metaData() { + return metaData; + } + + @Override + default Class getType() { + return MetaAndTemplateFields.class; + } + + + @Override + default void process(RosettaPath path, Processor processor) { + processor.processBasic(path.newSubPath("scheme"), String.class, getScheme(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("template"), String.class, getTemplate(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("location"), String.class, getLocation(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("address"), String.class, getAddress(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("templateGlobalReference"), String.class, getTemplateGlobalReference(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("globalKey"), String.class, getGlobalKey(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("externalKey"), String.class, getExternalKey(), this, AttributeMeta.META); + processRosetta(path.newSubPath("key"), processor, Key.class, getKey()); + } + + + /*********************** Builder Interface ***********************/ + interface MetaAndTemplateFieldsBuilder extends MetaAndTemplateFields, RosettaModelObjectBuilder, GlobalKeyFields.GlobalKeyFieldsBuilder, TemplateFields.TemplateFieldsBuilder, MetaDataFields.MetaDataFieldsBuilder { + Key.KeyBuilder getOrCreateKey(int _index); + List getKey(); + MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setScheme(String scheme); + MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setTemplate(String template); + MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setLocation(String location); + MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setAddress(String address); + MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setTemplateGlobalReference(String templateGlobalReference); + MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setGlobalKey(String globalKey); + MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setExternalKey(String externalKey); + MetaAndTemplateFields.MetaAndTemplateFieldsBuilder addKey(Key key0); + MetaAndTemplateFields.MetaAndTemplateFieldsBuilder addKey(Key key1, int _idx); + MetaAndTemplateFields.MetaAndTemplateFieldsBuilder addKey(List key2); + MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setKey(List key3); + + @Override + default void process(RosettaPath path, BuilderProcessor processor) { + processor.processBasic(path.newSubPath("scheme"), String.class, getScheme(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("template"), String.class, getTemplate(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("location"), String.class, getLocation(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("address"), String.class, getAddress(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("templateGlobalReference"), String.class, getTemplateGlobalReference(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("globalKey"), String.class, getGlobalKey(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("externalKey"), String.class, getExternalKey(), this, AttributeMeta.META); + processRosetta(path.newSubPath("key"), processor, Key.KeyBuilder.class, getKey()); + } + + + MetaAndTemplateFields.MetaAndTemplateFieldsBuilder prune(); + } + + /*********************** Immutable Implementation of MetaAndTemplateFields ***********************/ + class MetaAndTemplateFieldsImpl implements MetaAndTemplateFields { + private final String scheme; + private final String template; + private final String location; + private final String address; + private final String templateGlobalReference; + private final String globalKey; + private final String externalKey; + private final List key; + + protected MetaAndTemplateFieldsImpl(MetaAndTemplateFields.MetaAndTemplateFieldsBuilder builder) { + this.scheme = builder.getScheme(); + this.template = builder.getTemplate(); + this.location = builder.getLocation(); + this.address = builder.getAddress(); + this.templateGlobalReference = builder.getTemplateGlobalReference(); + this.globalKey = builder.getGlobalKey(); + this.externalKey = builder.getExternalKey(); + this.key = ofNullable(builder.getKey()).filter(_l->!_l.isEmpty()).map(list -> list.stream().filter(Objects::nonNull).map(f->f.build()).filter(Objects::nonNull).collect(ImmutableList.toImmutableList())).orElse(null); + } + + @Override + @RosettaAttribute("scheme") + public String getScheme() { + return scheme; + } + + @Override + @RosettaAttribute("template") + public String getTemplate() { + return template; + } + + @Override + @RosettaAttribute("scopedLocation") + public String getLocation() { + return location; + } + + @Override + @RosettaAttribute("address") + public String getAddress() { + return address; + } + + @Override + @RosettaAttribute("templateGlobalReference") + public String getTemplateGlobalReference() { + return templateGlobalReference; + } + + @Override + @RosettaAttribute("globalKey") + public String getGlobalKey() { + return globalKey; + } + + @Override + @RosettaAttribute("externalKey") + public String getExternalKey() { + return externalKey; + } + + @Override + @RosettaAttribute("location") + public List getKey() { + return key; + } + + @Override + public MetaAndTemplateFields build() { + return this; + } + + @Override + public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder toBuilder() { + MetaAndTemplateFields.MetaAndTemplateFieldsBuilder builder = builder(); + setBuilderFields(builder); + return builder; + } + + protected void setBuilderFields(MetaAndTemplateFields.MetaAndTemplateFieldsBuilder builder) { + ofNullable(getScheme()).ifPresent(builder::setScheme); + ofNullable(getTemplate()).ifPresent(builder::setTemplate); + ofNullable(getLocation()).ifPresent(builder::setLocation); + ofNullable(getAddress()).ifPresent(builder::setAddress); + ofNullable(getTemplateGlobalReference()).ifPresent(builder::setTemplateGlobalReference); + ofNullable(getGlobalKey()).ifPresent(builder::setGlobalKey); + ofNullable(getExternalKey()).ifPresent(builder::setExternalKey); + ofNullable(getKey()).ifPresent(builder::setKey); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !(o instanceof RosettaModelObject) || !getType().equals(((RosettaModelObject)o).getType())) return false; + + MetaAndTemplateFields _that = getType().cast(o); + + if (!Objects.equals(scheme, _that.getScheme())) return false; + if (!Objects.equals(template, _that.getTemplate())) return false; + if (!Objects.equals(location, _that.getLocation())) return false; + if (!Objects.equals(address, _that.getAddress())) return false; + if (!Objects.equals(templateGlobalReference, _that.getTemplateGlobalReference())) return false; + if (!Objects.equals(globalKey, _that.getGlobalKey())) return false; + if (!Objects.equals(externalKey, _that.getExternalKey())) return false; + if (!ListEquals.listEquals(key, _that.getKey())) return false; + return true; + } + + @Override + public int hashCode() { + int _result = 0; + _result = 31 * _result + (scheme != null ? scheme.hashCode() : 0); + _result = 31 * _result + (template != null ? template.hashCode() : 0); + _result = 31 * _result + (location != null ? location.hashCode() : 0); + _result = 31 * _result + (address != null ? address.hashCode() : 0); + _result = 31 * _result + (templateGlobalReference != null ? templateGlobalReference.hashCode() : 0); + _result = 31 * _result + (globalKey != null ? globalKey.hashCode() : 0); + _result = 31 * _result + (externalKey != null ? externalKey.hashCode() : 0); + _result = 31 * _result + (key != null ? key.hashCode() : 0); + return _result; + } + + @Override + public String toString() { + return "MetaAndTemplateFields {" + + "scheme=" + this.scheme + ", " + + "template=" + this.template + ", " + + "location=" + this.location + ", " + + "address=" + this.address + ", " + + "templateGlobalReference=" + this.templateGlobalReference + ", " + + "globalKey=" + this.globalKey + ", " + + "externalKey=" + this.externalKey + ", " + + "key=" + this.key + + '}'; + } + } + + /*********************** Builder Implementation of MetaAndTemplateFields ***********************/ + class MetaAndTemplateFieldsBuilderImpl implements MetaAndTemplateFields.MetaAndTemplateFieldsBuilder { + + protected String scheme; + protected String template; + protected String location; + protected String address; + protected String templateGlobalReference; + protected String globalKey; + protected String externalKey; + protected List key = new ArrayList<>(); + + public MetaAndTemplateFieldsBuilderImpl() { + } + + @Override + @RosettaAttribute("scheme") + public String getScheme() { + return scheme; + } + + @Override + @RosettaAttribute("template") + public String getTemplate() { + return template; + } + + @Override + @RosettaAttribute("scopedLocation") + public String getLocation() { + return location; + } + + @Override + @RosettaAttribute("address") + public String getAddress() { + return address; + } + + @Override + @RosettaAttribute("templateGlobalReference") + public String getTemplateGlobalReference() { + return templateGlobalReference; + } + + @Override + @RosettaAttribute("globalKey") + public String getGlobalKey() { + return globalKey; + } + + @Override + @RosettaAttribute("externalKey") + public String getExternalKey() { + return externalKey; + } + + @Override + @RosettaAttribute("location") + public List getKey() { + return key; + } + + public Key.KeyBuilder getOrCreateKey(int _index) { + + if (key==null) { + this.key = new ArrayList<>(); + } + Key.KeyBuilder result; + return getIndex(key, _index, () -> { + Key.KeyBuilder newKey = Key.builder(); + return newKey; + }); + } + + @Override + @RosettaAttribute("scheme") + public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setScheme(String scheme) { + this.scheme = scheme==null?null:scheme; + return this; + } + @Override + @RosettaAttribute("template") + public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setTemplate(String template) { + this.template = template==null?null:template; + return this; + } + @Override + @RosettaAttribute("scopedLocation") + public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setLocation(String location) { + this.location = location==null?null:location; + return this; + } + @Override + @RosettaAttribute("address") + public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setAddress(String address) { + this.address = address==null?null:address; + return this; + } + @Override + @RosettaAttribute("templateGlobalReference") + public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setTemplateGlobalReference(String templateGlobalReference) { + this.templateGlobalReference = templateGlobalReference==null?null:templateGlobalReference; + return this; + } + @Override + @RosettaAttribute("globalKey") + public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setGlobalKey(String globalKey) { + this.globalKey = globalKey==null?null:globalKey; + return this; + } + @Override + @RosettaAttribute("externalKey") + public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setExternalKey(String externalKey) { + this.externalKey = externalKey==null?null:externalKey; + return this; + } + @Override + public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder addKey(Key key) { + if (key!=null) this.key.add(key.toBuilder()); + return this; + } + + @Override + public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder addKey(Key key, int _idx) { + getIndex(this.key, _idx, () -> key.toBuilder()); + return this; + } + @Override + public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder addKey(List keys) { + if (keys != null) { + for (Key toAdd : keys) { + this.key.add(toAdd.toBuilder()); + } + } + return this; + } + + @Override + @RosettaAttribute("location") + public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setKey(List keys) { + if (keys == null) { + this.key = new ArrayList<>(); + } + else { + this.key = keys.stream() + .map(_a->_a.toBuilder()) + .collect(Collectors.toCollection(()->new ArrayList<>())); + } + return this; + } + + + @Override + public MetaAndTemplateFields build() { + return new MetaAndTemplateFields.MetaAndTemplateFieldsImpl(this); + } + + @Override + public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder toBuilder() { + return this; + } + + @SuppressWarnings("unchecked") + @Override + public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder prune() { + key = key.stream().filter(b->b!=null).map(b->b.prune()).filter(b->b.hasData()).collect(Collectors.toList()); + return this; + } + + @Override + public boolean hasData() { + if (getScheme()!=null) return true; + if (getTemplate()!=null) return true; + if (getLocation()!=null) return true; + if (getAddress()!=null) return true; + if (getTemplateGlobalReference()!=null) return true; + if (getGlobalKey()!=null) return true; + if (getExternalKey()!=null) return true; + if (getKey()!=null && getKey().stream().filter(Objects::nonNull).anyMatch(a->a.hasData())) return true; + return false; + } + + @SuppressWarnings("unchecked") + @Override + public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder merge(RosettaModelObjectBuilder other, BuilderMerger merger) { + MetaAndTemplateFields.MetaAndTemplateFieldsBuilder o = (MetaAndTemplateFields.MetaAndTemplateFieldsBuilder) other; + + merger.mergeRosetta(getKey(), o.getKey(), this::getOrCreateKey); + + merger.mergeBasic(getScheme(), o.getScheme(), this::setScheme); + merger.mergeBasic(getTemplate(), o.getTemplate(), this::setTemplate); + merger.mergeBasic(getLocation(), o.getLocation(), this::setLocation); + merger.mergeBasic(getAddress(), o.getAddress(), this::setAddress); + merger.mergeBasic(getTemplateGlobalReference(), o.getTemplateGlobalReference(), this::setTemplateGlobalReference); + merger.mergeBasic(getGlobalKey(), o.getGlobalKey(), this::setGlobalKey); + merger.mergeBasic(getExternalKey(), o.getExternalKey(), this::setExternalKey); + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !(o instanceof RosettaModelObject) || !getType().equals(((RosettaModelObject)o).getType())) return false; + + MetaAndTemplateFields _that = getType().cast(o); + + if (!Objects.equals(scheme, _that.getScheme())) return false; + if (!Objects.equals(template, _that.getTemplate())) return false; + if (!Objects.equals(location, _that.getLocation())) return false; + if (!Objects.equals(address, _that.getAddress())) return false; + if (!Objects.equals(templateGlobalReference, _that.getTemplateGlobalReference())) return false; + if (!Objects.equals(globalKey, _that.getGlobalKey())) return false; + if (!Objects.equals(externalKey, _that.getExternalKey())) return false; + if (!ListEquals.listEquals(key, _that.getKey())) return false; + return true; + } + + @Override + public int hashCode() { + int _result = 0; + _result = 31 * _result + (scheme != null ? scheme.hashCode() : 0); + _result = 31 * _result + (template != null ? template.hashCode() : 0); + _result = 31 * _result + (location != null ? location.hashCode() : 0); + _result = 31 * _result + (address != null ? address.hashCode() : 0); + _result = 31 * _result + (templateGlobalReference != null ? templateGlobalReference.hashCode() : 0); + _result = 31 * _result + (globalKey != null ? globalKey.hashCode() : 0); + _result = 31 * _result + (externalKey != null ? externalKey.hashCode() : 0); + _result = 31 * _result + (key != null ? key.hashCode() : 0); + return _result; + } + + @Override + public String toString() { + return "MetaAndTemplateFieldsBuilder {" + + "scheme=" + this.scheme + ", " + + "template=" + this.template + ", " + + "location=" + this.location + ", " + + "address=" + this.address + ", " + + "templateGlobalReference=" + this.templateGlobalReference + ", " + + "globalKey=" + this.globalKey + ", " + + "externalKey=" + this.externalKey + ", " + + "key=" + this.key + + '}'; + } + } +} + +class MetaAndTemplateFieldsMeta extends BasicRosettaMetaData{ + +} diff --git a/rosetta-runtime/src/main/java/com/rosetta/model/metafields/MetaFields.java b/rosetta-runtime/src/main/java/com/rosetta/model/metafields/MetaFields.java new file mode 100644 index 000000000..76b5f3b52 --- /dev/null +++ b/rosetta-runtime/src/main/java/com/rosetta/model/metafields/MetaFields.java @@ -0,0 +1,468 @@ +package com.rosetta.model.metafields; + +import com.google.common.collect.ImmutableList; +import com.rosetta.model.lib.RosettaModelObject; +import com.rosetta.model.lib.RosettaModelObjectBuilder; +import com.rosetta.model.lib.annotations.RosettaAttribute; +import com.rosetta.model.lib.annotations.RosettaDataType; +import com.rosetta.model.lib.meta.BasicRosettaMetaData; +import com.rosetta.model.lib.meta.GlobalKeyFields; +import com.rosetta.model.lib.meta.GlobalKeyFields.GlobalKeyFieldsBuilder; +import com.rosetta.model.lib.meta.Key; +import com.rosetta.model.lib.meta.MetaDataFields; +import com.rosetta.model.lib.meta.MetaDataFields.MetaDataFieldsBuilder; +import com.rosetta.model.lib.meta.RosettaMetaData; +import com.rosetta.model.lib.path.RosettaPath; +import com.rosetta.model.lib.process.AttributeMeta; +import com.rosetta.model.lib.process.BuilderMerger; +import com.rosetta.model.lib.process.BuilderProcessor; +import com.rosetta.model.lib.process.Processor; +import com.rosetta.util.ListEquals; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import static java.util.Optional.ofNullable; + +/** + * @version 1 + */ +@RosettaDataType(value="MetaFields", builder=MetaFields.MetaFieldsBuilderImpl.class, version="0.0.0") +public interface MetaFields extends RosettaModelObject, GlobalKeyFields, MetaDataFields { + + MetaFieldsMeta metaData = new MetaFieldsMeta(); + + /*********************** Getter Methods ***********************/ + String getScheme(); + String getTemplate(); + String getLocation(); + String getAddress(); + String getGlobalKey(); + String getExternalKey(); + List getKey(); + + /*********************** Build Methods ***********************/ + MetaFields build(); + + MetaFields.MetaFieldsBuilder toBuilder(); + + static MetaFields.MetaFieldsBuilder builder() { + return new MetaFields.MetaFieldsBuilderImpl(); + } + + /*********************** Utility Methods ***********************/ + @Override + default RosettaMetaData metaData() { + return metaData; + } + + @Override + default Class getType() { + return MetaFields.class; + } + + + @Override + default void process(RosettaPath path, Processor processor) { + processor.processBasic(path.newSubPath("scheme"), String.class, getScheme(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("template"), String.class, getTemplate(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("location"), String.class, getLocation(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("address"), String.class, getAddress(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("globalKey"), String.class, getGlobalKey(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("externalKey"), String.class, getExternalKey(), this, AttributeMeta.META); + processRosetta(path.newSubPath("key"), processor, Key.class, getKey()); + } + + + /*********************** Builder Interface ***********************/ + interface MetaFieldsBuilder extends MetaFields, RosettaModelObjectBuilder, GlobalKeyFields.GlobalKeyFieldsBuilder, MetaDataFields.MetaDataFieldsBuilder { + Key.KeyBuilder getOrCreateKey(int _index); + List getKey(); + MetaFields.MetaFieldsBuilder setScheme(String scheme); + MetaFields.MetaFieldsBuilder setTemplate(String template); + MetaFields.MetaFieldsBuilder setLocation(String location); + MetaFields.MetaFieldsBuilder setAddress(String address); + MetaFields.MetaFieldsBuilder setGlobalKey(String globalKey); + MetaFields.MetaFieldsBuilder setExternalKey(String externalKey); + MetaFields.MetaFieldsBuilder addKey(Key key0); + MetaFields.MetaFieldsBuilder addKey(Key key1, int _idx); + MetaFields.MetaFieldsBuilder addKey(List key2); + MetaFields.MetaFieldsBuilder setKey(List key3); + + @Override + default void process(RosettaPath path, BuilderProcessor processor) { + processor.processBasic(path.newSubPath("scheme"), String.class, getScheme(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("template"), String.class, getTemplate(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("location"), String.class, getLocation(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("address"), String.class, getAddress(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("globalKey"), String.class, getGlobalKey(), this, AttributeMeta.META); + processor.processBasic(path.newSubPath("externalKey"), String.class, getExternalKey(), this, AttributeMeta.META); + processRosetta(path.newSubPath("key"), processor, Key.KeyBuilder.class, getKey()); + } + + + MetaFields.MetaFieldsBuilder prune(); + } + + /*********************** Immutable Implementation of MetaFields ***********************/ + class MetaFieldsImpl implements MetaFields { + private final String scheme; + private final String template; + private final String location; + private final String address; + private final String globalKey; + private final String externalKey; + private final List key; + + protected MetaFieldsImpl(MetaFields.MetaFieldsBuilder builder) { + this.scheme = builder.getScheme(); + this.template = builder.getTemplate(); + this.location = builder.getLocation(); + this.address = builder.getAddress(); + this.globalKey = builder.getGlobalKey(); + this.externalKey = builder.getExternalKey(); + this.key = ofNullable(builder.getKey()).filter(_l->!_l.isEmpty()).map(list -> list.stream().filter(Objects::nonNull).map(f->f.build()).filter(Objects::nonNull).collect(ImmutableList.toImmutableList())).orElse(null); + } + + @Override + @RosettaAttribute("scheme") + public String getScheme() { + return scheme; + } + + @Override + @RosettaAttribute("template") + public String getTemplate() { + return template; + } + + @Override + @RosettaAttribute("scopedLocation") + public String getLocation() { + return location; + } + + @Override + @RosettaAttribute("address") + public String getAddress() { + return address; + } + + @Override + @RosettaAttribute("globalKey") + public String getGlobalKey() { + return globalKey; + } + + @Override + @RosettaAttribute("externalKey") + public String getExternalKey() { + return externalKey; + } + + @Override + @RosettaAttribute("location") + public List getKey() { + return key; + } + + @Override + public MetaFields build() { + return this; + } + + @Override + public MetaFields.MetaFieldsBuilder toBuilder() { + MetaFields.MetaFieldsBuilder builder = builder(); + setBuilderFields(builder); + return builder; + } + + protected void setBuilderFields(MetaFields.MetaFieldsBuilder builder) { + ofNullable(getScheme()).ifPresent(builder::setScheme); + ofNullable(getTemplate()).ifPresent(builder::setTemplate); + ofNullable(getLocation()).ifPresent(builder::setLocation); + ofNullable(getAddress()).ifPresent(builder::setAddress); + ofNullable(getGlobalKey()).ifPresent(builder::setGlobalKey); + ofNullable(getExternalKey()).ifPresent(builder::setExternalKey); + ofNullable(getKey()).ifPresent(builder::setKey); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !(o instanceof RosettaModelObject) || !getType().equals(((RosettaModelObject)o).getType())) return false; + + MetaFields _that = getType().cast(o); + + if (!Objects.equals(scheme, _that.getScheme())) return false; + if (!Objects.equals(template, _that.getTemplate())) return false; + if (!Objects.equals(location, _that.getLocation())) return false; + if (!Objects.equals(address, _that.getAddress())) return false; + if (!Objects.equals(globalKey, _that.getGlobalKey())) return false; + if (!Objects.equals(externalKey, _that.getExternalKey())) return false; + if (!ListEquals.listEquals(key, _that.getKey())) return false; + return true; + } + + @Override + public int hashCode() { + int _result = 0; + _result = 31 * _result + (scheme != null ? scheme.hashCode() : 0); + _result = 31 * _result + (template != null ? template.hashCode() : 0); + _result = 31 * _result + (location != null ? location.hashCode() : 0); + _result = 31 * _result + (address != null ? address.hashCode() : 0); + _result = 31 * _result + (globalKey != null ? globalKey.hashCode() : 0); + _result = 31 * _result + (externalKey != null ? externalKey.hashCode() : 0); + _result = 31 * _result + (key != null ? key.hashCode() : 0); + return _result; + } + + @Override + public String toString() { + return "MetaFields {" + + "scheme=" + this.scheme + ", " + + "template=" + this.template + ", " + + "location=" + this.location + ", " + + "address=" + this.address + ", " + + "globalKey=" + this.globalKey + ", " + + "externalKey=" + this.externalKey + ", " + + "key=" + this.key + + '}'; + } + } + + /*********************** Builder Implementation of MetaFields ***********************/ + class MetaFieldsBuilderImpl implements MetaFields.MetaFieldsBuilder { + + protected String scheme; + protected String template; + protected String location; + protected String address; + protected String globalKey; + protected String externalKey; + protected List key = new ArrayList<>(); + + public MetaFieldsBuilderImpl() { + } + + @Override + @RosettaAttribute("scheme") + public String getScheme() { + return scheme; + } + + @Override + @RosettaAttribute("template") + public String getTemplate() { + return template; + } + + @Override + @RosettaAttribute("scopedLocation") + public String getLocation() { + return location; + } + + @Override + @RosettaAttribute("address") + public String getAddress() { + return address; + } + + @Override + @RosettaAttribute("globalKey") + public String getGlobalKey() { + return globalKey; + } + + @Override + @RosettaAttribute("externalKey") + public String getExternalKey() { + return externalKey; + } + + @Override + @RosettaAttribute("location") + public List getKey() { + return key; + } + + public Key.KeyBuilder getOrCreateKey(int _index) { + + if (key==null) { + this.key = new ArrayList<>(); + } + Key.KeyBuilder result; + return getIndex(key, _index, () -> { + Key.KeyBuilder newKey = Key.builder(); + return newKey; + }); + } + + @Override + @RosettaAttribute("scheme") + public MetaFields.MetaFieldsBuilder setScheme(String scheme) { + this.scheme = scheme==null?null:scheme; + return this; + } + @Override + @RosettaAttribute("template") + public MetaFields.MetaFieldsBuilder setTemplate(String template) { + this.template = template==null?null:template; + return this; + } + @Override + @RosettaAttribute("scopedLocation") + public MetaFields.MetaFieldsBuilder setLocation(String location) { + this.location = location==null?null:location; + return this; + } + @Override + @RosettaAttribute("address") + public MetaFields.MetaFieldsBuilder setAddress(String address) { + this.address = address==null?null:address; + return this; + } + @Override + @RosettaAttribute("globalKey") + public MetaFields.MetaFieldsBuilder setGlobalKey(String globalKey) { + this.globalKey = globalKey==null?null:globalKey; + return this; + } + @Override + @RosettaAttribute("externalKey") + public MetaFields.MetaFieldsBuilder setExternalKey(String externalKey) { + this.externalKey = externalKey==null?null:externalKey; + return this; + } + @Override + public MetaFields.MetaFieldsBuilder addKey(Key key) { + if (key!=null) this.key.add(key.toBuilder()); + return this; + } + + @Override + public MetaFields.MetaFieldsBuilder addKey(Key key, int _idx) { + getIndex(this.key, _idx, () -> key.toBuilder()); + return this; + } + @Override + public MetaFields.MetaFieldsBuilder addKey(List keys) { + if (keys != null) { + for (Key toAdd : keys) { + this.key.add(toAdd.toBuilder()); + } + } + return this; + } + + @Override + @RosettaAttribute("location") + public MetaFields.MetaFieldsBuilder setKey(List keys) { + if (keys == null) { + this.key = new ArrayList<>(); + } + else { + this.key = keys.stream() + .map(_a->_a.toBuilder()) + .collect(Collectors.toCollection(()->new ArrayList<>())); + } + return this; + } + + + @Override + public MetaFields build() { + return new MetaFields.MetaFieldsImpl(this); + } + + @Override + public MetaFields.MetaFieldsBuilder toBuilder() { + return this; + } + + @SuppressWarnings("unchecked") + @Override + public MetaFields.MetaFieldsBuilder prune() { + key = key.stream().filter(b->b!=null).map(b->b.prune()).filter(b->b.hasData()).collect(Collectors.toList()); + return this; + } + + @Override + public boolean hasData() { + if (getScheme()!=null) return true; + if (getTemplate()!=null) return true; + if (getLocation()!=null) return true; + if (getAddress()!=null) return true; + if (getGlobalKey()!=null) return true; + if (getExternalKey()!=null) return true; + if (getKey()!=null && getKey().stream().filter(Objects::nonNull).anyMatch(a->a.hasData())) return true; + return false; + } + + @SuppressWarnings("unchecked") + @Override + public MetaFields.MetaFieldsBuilder merge(RosettaModelObjectBuilder other, BuilderMerger merger) { + MetaFields.MetaFieldsBuilder o = (MetaFields.MetaFieldsBuilder) other; + + merger.mergeRosetta(getKey(), o.getKey(), this::getOrCreateKey); + + merger.mergeBasic(getScheme(), o.getScheme(), this::setScheme); + merger.mergeBasic(getTemplate(), o.getTemplate(), this::setTemplate); + merger.mergeBasic(getLocation(), o.getLocation(), this::setLocation); + merger.mergeBasic(getAddress(), o.getAddress(), this::setAddress); + merger.mergeBasic(getGlobalKey(), o.getGlobalKey(), this::setGlobalKey); + merger.mergeBasic(getExternalKey(), o.getExternalKey(), this::setExternalKey); + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !(o instanceof RosettaModelObject) || !getType().equals(((RosettaModelObject)o).getType())) return false; + + MetaFields _that = getType().cast(o); + + if (!Objects.equals(scheme, _that.getScheme())) return false; + if (!Objects.equals(template, _that.getTemplate())) return false; + if (!Objects.equals(location, _that.getLocation())) return false; + if (!Objects.equals(address, _that.getAddress())) return false; + if (!Objects.equals(globalKey, _that.getGlobalKey())) return false; + if (!Objects.equals(externalKey, _that.getExternalKey())) return false; + if (!ListEquals.listEquals(key, _that.getKey())) return false; + return true; + } + + @Override + public int hashCode() { + int _result = 0; + _result = 31 * _result + (scheme != null ? scheme.hashCode() : 0); + _result = 31 * _result + (template != null ? template.hashCode() : 0); + _result = 31 * _result + (location != null ? location.hashCode() : 0); + _result = 31 * _result + (address != null ? address.hashCode() : 0); + _result = 31 * _result + (globalKey != null ? globalKey.hashCode() : 0); + _result = 31 * _result + (externalKey != null ? externalKey.hashCode() : 0); + _result = 31 * _result + (key != null ? key.hashCode() : 0); + return _result; + } + + @Override + public String toString() { + return "MetaFieldsBuilder {" + + "scheme=" + this.scheme + ", " + + "template=" + this.template + ", " + + "location=" + this.location + ", " + + "address=" + this.address + ", " + + "globalKey=" + this.globalKey + ", " + + "externalKey=" + this.externalKey + ", " + + "key=" + this.key + + '}'; + } + } +} + +class MetaFieldsMeta extends BasicRosettaMetaData{ + +} diff --git a/rosetta-runtime/src/main/java/com/rosetta/util/types/JavaParameterizedType.java b/rosetta-runtime/src/main/java/com/rosetta/util/types/JavaParameterizedType.java index 4270134ca..1724c9188 100644 --- a/rosetta-runtime/src/main/java/com/rosetta/util/types/JavaParameterizedType.java +++ b/rosetta-runtime/src/main/java/com/rosetta/util/types/JavaParameterizedType.java @@ -112,24 +112,23 @@ public boolean isSupertypeOf(JavaClass other) { if (this.equals(other)) { return true; } - if (other.extendsDeclaration(getGenericTypeDeclaration())) { + JavaGenericTypeDeclaration typeDeclaration = getGenericTypeDeclaration(); + if (other.extendsDeclaration(typeDeclaration)) { JavaClass currentSuper = other; JavaClass nextSuper = currentSuper.getSuperclass(); // First check superclasses - while (nextSuper.extendsDeclaration(getGenericTypeDeclaration())) { + while (nextSuper.extendsDeclaration(typeDeclaration)) { currentSuper = nextSuper; - nextSuper = nextSuper.getSuperclass(); + nextSuper = currentSuper.getSuperclass(); } // Then check interfaces - JavaClass temp0 = currentSuper; - Optional> nextInterface = temp0.getInterfaces().stream() - .filter(i -> temp0.extendsDeclaration(i)) + Optional> nextInterface = currentSuper.getInterfaces().stream() + .filter(i -> i.extendsDeclaration(typeDeclaration)) .findAny(); while (nextInterface.isPresent()) { currentSuper = nextInterface.get(); - JavaClass temp1 = currentSuper; - nextInterface = temp1.getInterfaces().stream() - .filter(i -> temp1.extendsDeclaration(i)) + nextInterface = currentSuper.getInterfaces().stream() + .filter(i -> i.extendsDeclaration(typeDeclaration)) .findAny(); } Map substitution = ((JavaParameterizedType)currentSuper).getTypeVariableSubstitution(); diff --git a/rosetta-testing/src/main/java/com/regnosys/rosetta/tests/util/CodeGeneratorTestHelper.xtend b/rosetta-testing/src/main/java/com/regnosys/rosetta/tests/util/CodeGeneratorTestHelper.xtend index ee1d774dd..51d780566 100644 --- a/rosetta-testing/src/main/java/com/regnosys/rosetta/tests/util/CodeGeneratorTestHelper.xtend +++ b/rosetta-testing/src/main/java/com/regnosys/rosetta/tests/util/CodeGeneratorTestHelper.xtend @@ -22,6 +22,7 @@ import javax.inject.Inject import com.regnosys.rosetta.tests.compiler.InMemoryJavacCompiler import com.regnosys.rosetta.utils.ModelIdProvider import com.rosetta.model.lib.RosettaModelObjectBuilder +import com.rosetta.model.metafields.MetaFields class CodeGeneratorTestHelper { @@ -153,12 +154,11 @@ class CodeGeneratorTestHelper { } def FieldWithMeta createFieldWithMetaString(Map> classes, String value, String scheme) { - val metaFieldsBuilder = classes.get('com.rosetta.model.metafields.MetaFields').getMethod("builder").invoke(null); - metaFieldsBuilder.class.getMatchingMethod('setScheme', #[scheme.class]).invoke(metaFieldsBuilder, scheme); + val metaFieldsBuilder = MetaFields.builder().setScheme(scheme) val fieldWithMetaStringBuilder = classes.get('com.rosetta.model.metafields.FieldWithMetaString').getMethod("builder").invoke(null); fieldWithMetaStringBuilder.class.getMatchingMethod('setValue', #[value.class]).invoke(fieldWithMetaStringBuilder, value); - fieldWithMetaStringBuilder.class.getMatchingMethod('setMeta', #[metaFieldsBuilder.class]).invoke(fieldWithMetaStringBuilder, metaFieldsBuilder); + fieldWithMetaStringBuilder.class.getMatchingMethod('setMeta', #[MetaFields]).invoke(fieldWithMetaStringBuilder, metaFieldsBuilder); return fieldWithMetaStringBuilder.class.getMethod('build').invoke(fieldWithMetaStringBuilder) as FieldWithMeta; } diff --git a/rosetta-testing/src/main/java/com/regnosys/rosetta/tests/util/ExpressionParser.xtend b/rosetta-testing/src/main/java/com/regnosys/rosetta/tests/util/ExpressionParser.xtend index 8e98addb1..4b4953d4f 100644 --- a/rosetta-testing/src/main/java/com/regnosys/rosetta/tests/util/ExpressionParser.xtend +++ b/rosetta-testing/src/main/java/com/regnosys/rosetta/tests/util/ExpressionParser.xtend @@ -45,7 +45,7 @@ class ExpressionParser { } def RosettaExpression parseExpression(CharSequence expr, Collection attrs) { - return parseExpression(expr, defaultContext, attrs) + return parseExpression(expr, emptyList, attrs) } def RosettaExpression parseExpression(CharSequence expr, List context, Collection attrs) { @@ -54,15 +54,16 @@ class ExpressionParser { } def RosettaExpression parseExpression(CharSequence expr, Attribute... attributes) { - return parseExpression(expr, defaultContext, attributes) + return parseExpression(expr, emptyList, attributes) } def RosettaExpression parseExpression(CharSequence expr, List context, Attribute... attributes) { + val cont = context.isEmpty ? defaultContext : context val IParseResult result = parser.parse(grammar.rosettaCalcExpressionRule, new StringReader(expr.toString())) assertFalse(result.hasSyntaxErrors) val expression = result.rootASTElement as RosettaExpression - createResource("expr", expression, context) - link(expression, context, attributes) + createResource("expr", expression, cont) + link(expression, cont, attributes) return expression } @@ -71,10 +72,11 @@ class ExpressionParser { } def Attribute parseAttribute(CharSequence attr, List context) { + val cont = context.isEmpty ? defaultContext : context val IParseResult result = parser.parse(grammar.attributeRule, new StringReader(attr.toString())) assertFalse(result.hasSyntaxErrors) val attribute = result.rootASTElement as Attribute - createResource("attribute", attribute, context) + createResource("attribute", attribute, cont) link(attribute, context, emptyList) return attribute } diff --git a/rosetta-testing/src/test/java/com/regnosys/rosetta/formatting2/RosettaFormattingTest.xtend b/rosetta-testing/src/test/java/com/regnosys/rosetta/formatting2/RosettaFormattingTest.xtend index 9f1289441..6f30341f4 100644 --- a/rosetta-testing/src/test/java/com/regnosys/rosetta/formatting2/RosettaFormattingTest.xtend +++ b/rosetta-testing/src/test/java/com/regnosys/rosetta/formatting2/RosettaFormattingTest.xtend @@ -22,7 +22,7 @@ class RosettaFormattingTest { req.toBeFormatted = unformated // extra check to make sure we didn't miss any hidden region in our formatter: - req.allowUnformattedWhitespace = false + req.allowUnformattedWhitespace = false // see issue https://github.com/eclipse/xtext-core/issues/2058 req.request.allowIdentityEdits = true diff --git a/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/expression/ExpressionGeneratorTest.xtend b/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/expression/ExpressionGeneratorTest.xtend index 2b161f5c8..80e696297 100644 --- a/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/expression/ExpressionGeneratorTest.xtend +++ b/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/expression/ExpressionGeneratorTest.xtend @@ -1,42 +1,29 @@ package com.regnosys.rosetta.generator.java.expression import com.regnosys.rosetta.generator.java.expression.ExpressionGenerator -import com.regnosys.rosetta.rosetta.expression.RosettaBinaryOperation -import com.regnosys.rosetta.rosetta.RosettaCardinality -import com.regnosys.rosetta.rosetta.expression.RosettaExistsExpression -import com.regnosys.rosetta.rosetta.expression.RosettaExpression -import com.regnosys.rosetta.rosetta.expression.RosettaFeatureCall -import com.regnosys.rosetta.rosetta.expression.RosettaIntLiteral import com.regnosys.rosetta.rosetta.RosettaModel -import com.regnosys.rosetta.rosetta.simple.Attribute -import com.regnosys.rosetta.rosetta.simple.Data import com.regnosys.rosetta.tests.RosettaInjectorProvider -import org.eclipse.emf.common.util.ECollections import org.eclipse.xtext.testing.InjectWith import org.eclipse.xtext.testing.extensions.InjectionExtension import org.junit.jupiter.api.Test import org.junit.jupiter.api.^extension.ExtendWith import static org.junit.jupiter.api.Assertions.* -import static org.mockito.Mockito.mock -import static org.mockito.Mockito.when -import com.regnosys.rosetta.rosetta.expression.ModifiableBinaryOperation -import com.regnosys.rosetta.rosetta.expression.CardinalityModifier -import com.regnosys.rosetta.rosetta.expression.ComparisonOperation -import com.regnosys.rosetta.rosetta.expression.EqualityOperation -import com.regnosys.rosetta.rosetta.expression.LogicalOperation import com.regnosys.rosetta.generator.java.JavaScope -import com.regnosys.rosetta.rosetta.TypeCall -import com.regnosys.rosetta.rosetta.RosettaBasicType import com.regnosys.rosetta.tests.util.ExpressionParser import com.rosetta.util.DottedPath import javax.inject.Inject -import com.regnosys.rosetta.rosetta.expression.RosettaImplicitVariable -import com.regnosys.rosetta.generator.ImplicitVariableRepresentation -import com.regnosys.rosetta.generator.java.statement.builder.JavaStatementBuilder import com.regnosys.rosetta.generator.java.util.ImportManagerExtension -import java.math.BigInteger import com.regnosys.rosetta.generator.java.types.JavaTypeUtil +import com.rosetta.util.types.JavaType +import java.util.List +import java.util.Collection +import com.regnosys.rosetta.generator.java.statement.JavaLocalVariableDeclarationStatement +import com.regnosys.rosetta.generator.java.types.JavaTypeTranslator +import com.regnosys.rosetta.types.RObjectFactory +import com.regnosys.rosetta.tests.util.ModelHelper +import com.regnosys.rosetta.generator.java.JavaIdentifierRepresentationService +import org.eclipse.xtend2.lib.StringConcatenationClient @ExtendWith(InjectionExtension) @InjectWith(RosettaInjectorProvider) @@ -45,25 +32,88 @@ class ExpressionGeneratorTest { @Inject extension ExpressionParser @Inject extension ImportManagerExtension @Inject extension JavaTypeUtil + @Inject extension JavaTypeTranslator + @Inject extension RObjectFactory + @Inject extension ModelHelper + @Inject extension JavaDependencyProvider + @Inject extension JavaIdentifierRepresentationService - DottedPath testPackageName = DottedPath.of("com", "regnosys", "test") + + private def void assertJavaCode(String expectedCode, CharSequence expr, Class expectedType) { + assertJavaCode(expectedCode, expr, expectedType, emptyList, emptyList) + } + private def void assertJavaCode(String expectedCode, CharSequence expr, Class expectedType, List context, Collection attrs) { + assertJavaCode(expectedCode, expr, JavaType.from(expectedType), context, attrs) + } + private def void assertJavaCode(String expectedCode, CharSequence expr, JavaType expectedType, List context, Collection attrs) { + val attributes = attrs.map[parseAttribute(context)].toList + val parsedExpr = expr.parseExpression(context, attributes) + val dependencies = parsedExpr.javaDependencies + + val pkg = DottedPath.of("test", "ns") + val scope = new JavaScope(pkg) + + val List dependencyStatements = newArrayList + dependencies + .map[new JavaLocalVariableDeclarationStatement(false, it, scope.createIdentifier(toDependencyInstance, simpleName.toFirstLower))] + .forEach[dependencyStatements.add('''@«Inject» «it»''')] + + val statements = newArrayList + statements.addAll( + attributes + .map[buildRAttribute] + .map[new JavaLocalVariableDeclarationStatement(false, toMetaJavaType, scope.createIdentifier(it, name))]) + statements.add(parsedExpr.javaCode(expectedType, scope).completeAsReturn) + + val actual = statements.reduce[s1, s2|s1.append(s2)] + assertEquals(expectedCode, buildClass(pkg, '''«FOR dep : dependencyStatements SEPARATOR "\n" AFTER "\n\n"»«dep»«ENDFOR»«actual»''', scope).replace("package test.ns;", "").trim + System.lineSeparator) + } + + @Test - def void shouldEscapeStrings() { - val scope = new JavaScope(testPackageName) + def void testFeatureCallToIncompatibleOverrideUsesCorrectGetter() { + val context = ''' + type Foo: + attr number (1..1) + + type Bar extends Foo: + override attr int (1..1) + + func Round: + inputs: + inp number (1..1) + output: + result int (1..1) + '''.parseRosettaWithNoIssues + + val expected = ''' + import com.rosetta.model.lib.expression.MapperMaths; + import com.rosetta.model.lib.mapper.MapperS; + import com.rosetta.test.model.Bar; + import com.rosetta.test.model.functions.Round; + import java.math.BigDecimal; + import javax.inject.Inject; - val gen = - '''"Hello \"world\"!"''' - .parseExpression - .javaCode(STRING, scope) - .formatGeneratedFunction(scope) - assertEquals( - ''' - return "Hello \"world\"!"; - '''.toString, - gen - ) + @Inject Round round; + + { + Bar bar; + return MapperMaths.add(MapperS.of(bar).map("getAttr", _bar -> _bar.getAttrOverriddenAsInteger()), MapperS.of(round.evaluate(MapperS.of(bar).map("getAttr", _bar -> _bar.getAttr()).get()))).get(); + } + ''' + + assertJavaCode(expected, '''bar -> attr + Round(bar -> attr)''', Integer, #[context], #["bar Bar (1..1)"]) + + } + + @Test + def void shouldEscapeStrings() { + val expected = ''' + return "Hello \"world\"!"; + ''' + assertJavaCode(expected, '''"Hello \"world\"!"''', String) } /** @@ -71,30 +121,24 @@ class ExpressionGeneratorTest { */ @Test def void shouldGenerateGreaterThanExpression() { - val lhsMockClass = createData("Foo") - val lhsFeatureCall = createItemFeatureCall(lhsMockClass, "attr1", "number") - - val rhsIntLiteral = createIntLiteral(5) - - val comparisonOp = createModifiableBinaryOperation(">", lhsFeatureCall, rhsIntLiteral, ComparisonOperation) - - val scope = new JavaScope(testPackageName) - scope.createIdentifier(new ImplicitVariableRepresentation(lhsMockClass), "foo") - val generatedFunction = expressionGenerator.javaCode(comparisonOp, COMPARISON_RESULT, scope) - - assertNotNull(generatedFunction) - assertEquals( - ''' - import com.rosetta.model.lib.expression.CardinalityOperator; - import com.rosetta.model.lib.mapper.MapperS; - import java.math.BigDecimal; - - import static com.rosetta.model.lib.expression.ExpressionOperators.*; - + val context = ''' + type Foo: + attr1 number (1..1) + '''.parseRosettaWithNoIssues + val expected = ''' + import com.rosetta.model.lib.expression.CardinalityOperator; + import com.rosetta.model.lib.mapper.MapperS; + import com.rosetta.test.model.Foo; + import java.math.BigDecimal; + + import static com.rosetta.model.lib.expression.ExpressionOperators.*; + + { + Foo foo; return greaterThan(MapperS.of(foo).map("getAttr1", _foo -> _foo.getAttr1()), MapperS.of(BigDecimal.valueOf(5)), CardinalityOperator.All); - '''.toString, - formatGeneratedFunction(generatedFunction, scope) - ) + } + ''' + assertJavaCode(expected, '''foo -> attr1 > 5''', COMPARISON_RESULT, #[context], #["foo Foo (1..1)"]) } /** @@ -102,33 +146,25 @@ class ExpressionGeneratorTest { */ @Test def void shouldGenerateGreaterThanExpressionsWithOr1() { - val mockClass = createData("Foo") - - val lhsFeatureCall = createItemFeatureCall(mockClass, "attr1", "number") - val lhsComparisonOp = createModifiableBinaryOperation(">", lhsFeatureCall, createIntLiteral(5), ComparisonOperation) - - val rhsFeatureCall = createItemFeatureCall(mockClass, "attr2", "number") - val rhsComparisonOp = createModifiableBinaryOperation(">", rhsFeatureCall, createIntLiteral(5), ComparisonOperation) - - val orOp = createBinaryOperation("or", lhsComparisonOp, rhsComparisonOp, LogicalOperation) - - val scope = new JavaScope(testPackageName) - scope.createIdentifier(new ImplicitVariableRepresentation(mockClass), "foo") - val generatedFunction = expressionGenerator.javaCode(orOp, COMPARISON_RESULT, scope) - - assertNotNull(generatedFunction) - assertEquals( - ''' - import com.rosetta.model.lib.expression.CardinalityOperator; - import com.rosetta.model.lib.mapper.MapperS; - import java.math.BigDecimal; - - import static com.rosetta.model.lib.expression.ExpressionOperators.*; - + val context = ''' + type Foo: + attr1 number (1..1) + attr2 number (1..1) + '''.parseRosettaWithNoIssues + val expected = ''' + import com.rosetta.model.lib.expression.CardinalityOperator; + import com.rosetta.model.lib.mapper.MapperS; + import com.rosetta.test.model.Foo; + import java.math.BigDecimal; + + import static com.rosetta.model.lib.expression.ExpressionOperators.*; + + { + Foo foo; return greaterThan(MapperS.of(foo).map("getAttr1", _foo -> _foo.getAttr1()), MapperS.of(BigDecimal.valueOf(5)), CardinalityOperator.All).or(greaterThan(MapperS.of(foo).map("getAttr2", _foo -> _foo.getAttr2()), MapperS.of(BigDecimal.valueOf(5)), CardinalityOperator.All)); - '''.toString, - formatGeneratedFunction(generatedFunction, scope) - ) + } + ''' + assertJavaCode(expected, '''foo -> attr1 > 5 or foo -> attr2 > 5''', COMPARISON_RESULT, #[context], #["foo Foo (1..1)"]) } /** @@ -136,200 +172,47 @@ class ExpressionGeneratorTest { */ @Test def void shouldGenerateExistsExpression() { - val lhsMockClass = createData("Foo") - val lhsFeatureCall = createItemFeatureCall(lhsMockClass, "attr", "number") - val lhsExistsOp = createExistsExpression(lhsFeatureCall) - - val scope = new JavaScope(testPackageName) - scope.createIdentifier(new ImplicitVariableRepresentation(lhsMockClass), "foo") - val generatedFunction = expressionGenerator.javaCode(lhsExistsOp, COMPARISON_RESULT, scope) - - assertNotNull(generatedFunction) - assertEquals( - ''' - import com.rosetta.model.lib.mapper.MapperS; - import java.math.BigDecimal; - - import static com.rosetta.model.lib.expression.ExpressionOperators.*; - + val context = ''' + type Foo: + attr number (0..1) + '''.parseRosettaWithNoIssues + val expected = ''' + import com.rosetta.model.lib.mapper.MapperS; + import com.rosetta.test.model.Foo; + import java.math.BigDecimal; + + import static com.rosetta.model.lib.expression.ExpressionOperators.*; + + { + Foo foo; return exists(MapperS.of(foo).map("getAttr", _foo -> _foo.getAttr())); - '''.toString, - formatGeneratedFunction(generatedFunction, scope) - ) - } - - /** - * Foo -> attr1 exists or Foo -> attr2 exists - */ - @Test - def void shouldGenerateExistsExpressionsWithOr1() { - val mockClass = createData("Foo") - - val lhsFeatureCall = createItemFeatureCall(mockClass, "attr1", "boolean") - val lhsExistsOp = createExistsExpression(lhsFeatureCall) - - val rhsFeatureCall = createItemFeatureCall(mockClass, "attr2", "boolean") - val rhsExistsOp = createExistsExpression(rhsFeatureCall) - - val orOp = createBinaryOperation("or", lhsExistsOp, rhsExistsOp, LogicalOperation) - - val scope = new JavaScope(testPackageName) - scope.createIdentifier(new ImplicitVariableRepresentation(mockClass), "foo") - val generatedFunction = expressionGenerator.javaCode(orOp, COMPARISON_RESULT, scope) - - assertNotNull(generatedFunction) - assertEquals( - ''' - import com.rosetta.model.lib.mapper.MapperS; - - import static com.rosetta.model.lib.expression.ExpressionOperators.*; - - return exists(MapperS.of(foo).map("getAttr1", _foo -> _foo.getAttr1())).or(exists(MapperS.of(foo).map("getAttr2", _foo -> _foo.getAttr2()))); - '''.toString, - formatGeneratedFunction(generatedFunction, scope) - ) + } + ''' + assertJavaCode(expected, '''foo -> attr exists''', COMPARISON_RESULT, #[context], #["foo Foo (1..1)"]) } - - // ( Foo -> attr1 = Foo -> attr2 ) or ( Foo -> attr1 = Foo -> attr2 ) @Test - def void shouldGenerateEqualityExprWithOr() { - val mockClass = createData("Foo") - - val featureCall1 = createItemFeatureCall(mockClass, "attr1", "number") - val featureCall2 = createItemFeatureCall(mockClass, "attr2", "number") - - val lhsEqualsOp = createModifiableBinaryOperation("=", featureCall1, featureCall2, EqualityOperation) - - val featureCall3 = createItemFeatureCall(mockClass, "attr3", "string") - val featureCall4 = createItemFeatureCall(mockClass, "attr4", "string") - - val rhsEqualsOp = createModifiableBinaryOperation("=", featureCall3, featureCall4, EqualityOperation) - - val orOp = createBinaryOperation("or", lhsEqualsOp, rhsEqualsOp, LogicalOperation) - - val scope = new JavaScope(testPackageName) - scope.createIdentifier(new ImplicitVariableRepresentation(mockClass), "foo") - val generatedFunction = expressionGenerator.javaCode(orOp, COMPARISON_RESULT, scope) - - assertNotNull(generatedFunction) - assertEquals( - ''' - import com.rosetta.model.lib.expression.CardinalityOperator; - import com.rosetta.model.lib.mapper.MapperS; - import java.math.BigDecimal; - - import static com.rosetta.model.lib.expression.ExpressionOperators.*; - - return areEqual(MapperS.of(foo).map("getAttr1", _foo -> _foo.getAttr1()), MapperS.of(foo).map("getAttr2", _foo -> _foo.getAttr2()), CardinalityOperator.All).or(areEqual(MapperS.of(foo).map("getAttr3", _foo -> _foo.getAttr3()), MapperS.of(foo).map("getAttr4", _foo -> _foo.getAttr4()), CardinalityOperator.All)); - '''.toString, - formatGeneratedFunction(generatedFunction, scope) - ) - } - - @Test - def void shouldGenerateEnumValueRef() { - val mockClass = createData("Foo") - - val featureCall1 = createItemFeatureCall(mockClass, "attr1", "number") - val featureCall2 = createItemFeatureCall(mockClass, "attr2", "number") - - val lhsEqualsOp = createModifiableBinaryOperation("=", featureCall1, featureCall2, EqualityOperation) - - val featureCall3 = createItemFeatureCall(mockClass, "attr3", "string") - val featureCall4 = createItemFeatureCall(mockClass, "attr4", "string") - - val rhsEqualsOp = createModifiableBinaryOperation("=", featureCall3, featureCall4, EqualityOperation) - - val orOp = createBinaryOperation("or", lhsEqualsOp, rhsEqualsOp, LogicalOperation) - - val scope = new JavaScope(testPackageName) - scope.createIdentifier(new ImplicitVariableRepresentation(mockClass), "foo") - val generatedFunction = expressionGenerator.javaCode(orOp, COMPARISON_RESULT, scope) - - assertNotNull(generatedFunction) - assertEquals( - ''' - import com.rosetta.model.lib.expression.CardinalityOperator; - import com.rosetta.model.lib.mapper.MapperS; - import java.math.BigDecimal; - - import static com.rosetta.model.lib.expression.ExpressionOperators.*; - + def void shouldGenerateEnumValueRef() { + val context = ''' + type Foo: + attr1 number (0..1) + attr2 number (0..1) + attr3 string (0..1) + attr4 string (0..1) + '''.parseRosettaWithNoIssues + val expected = ''' + import com.rosetta.model.lib.expression.CardinalityOperator; + import com.rosetta.model.lib.mapper.MapperS; + import com.rosetta.test.model.Foo; + import java.math.BigDecimal; + + import static com.rosetta.model.lib.expression.ExpressionOperators.*; + + { + Foo foo; return areEqual(MapperS.of(foo).map("getAttr1", _foo -> _foo.getAttr1()), MapperS.of(foo).map("getAttr2", _foo -> _foo.getAttr2()), CardinalityOperator.All).or(areEqual(MapperS.of(foo).map("getAttr3", _foo -> _foo.getAttr3()), MapperS.of(foo).map("getAttr4", _foo -> _foo.getAttr4()), CardinalityOperator.All)); - '''.toString, - formatGeneratedFunction(generatedFunction, scope) - ) - } - - private def String formatGeneratedFunction(JavaStatementBuilder generatedFunction, JavaScope topScope) { - buildClass(testPackageName, '''«generatedFunction.completeAsReturn»''', topScope).replace("package " + testPackageName + ";", "").trim + System.lineSeparator - } - - // Mock utils - - private def RosettaExistsExpression createExistsExpression(RosettaExpression argument) { - val mockExistsExpression = mock(RosettaExistsExpression); - when(mockExistsExpression.argument).thenReturn(argument); - return mockExistsExpression; - } - - private def T createBinaryOperation(String operator, RosettaExpression left, RosettaExpression right, Class op) { - val mockBinaryOperation = mock(op) - when(mockBinaryOperation.operator).thenReturn(operator) - when(mockBinaryOperation.left).thenReturn(left) - when(mockBinaryOperation.right).thenReturn(right) - return mockBinaryOperation - } - - private def T createModifiableBinaryOperation(String operator, RosettaExpression left, RosettaExpression right, Class op) { - val mockBinaryOperation = createBinaryOperation(operator, left, right, op) - when(mockBinaryOperation.cardMod).thenReturn(CardinalityModifier.NONE) - return mockBinaryOperation - } - - private def RosettaFeatureCall createItemFeatureCall(Data rosettaClass, String attributeName, String attributeType) { - val mockReference = mock(RosettaImplicitVariable) - when(mockReference.name).thenReturn("item") - when(mockReference.eContainer).thenReturn(rosettaClass) - - val mockCardinality = mock(RosettaCardinality) - when(mockCardinality.sup).thenReturn(1) - - val mockBasicType = mock(RosettaBasicType) - when(mockBasicType.name).thenReturn(attributeType) - when(mockBasicType.parameters).thenReturn(ECollections.emptyEList) - - val mockTypeCall = mock(TypeCall) - when(mockTypeCall.type).thenReturn(mockBasicType) - when(mockTypeCall.arguments).thenReturn(ECollections.emptyEList) - - val mockAttribute = mock(Attribute) - when(mockAttribute.name).thenReturn(attributeName) - when(mockAttribute.card).thenReturn(mockCardinality) - when(mockAttribute.eContainer).thenReturn(rosettaClass) - when(mockAttribute.typeCall).thenReturn(mockTypeCall) - when(mockAttribute.annotations).thenReturn(ECollections.emptyEList) - - val mockFeatureCall = mock(RosettaFeatureCall) - when(mockFeatureCall.feature).thenReturn(mockAttribute) - when(mockFeatureCall.receiver).thenReturn(mockReference) - return mockFeatureCall - } - - private def RosettaIntLiteral createIntLiteral(int value) { - val mockIntLiteral = mock(RosettaIntLiteral) - when(mockIntLiteral.value).thenReturn(BigInteger.valueOf(value)) - return mockIntLiteral - } - - private def Data createData(String className) { - val mockData = mock(Data) - val model = mock(RosettaModel) - when(model.name).thenReturn('com.rosetta.test') - when(mockData.model).thenReturn(model) - when(mockData.name).thenReturn(className) - when(mockData.annotations).thenReturn(ECollections.emptyEList) - return mockData + } + ''' + assertJavaCode(expected, '''(foo -> attr1 = foo -> attr2) or (foo -> attr3 = foo -> attr4)''', COMPARISON_RESULT, #[context], #["foo Foo (1..1)"]) } } diff --git a/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/function/FunctionGeneratorTest.xtend b/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/function/FunctionGeneratorTest.xtend index 143fa96c0..2d3859cf0 100644 --- a/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/function/FunctionGeneratorTest.xtend +++ b/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/function/FunctionGeneratorTest.xtend @@ -33,6 +33,7 @@ import java.time.LocalDateTime import com.regnosys.rosetta.generator.java.RosettaJavaPackages.RootPackage import com.rosetta.model.lib.meta.Key import com.rosetta.model.lib.meta.Reference +import com.rosetta.model.metafields.MetaFields @ExtendWith(InjectionExtension) @InjectWith(RosettaInjectorProvider) @@ -155,9 +156,7 @@ class FunctionGeneratorTest { "a" -> "aValue", "c" -> BigDecimal.valueOf(20) }), - "meta" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "MetaFields", #{ - "scheme" -> "myScheme" - }) + "meta" -> MetaFields.builder.setScheme("myScheme") }) val result = test.invokeFunc(Boolean, myInput) @@ -212,15 +211,11 @@ class FunctionGeneratorTest { val myInputs = #[ classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "FieldWithMetaInteger", #{ "value" -> 6, - "meta" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "MetaFields", #{ - "scheme" -> "myScheme" - }) + "meta" -> MetaFields.builder.setScheme("myScheme") }), classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "FieldWithMetaInteger", #{ "value" -> 5, - "meta" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "MetaFields", #{ - "scheme" -> "myScheme" - }) + "meta" -> MetaFields.builder.setScheme("myScheme") }) ] @@ -312,9 +307,7 @@ class FunctionGeneratorTest { val myInput = classes.createInstanceUsingBuilder("Foo", #{ "myEnum" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.test.model.metafields"), "FieldWithMetaMyEnum", #{ "value" -> classes.createEnumInstance("MyEnum", "B"), - "meta" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "MetaFields", #{ - "scheme" -> "myScheme" - }) + "meta" -> MetaFields.builder.setScheme("myScheme") }) }) @@ -349,10 +342,7 @@ class FunctionGeneratorTest { val myInput = classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.test.model.metafields"), "ReferenceWithMetaFoo", #{ "value" -> classes.createInstanceUsingBuilder("Foo", #{ - "meta" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "MetaFields", #{ - "externalKey" -> "myExternalKey", - "globalKey" -> "myGlobalKey" - }) + "meta" -> MetaFields.builder.setExternalKey("myExternalKey").setGlobalKey("myGlobalKey") }) }) @@ -392,9 +382,7 @@ class FunctionGeneratorTest { val myInput = classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "FieldWithMetaString", #{ "value" -> "someInput", - "meta" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "MetaFields", #{ - "scheme" -> "myScheme" - }) + "meta" -> MetaFields.builder.setScheme("myScheme") }) val expected = classes.createInstanceUsingBuilder("Bar", #{ @@ -441,10 +429,7 @@ class FunctionGeneratorTest { val myInput = classes.createInstanceUsingBuilder("FooContainer" , #{ "foo" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.test.model.metafields"), "ReferenceWithMetaFoo", #{ "value" -> classes.createInstanceUsingBuilder("Foo", #{ - "meta" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "MetaFields", #{ - "externalKey" -> "myExternalKey", - "globalKey" -> "myGlobalKey" - }) + "meta" -> MetaFields.builder.setExternalKey("myExternalKey").setGlobalKey("myGlobalKey") }) }) }) @@ -489,10 +474,7 @@ class FunctionGeneratorTest { val myInput = classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.test.model.metafields"), "ReferenceWithMetaFoo", #{ "value" -> classes.createInstanceUsingBuilder("Foo", #{ - "meta" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "MetaFields", #{ - "externalKey" -> "myExternalKey", - "globalKey" -> "myGlobalKey" - }) + "meta" -> MetaFields.builder.setExternalKey("myExternalKey").setGlobalKey("myGlobalKey") }) }) @@ -623,6 +605,8 @@ class FunctionGeneratorTest { def void testDeepFeatureCallWithMeta() { val code = ''' choice Foo: + [metadata key] + A B @@ -931,9 +915,7 @@ class FunctionGeneratorTest { }) val fooStrWithScheme = classes.createInstanceUsingBuilder("Foo", #{ "MyString" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "FieldWithMetaString", #{ - "meta" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "MetaFields", #{ - "scheme" -> "myScheme" - }), + "meta" -> MetaFields.builder.setScheme("myScheme"), "value" -> "abc123" }) }) @@ -1285,13 +1267,9 @@ class FunctionGeneratorTest { val aB = classes.createInstanceUsingBuilder("A", #{ "B" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.test.model.metafields"), "ReferenceWithMetaB", #{ "value" -> classes.createInstanceUsingBuilder("B", #{ - "meta" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "MetaFields", #{ - "key" -> #[Key.builder.setKeyValue("myKey")] - }), + "meta" -> MetaFields.builder.setKey(#[Key.builder.setKeyValue("myKey")]), "id" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "FieldWithMetaString", #{ - "meta" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "MetaFields", #{ - "scheme" -> "myScheme" - }), + "meta" -> MetaFields.builder.setScheme("myScheme"), "value" -> "abc123" }) }), @@ -1336,15 +1314,11 @@ class FunctionGeneratorTest { "prop" -> #[ classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "FieldWithMetaInteger", #{ - "meta" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "MetaFields", #{ - "scheme" -> "myScheme" - }), + "meta" -> MetaFields.builder.setScheme("myScheme"), "value" -> 42 }), classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "FieldWithMetaInteger", #{ - "meta" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "MetaFields", #{ - "scheme" -> "otherScheme" - }), + "meta" -> MetaFields.builder.setScheme("otherScheme"), "value" -> 0 }) ] @@ -1785,10 +1759,7 @@ class FunctionGeneratorTest { val classes = code.compileToClasses val objectWithKey = classes.createInstanceUsingBuilder('TypeWithKey', #{ - "meta" -> classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.model.metafields"), "MetaFields", #{ - "externalKey" -> "external", - "globalKey" -> "global" - }) + "meta" -> MetaFields.builder.setExternalKey("external").setGlobalKey("global") }) val objectWithKeyReference = classes.createInstanceUsingBuilder(new RootPackage("com.rosetta.test.model.metafields"), 'ReferenceWithMetaTypeWithKey', #{ "externalReference" -> "external", diff --git a/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/ModelMetaGeneratorTest.xtend b/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/ModelMetaGeneratorTest.xtend index 09f1c1f46..71085ec5c 100644 --- a/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/ModelMetaGeneratorTest.xtend +++ b/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/ModelMetaGeneratorTest.xtend @@ -133,9 +133,9 @@ class ModelMetaGeneratorTest { private List getComparisonResults(Foo o) { return Lists.newArrayList( - checkCardinality("a", (List) o.getA() == null ? 0 : ((List) o.getA()).size(), 1, 2), + checkCardinality("a", (List) o.getA() == null ? 0 : o.getA().size(), 1, 2), checkCardinality("b", (BigDecimal) o.getB() != null ? 1 : 0, 1, 1), - checkCardinality("c", (List) o.getC() == null ? 0 : ((List) o.getC()).size(), 1, 0), + checkCardinality("c", (List) o.getC() == null ? 0 : o.getC().size(), 1, 0), checkCardinality("d", (BigDecimal) o.getD() != null ? 1 : 0, 0, 1) ); } diff --git a/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/ModelObjectBuilderGeneratorTest.xtend b/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/ModelObjectBuilderGeneratorTest.xtend index bfe503b81..10ed592eb 100644 --- a/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/ModelObjectBuilderGeneratorTest.xtend +++ b/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/ModelObjectBuilderGeneratorTest.xtend @@ -111,8 +111,8 @@ class ModelObjectBuilderGeneratorTest { assertThat(testClassCode, containsString('One.OneBuilder singleOne;')) // Builder setters handles adding builder types - assertThat(testClassCode, containsString('public Test.TestBuilder setSingleOne(One singleOne) {')) - assertThat(testClassCode, containsString('public Test.TestBuilder addMultipleOnes(One multipleOnes) {')) + assertThat(testClassCode, containsString('public Test.TestBuilder setSingleOne(One _singleOne) {')) + assertThat(testClassCode, containsString('public Test.TestBuilder addMultipleOnes(One _multipleOnes) {')) code.compileToClasses } diff --git a/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/ModelObjectGeneratorTest.xtend b/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/ModelObjectGeneratorTest.xtend index c334ce15b..e55b62206 100644 --- a/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/ModelObjectGeneratorTest.xtend +++ b/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/ModelObjectGeneratorTest.xtend @@ -213,9 +213,11 @@ class ModelObjectGeneratorTest { def void shouldGenerateRosettaReferenceField() { val code = ''' type TestObject: <""> - fieldOne Test2 (0..1) [metadata reference] + fieldOne Test2 (0..1) + [metadata reference] type Test2: + [metadata key] '''.generateCode //code.writeClasses("objectTest") val classes = code.compileToClasses @@ -270,9 +272,11 @@ class ModelObjectGeneratorTest { val code = ''' type ComplexObject: + [metadata key] type TestObject: <""> - fieldOne ComplexObject (0..1) [metadata reference] + fieldOne ComplexObject (0..1) + [metadata reference] '''.generateCode //code.writeClasses("shouldCreateFieldWithReferenceTypeWhenAttributeIsReference") val generatedClass = code.compileToClasses diff --git a/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/PojoInheritanceRegressionTest.xtend b/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/PojoInheritanceRegressionTest.xtend new file mode 100644 index 000000000..d7b547bcb --- /dev/null +++ b/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/PojoInheritanceRegressionTest.xtend @@ -0,0 +1,1517 @@ +package com.regnosys.rosetta.generator.java.object + +import org.eclipse.xtext.testing.extensions.InjectionExtension +import org.junit.jupiter.api.^extension.ExtendWith +import org.eclipse.xtext.testing.InjectWith +import com.regnosys.rosetta.tests.RosettaInjectorProvider +import javax.inject.Inject +import com.regnosys.rosetta.tests.util.CodeGeneratorTestHelper +import org.junit.jupiter.api.Test + +import static org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.BeforeAll +import java.util.Map +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.TestInstance.Lifecycle + +/** + * This test is meant to prevent accidental changes to the generated code of + * Rosetta Model Objects related to inheritance. If any unwanted change accidentally + * gets through, please add to this test so it does not happen again. + */ +@ExtendWith(InjectionExtension) +@InjectWith(RosettaInjectorProvider) +@TestInstance(Lifecycle.PER_CLASS) +class PojoInheritanceRegressionTest { + @Inject extension CodeGeneratorTestHelper + + Map code + + @BeforeAll + def void setup() { + code = ''' + type Foo1: + attr int (1..1) + numberAttr number (0..1) + parent Parent (1..1) + parentList Parent (0..10) + stringAttr string (1..1) + [metadata scheme] + + type Foo2 extends Foo1: + override numberAttr int(digits: 30, max: 100) (1..1) + override parent Child (1..1) + override parentList Child (1..1) + [metadata reference] + override stringAttr string(maxLength: 42) (1..1) + + type Foo3 extends Foo2: + override numberAttr int (1..1) + override parentList GrandChild (1..1) + + type Parent: + + type Child extends Parent: + [metadata key] + + type GrandChild extends Child: + '''.generateCode + } + + private def void assertGeneratedCode(String className, String expected) { + assertEquals(expected, code.get(className)) + } + + @Test + def void testCodeCompiles() { + code.compileToClasses + } + + @Test + def void testFoo2Code() { + assertGeneratedCode('com.rosetta.test.model.Foo2', ''' + package com.rosetta.test.model; + + import com.rosetta.model.lib.RosettaModelObject; + import com.rosetta.model.lib.RosettaModelObjectBuilder; + import com.rosetta.model.lib.annotations.RosettaAttribute; + import com.rosetta.model.lib.annotations.RosettaDataType; + import com.rosetta.model.lib.mapper.MapperC; + import com.rosetta.model.lib.meta.RosettaMetaData; + import com.rosetta.model.lib.path.RosettaPath; + import com.rosetta.model.lib.process.BuilderMerger; + import com.rosetta.model.lib.process.BuilderProcessor; + import com.rosetta.model.lib.process.Processor; + import com.rosetta.model.metafields.FieldWithMetaString; + import com.rosetta.model.metafields.FieldWithMetaString.FieldWithMetaStringBuilder; + import com.rosetta.test.model.Child; + import com.rosetta.test.model.Child.ChildBuilder; + import com.rosetta.test.model.Foo1; + import com.rosetta.test.model.Foo1.Foo1Builder; + import com.rosetta.test.model.Foo2; + import com.rosetta.test.model.Foo2.Foo2Builder; + import com.rosetta.test.model.Foo2.Foo2BuilderImpl; + import com.rosetta.test.model.Foo2.Foo2Impl; + import com.rosetta.test.model.Parent; + import com.rosetta.test.model.Parent.ParentBuilder; + import com.rosetta.test.model.meta.Foo2Meta; + import com.rosetta.test.model.metafields.ReferenceWithMetaChild; + import com.rosetta.test.model.metafields.ReferenceWithMetaChild.ReferenceWithMetaChildBuilder; + import java.math.BigDecimal; + import java.math.BigInteger; + import java.util.Collections; + import java.util.List; + import java.util.Objects; + + import static java.util.Optional.ofNullable; + + /** + * @version test + */ + @RosettaDataType(value="Foo2", builder=Foo2.Foo2BuilderImpl.class, version="test") + public interface Foo2 extends Foo1 { + + Foo2Meta metaData = new Foo2Meta(); + + /*********************** Getter Methods ***********************/ + BigInteger getNumberAttrOverriddenAsBigInteger(); + @Override + Child getParent(); + ReferenceWithMetaChild getParentListOverriddenAsSingleReferenceWithMetaChild(); + + /*********************** Build Methods ***********************/ + Foo2 build(); + + Foo2.Foo2Builder toBuilder(); + + static Foo2.Foo2Builder builder() { + return new Foo2.Foo2BuilderImpl(); + } + + /*********************** Utility Methods ***********************/ + @Override + default RosettaMetaData metaData() { + return metaData; + } + + @Override + default Class getType() { + return Foo2.class; + } + + @Override + default void process(RosettaPath path, Processor processor) { + processor.processBasic(path.newSubPath("attr"), Integer.class, getAttr(), this); + processor.processBasic(path.newSubPath("numberAttr"), BigInteger.class, getNumberAttrOverriddenAsBigInteger(), this); + processRosetta(path.newSubPath("parent"), processor, Child.class, getParent()); + processRosetta(path.newSubPath("parentList"), processor, ReferenceWithMetaChild.class, getParentListOverriddenAsSingleReferenceWithMetaChild()); + processRosetta(path.newSubPath("stringAttr"), processor, FieldWithMetaString.class, getStringAttr()); + } + + + /*********************** Builder Interface ***********************/ + interface Foo2Builder extends Foo2, Foo1.Foo1Builder { + Child.ChildBuilder getOrCreateParent(); + @Override + Child.ChildBuilder getParent(); + ReferenceWithMetaChild.ReferenceWithMetaChildBuilder getOrCreateParentListOverriddenAsSingleReferenceWithMetaChild(); + @Override + ReferenceWithMetaChild.ReferenceWithMetaChildBuilder getParentListOverriddenAsSingleReferenceWithMetaChild(); + @Override + Foo2.Foo2Builder setAttr(Integer attr); + @Override + Foo2.Foo2Builder setNumberAttr(BigDecimal numberAttr); + @Override + Foo2.Foo2Builder setParent(Parent parent); + @Override + Foo2.Foo2Builder addParentList(Parent parentList); + @Override + Foo2.Foo2Builder addParentList(Parent parentList, int _idx); + @Override + Foo2.Foo2Builder addParentList(List parentList); + @Override + Foo2.Foo2Builder setParentList(List parentList); + @Override + Foo2.Foo2Builder setStringAttr(FieldWithMetaString stringAttr); + @Override + Foo2.Foo2Builder setStringAttrValue(String stringAttr); + Foo2.Foo2Builder setNumberAttr(BigInteger numberAttr); + Foo2.Foo2Builder setParent(Child parent); + Foo2.Foo2Builder setParentList(ReferenceWithMetaChild parentList); + Foo2.Foo2Builder setParentListValue(Child parentList); + + @Override + default void process(RosettaPath path, BuilderProcessor processor) { + processor.processBasic(path.newSubPath("attr"), Integer.class, getAttr(), this); + processor.processBasic(path.newSubPath("numberAttr"), BigInteger.class, getNumberAttrOverriddenAsBigInteger(), this); + processRosetta(path.newSubPath("parent"), processor, Child.ChildBuilder.class, getParent()); + processRosetta(path.newSubPath("parentList"), processor, ReferenceWithMetaChild.ReferenceWithMetaChildBuilder.class, getParentListOverriddenAsSingleReferenceWithMetaChild()); + processRosetta(path.newSubPath("stringAttr"), processor, FieldWithMetaString.FieldWithMetaStringBuilder.class, getStringAttr()); + } + + + Foo2.Foo2Builder prune(); + } + + /*********************** Immutable Implementation of Foo2 ***********************/ + class Foo2Impl implements Foo2 { + private final Integer attr; + private final BigInteger numberAttr; + private final Child parent; + private final ReferenceWithMetaChild parentList; + private final FieldWithMetaString stringAttr; + + protected Foo2Impl(Foo2.Foo2Builder builder) { + this.attr = builder.getAttr(); + this.numberAttr = builder.getNumberAttrOverriddenAsBigInteger(); + this.parent = ofNullable(builder.getParent()).map(f->f.build()).orElse(null); + this.parentList = ofNullable(builder.getParentListOverriddenAsSingleReferenceWithMetaChild()).map(f->f.build()).orElse(null); + this.stringAttr = ofNullable(builder.getStringAttr()).map(f->f.build()).orElse(null); + } + + @Override + @RosettaAttribute("attr") + public Integer getAttr() { + return attr; + } + + @Override + @RosettaAttribute("numberAttr") + public BigInteger getNumberAttrOverriddenAsBigInteger() { + return numberAttr; + } + + @Override + public BigDecimal getNumberAttr() { + return numberAttr == null ? null : new BigDecimal(numberAttr); + } + + @Override + @RosettaAttribute("parent") + public Child getParent() { + return parent; + } + + @Override + @RosettaAttribute("parentList") + public ReferenceWithMetaChild getParentListOverriddenAsSingleReferenceWithMetaChild() { + return parentList; + } + + @Override + public List getParentList() { + return parentList == null ? Collections.emptyList() : Collections.singletonList(parentList.getValue()); + } + + @Override + @RosettaAttribute("stringAttr") + public FieldWithMetaString getStringAttr() { + return stringAttr; + } + + @Override + public Foo2 build() { + return this; + } + + @Override + public Foo2.Foo2Builder toBuilder() { + Foo2.Foo2Builder builder = builder(); + setBuilderFields(builder); + return builder; + } + + protected void setBuilderFields(Foo2.Foo2Builder builder) { + ofNullable(getAttr()).ifPresent(builder::setAttr); + ofNullable(getNumberAttrOverriddenAsBigInteger()).ifPresent(builder::setNumberAttr); + ofNullable(getParent()).ifPresent(builder::setParent); + ofNullable(getParentListOverriddenAsSingleReferenceWithMetaChild()).ifPresent(builder::setParentList); + ofNullable(getStringAttr()).ifPresent(builder::setStringAttr); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !(o instanceof RosettaModelObject) || !getType().equals(((RosettaModelObject)o).getType())) return false; + + Foo2 _that = getType().cast(o); + + if (!Objects.equals(attr, _that.getAttr())) return false; + if (!Objects.equals(numberAttr, _that.getNumberAttrOverriddenAsBigInteger())) return false; + if (!Objects.equals(parent, _that.getParent())) return false; + if (!Objects.equals(parentList, _that.getParentListOverriddenAsSingleReferenceWithMetaChild())) return false; + if (!Objects.equals(stringAttr, _that.getStringAttr())) return false; + return true; + } + + @Override + public int hashCode() { + int _result = 0; + _result = 31 * _result + (attr != null ? attr.hashCode() : 0); + _result = 31 * _result + (numberAttr != null ? numberAttr.hashCode() : 0); + _result = 31 * _result + (parent != null ? parent.hashCode() : 0); + _result = 31 * _result + (parentList != null ? parentList.hashCode() : 0); + _result = 31 * _result + (stringAttr != null ? stringAttr.hashCode() : 0); + return _result; + } + + @Override + public String toString() { + return "Foo2 {" + + "attr=" + this.attr + ", " + + "numberAttr=" + this.numberAttr + ", " + + "parent=" + this.parent + ", " + + "parentList=" + this.parentList + ", " + + "stringAttr=" + this.stringAttr + + '}'; + } + } + + /*********************** Builder Implementation of Foo2 ***********************/ + class Foo2BuilderImpl implements Foo2.Foo2Builder { + + protected Integer attr; + protected BigInteger numberAttr; + protected Child.ChildBuilder parent; + protected ReferenceWithMetaChild.ReferenceWithMetaChildBuilder parentList; + protected FieldWithMetaString.FieldWithMetaStringBuilder stringAttr; + + @Override + @RosettaAttribute("attr") + public Integer getAttr() { + return attr; + } + + @Override + @RosettaAttribute("numberAttr") + public BigInteger getNumberAttrOverriddenAsBigInteger() { + return numberAttr; + } + + @Override + public BigDecimal getNumberAttr() { + return numberAttr == null ? null : new BigDecimal(numberAttr); + } + + @Override + @RosettaAttribute("parent") + public Child.ChildBuilder getParent() { + return parent; + } + + @Override + public Child.ChildBuilder getOrCreateParent() { + Child.ChildBuilder result; + if (parent!=null) { + result = parent; + } + else { + result = parent = Child.builder(); + } + + return result; + } + + @Override + @RosettaAttribute("parentList") + public ReferenceWithMetaChild.ReferenceWithMetaChildBuilder getParentListOverriddenAsSingleReferenceWithMetaChild() { + return parentList; + } + + @Override + public ReferenceWithMetaChild.ReferenceWithMetaChildBuilder getOrCreateParentListOverriddenAsSingleReferenceWithMetaChild() { + ReferenceWithMetaChild.ReferenceWithMetaChildBuilder result; + if (parentList!=null) { + result = parentList; + } + else { + result = parentList = ReferenceWithMetaChild.builder(); + } + + return result; + } + + @Override + public List getParentList() { + return parentList == null ? Collections.emptyList() : Collections.singletonList(parentList.getValue().toBuilder()); + } + + @Override + public Parent.ParentBuilder getOrCreateParentList(int _index) { + final ReferenceWithMetaChild referenceWithMetaChild = getOrCreateParentListOverriddenAsSingleReferenceWithMetaChild(); + return referenceWithMetaChild == null ? null : referenceWithMetaChild.getValue().toBuilder(); + } + + @Override + @RosettaAttribute("stringAttr") + public FieldWithMetaString.FieldWithMetaStringBuilder getStringAttr() { + return stringAttr; + } + + @Override + public FieldWithMetaString.FieldWithMetaStringBuilder getOrCreateStringAttr() { + FieldWithMetaString.FieldWithMetaStringBuilder result; + if (stringAttr!=null) { + result = stringAttr; + } + else { + result = stringAttr = FieldWithMetaString.builder(); + } + + return result; + } + + @Override + @RosettaAttribute("attr") + public Foo2.Foo2Builder setAttr(Integer _attr) { + this.attr = _attr == null ? null : _attr; + return this; + } + + @Override + @RosettaAttribute("numberAttr") + public Foo2.Foo2Builder setNumberAttr(BigInteger _numberAttr) { + this.numberAttr = _numberAttr == null ? null : _numberAttr; + return this; + } + + @Override + public Foo2.Foo2Builder setNumberAttr(BigDecimal _numberAttr) { + final BigInteger ifThenElseResult; + if (_numberAttr == null) { + ifThenElseResult = null; + } else { + ifThenElseResult = new BigDecimal(_numberAttr.toBigInteger()).compareTo(_numberAttr) == 0 ? _numberAttr.toBigInteger() : null; + } + return setNumberAttr(ifThenElseResult); + } + + @Override + @RosettaAttribute("parent") + public Foo2.Foo2Builder setParent(Child _parent) { + this.parent = _parent == null ? null : _parent.toBuilder(); + return this; + } + + @Override + public Foo2.Foo2Builder setParent(Parent _parent) { + final Child ifThenElseResult; + if (_parent == null) { + ifThenElseResult = null; + } else { + ifThenElseResult = _parent instanceof Child ? Child.class.cast(_parent) : null; + } + return setParent(ifThenElseResult); + } + + @Override + @RosettaAttribute("parentList") + public Foo2.Foo2Builder setParentList(ReferenceWithMetaChild _parentList) { + this.parentList = _parentList == null ? null : _parentList.toBuilder(); + return this; + } + + @Override + public Foo2.Foo2Builder setParentListValue(Child _parentList) { + this.getOrCreateParentListOverriddenAsSingleReferenceWithMetaChild().setValue(_parentList); + return this; + } + + @Override + public Foo2.Foo2Builder addParentList(Parent parentList0) { + final ReferenceWithMetaChild ifThenElseResult; + if (parentList0 == null) { + ifThenElseResult = null; + } else { + ifThenElseResult = parentList0 instanceof Child ? ReferenceWithMetaChild.builder().setValue(Child.class.cast(parentList0)).build() : ReferenceWithMetaChild.builder().setValue(null).build(); + } + return setParentList(ifThenElseResult); + } + + @Override + public Foo2.Foo2Builder addParentList(Parent _parentList, int _idx) { + final ReferenceWithMetaChild ifThenElseResult; + if (_parentList == null) { + ifThenElseResult = null; + } else { + ifThenElseResult = _parentList instanceof Child ? ReferenceWithMetaChild.builder().setValue(Child.class.cast(_parentList)).build() : ReferenceWithMetaChild.builder().setValue(null).build(); + } + return setParentList(ifThenElseResult); + } + + @Override + public Foo2.Foo2Builder addParentList(List parentLists) { + final Parent _parent = MapperC.of(parentLists).get(); + final ReferenceWithMetaChild ifThenElseResult; + if (_parent == null) { + ifThenElseResult = null; + } else { + ifThenElseResult = _parent instanceof Child ? ReferenceWithMetaChild.builder().setValue(Child.class.cast(_parent)).build() : ReferenceWithMetaChild.builder().setValue(null).build(); + } + return setParentList(ifThenElseResult); + } + + @Override + public Foo2.Foo2Builder setParentList(List parentLists) { + final Parent _parent = MapperC.of(parentLists).get(); + final ReferenceWithMetaChild ifThenElseResult; + if (_parent == null) { + ifThenElseResult = null; + } else { + ifThenElseResult = _parent instanceof Child ? ReferenceWithMetaChild.builder().setValue(Child.class.cast(_parent)).build() : ReferenceWithMetaChild.builder().setValue(null).build(); + } + return setParentList(ifThenElseResult); + } + + @Override + @RosettaAttribute("stringAttr") + public Foo2.Foo2Builder setStringAttr(FieldWithMetaString _stringAttr) { + this.stringAttr = _stringAttr == null ? null : _stringAttr.toBuilder(); + return this; + } + + @Override + public Foo2.Foo2Builder setStringAttrValue(String _stringAttr) { + this.getOrCreateStringAttr().setValue(_stringAttr); + return this; + } + + @Override + public Foo2 build() { + return new Foo2.Foo2Impl(this); + } + + @Override + public Foo2.Foo2Builder toBuilder() { + return this; + } + + @SuppressWarnings("unchecked") + @Override + public Foo2.Foo2Builder prune() { + if (parent!=null && !parent.prune().hasData()) parent = null; + if (parentList!=null && !parentList.prune().hasData()) parentList = null; + if (stringAttr!=null && !stringAttr.prune().hasData()) stringAttr = null; + return this; + } + + @Override + public boolean hasData() { + if (getAttr()!=null) return true; + if (getNumberAttrOverriddenAsBigInteger()!=null) return true; + if (getParent()!=null && getParent().hasData()) return true; + if (getParentListOverriddenAsSingleReferenceWithMetaChild()!=null && getParentListOverriddenAsSingleReferenceWithMetaChild().hasData()) return true; + if (getStringAttr()!=null) return true; + return false; + } + + @SuppressWarnings("unchecked") + @Override + public Foo2.Foo2Builder merge(RosettaModelObjectBuilder other, BuilderMerger merger) { + Foo2.Foo2Builder o = (Foo2.Foo2Builder) other; + + merger.mergeRosetta(getParent(), o.getParent(), this::setParent); + merger.mergeRosetta(getParentListOverriddenAsSingleReferenceWithMetaChild(), o.getParentListOverriddenAsSingleReferenceWithMetaChild(), this::setParentList); + merger.mergeRosetta(getStringAttr(), o.getStringAttr(), this::setStringAttr); + + merger.mergeBasic(getAttr(), o.getAttr(), this::setAttr); + merger.mergeBasic(getNumberAttrOverriddenAsBigInteger(), o.getNumberAttrOverriddenAsBigInteger(), this::setNumberAttr); + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !(o instanceof RosettaModelObject) || !getType().equals(((RosettaModelObject)o).getType())) return false; + + Foo2 _that = getType().cast(o); + + if (!Objects.equals(attr, _that.getAttr())) return false; + if (!Objects.equals(numberAttr, _that.getNumberAttrOverriddenAsBigInteger())) return false; + if (!Objects.equals(parent, _that.getParent())) return false; + if (!Objects.equals(parentList, _that.getParentListOverriddenAsSingleReferenceWithMetaChild())) return false; + if (!Objects.equals(stringAttr, _that.getStringAttr())) return false; + return true; + } + + @Override + public int hashCode() { + int _result = 0; + _result = 31 * _result + (attr != null ? attr.hashCode() : 0); + _result = 31 * _result + (numberAttr != null ? numberAttr.hashCode() : 0); + _result = 31 * _result + (parent != null ? parent.hashCode() : 0); + _result = 31 * _result + (parentList != null ? parentList.hashCode() : 0); + _result = 31 * _result + (stringAttr != null ? stringAttr.hashCode() : 0); + return _result; + } + + @Override + public String toString() { + return "Foo2Builder {" + + "attr=" + this.attr + ", " + + "numberAttr=" + this.numberAttr + ", " + + "parent=" + this.parent + ", " + + "parentList=" + this.parentList + ", " + + "stringAttr=" + this.stringAttr + + '}'; + } + } + } + ''') + } + + @Test + def void testFoo2TypeFormatValidator() { + assertGeneratedCode('com.rosetta.test.model.validation.Foo2TypeFormatValidator', ''' + package com.rosetta.test.model.validation; + + import com.google.common.collect.Lists; + import com.rosetta.model.lib.expression.ComparisonResult; + import com.rosetta.model.lib.path.RosettaPath; + import com.rosetta.model.lib.validation.ValidationResult; + import com.rosetta.model.lib.validation.ValidationResult.ValidationType; + import com.rosetta.model.lib.validation.Validator; + import com.rosetta.test.model.Foo2; + import java.math.BigDecimal; + import java.util.List; + + import static com.google.common.base.Strings.isNullOrEmpty; + import static com.rosetta.model.lib.expression.ExpressionOperators.checkNumber; + import static com.rosetta.model.lib.expression.ExpressionOperators.checkString; + import static com.rosetta.model.lib.validation.ValidationResult.failure; + import static com.rosetta.model.lib.validation.ValidationResult.success; + import static java.util.Optional.empty; + import static java.util.Optional.of; + import static java.util.stream.Collectors.joining; + import static java.util.stream.Collectors.toList; + + public class Foo2TypeFormatValidator implements Validator { + + private List getComparisonResults(Foo2 o) { + return Lists.newArrayList( + checkNumber("attr", o.getAttr(), empty(), of(0), empty(), empty()), + checkNumber("numberAttr", o.getNumberAttrOverriddenAsBigInteger(), of(30), of(0), empty(), of(new BigDecimal("1E+2"))), + checkString("stringAttr", o.getStringAttr().getValue(), 0, of(42), empty()) + ); + } + + @Override + public ValidationResult validate(RosettaPath path, Foo2 o) { + String error = getComparisonResults(o) + .stream() + .filter(res -> !res.get()) + .map(res -> res.getError()) + .collect(joining("; ")); + + if (!isNullOrEmpty(error)) { + return failure("Foo2", ValidationType.TYPE_FORMAT, "Foo2", path, "", error); + } + return success("Foo2", ValidationType.TYPE_FORMAT, "Foo2", path, ""); + } + + @Override + public List> getValidationResults(RosettaPath path, Foo2 o) { + return getComparisonResults(o) + .stream() + .map(res -> { + if (!isNullOrEmpty(res.getError())) { + return failure("Foo2", ValidationType.TYPE_FORMAT, "Foo2", path, "", res.getError()); + } + return success("Foo2", ValidationType.TYPE_FORMAT, "Foo2", path, ""); + }) + .collect(toList()); + } + + } + ''') + } + + @Test + def void testFoo2OnlyExistsValidator() { + assertGeneratedCode('com.rosetta.test.model.validation.exists.Foo2OnlyExistsValidator', ''' + package com.rosetta.test.model.validation.exists; + + import com.google.common.collect.ImmutableMap; + import com.rosetta.model.lib.path.RosettaPath; + import com.rosetta.model.lib.validation.ExistenceChecker; + import com.rosetta.model.lib.validation.ValidationResult; + import com.rosetta.model.lib.validation.ValidationResult.ValidationType; + import com.rosetta.model.lib.validation.ValidatorWithArg; + import com.rosetta.model.metafields.FieldWithMetaString; + import com.rosetta.test.model.Child; + import com.rosetta.test.model.Foo2; + import com.rosetta.test.model.metafields.ReferenceWithMetaChild; + import java.math.BigInteger; + import java.util.Map; + import java.util.Set; + import java.util.stream.Collectors; + + import static com.rosetta.model.lib.validation.ValidationResult.failure; + import static com.rosetta.model.lib.validation.ValidationResult.success; + + public class Foo2OnlyExistsValidator implements ValidatorWithArg> { + + /* Casting is required to ensure types are output to ensure recompilation in Rosetta */ + @Override + public ValidationResult validate(RosettaPath path, T2 o, Set fields) { + Map fieldExistenceMap = ImmutableMap.builder() + .put("attr", ExistenceChecker.isSet((Integer) o.getAttr())) + .put("numberAttr", ExistenceChecker.isSet((BigInteger) o.getNumberAttrOverriddenAsBigInteger())) + .put("parent", ExistenceChecker.isSet((Child) o.getParent())) + .put("parentList", ExistenceChecker.isSet((ReferenceWithMetaChild) o.getParentListOverriddenAsSingleReferenceWithMetaChild())) + .put("stringAttr", ExistenceChecker.isSet((FieldWithMetaString) o.getStringAttr())) + .build(); + + // Find the fields that are set + Set setFields = fieldExistenceMap.entrySet().stream() + .filter(Map.Entry::getValue) + .map(Map.Entry::getKey) + .collect(Collectors.toSet()); + + if (setFields.equals(fields)) { + return success("Foo2", ValidationType.ONLY_EXISTS, "Foo2", path, ""); + } + return failure("Foo2", ValidationType.ONLY_EXISTS, "Foo2", path, "", + String.format("[%s] should only be set. Set fields: %s", fields, setFields)); + } + } + ''') + } + + @Test + def void testFoo3Code() { + assertGeneratedCode('com.rosetta.test.model.Foo3', ''' + package com.rosetta.test.model; + + import com.rosetta.model.lib.RosettaModelObject; + import com.rosetta.model.lib.RosettaModelObjectBuilder; + import com.rosetta.model.lib.annotations.RosettaAttribute; + import com.rosetta.model.lib.annotations.RosettaDataType; + import com.rosetta.model.lib.mapper.MapperC; + import com.rosetta.model.lib.meta.RosettaMetaData; + import com.rosetta.model.lib.path.RosettaPath; + import com.rosetta.model.lib.process.BuilderMerger; + import com.rosetta.model.lib.process.BuilderProcessor; + import com.rosetta.model.lib.process.Processor; + import com.rosetta.model.metafields.FieldWithMetaString; + import com.rosetta.model.metafields.FieldWithMetaString.FieldWithMetaStringBuilder; + import com.rosetta.test.model.Child; + import com.rosetta.test.model.Child.ChildBuilder; + import com.rosetta.test.model.Foo2; + import com.rosetta.test.model.Foo2.Foo2Builder; + import com.rosetta.test.model.Foo3; + import com.rosetta.test.model.Foo3.Foo3Builder; + import com.rosetta.test.model.Foo3.Foo3BuilderImpl; + import com.rosetta.test.model.Foo3.Foo3Impl; + import com.rosetta.test.model.GrandChild; + import com.rosetta.test.model.Parent; + import com.rosetta.test.model.Parent.ParentBuilder; + import com.rosetta.test.model.meta.Foo3Meta; + import com.rosetta.test.model.metafields.ReferenceWithMetaChild; + import com.rosetta.test.model.metafields.ReferenceWithMetaChild.ReferenceWithMetaChildBuilder; + import com.rosetta.test.model.metafields.ReferenceWithMetaGrandChild; + import com.rosetta.test.model.metafields.ReferenceWithMetaGrandChild.ReferenceWithMetaGrandChildBuilder; + import java.math.BigDecimal; + import java.math.BigInteger; + import java.util.Collections; + import java.util.List; + import java.util.Objects; + + import static java.util.Optional.ofNullable; + + /** + * @version test + */ + @RosettaDataType(value="Foo3", builder=Foo3.Foo3BuilderImpl.class, version="test") + public interface Foo3 extends Foo2 { + + Foo3Meta metaData = new Foo3Meta(); + + /*********************** Getter Methods ***********************/ + Integer getNumberAttrOverriddenAsInteger(); + ReferenceWithMetaGrandChild getParentListOverriddenAsReferenceWithMetaGrandChild(); + + /*********************** Build Methods ***********************/ + Foo3 build(); + + Foo3.Foo3Builder toBuilder(); + + static Foo3.Foo3Builder builder() { + return new Foo3.Foo3BuilderImpl(); + } + + /*********************** Utility Methods ***********************/ + @Override + default RosettaMetaData metaData() { + return metaData; + } + + @Override + default Class getType() { + return Foo3.class; + } + + @Override + default void process(RosettaPath path, Processor processor) { + processor.processBasic(path.newSubPath("attr"), Integer.class, getAttr(), this); + processor.processBasic(path.newSubPath("numberAttr"), Integer.class, getNumberAttrOverriddenAsInteger(), this); + processRosetta(path.newSubPath("parent"), processor, Child.class, getParent()); + processRosetta(path.newSubPath("parentList"), processor, ReferenceWithMetaGrandChild.class, getParentListOverriddenAsReferenceWithMetaGrandChild()); + processRosetta(path.newSubPath("stringAttr"), processor, FieldWithMetaString.class, getStringAttr()); + } + + + /*********************** Builder Interface ***********************/ + interface Foo3Builder extends Foo3, Foo2.Foo2Builder { + ReferenceWithMetaGrandChild.ReferenceWithMetaGrandChildBuilder getOrCreateParentListOverriddenAsReferenceWithMetaGrandChild(); + @Override + ReferenceWithMetaGrandChild.ReferenceWithMetaGrandChildBuilder getParentListOverriddenAsReferenceWithMetaGrandChild(); + @Override + Foo3.Foo3Builder setAttr(Integer attr); + @Override + Foo3.Foo3Builder setNumberAttr(BigDecimal numberAttr); + @Override + Foo3.Foo3Builder setParent(Parent parent); + @Override + Foo3.Foo3Builder addParentList(Parent parentList); + @Override + Foo3.Foo3Builder addParentList(Parent parentList, int _idx); + @Override + Foo3.Foo3Builder addParentList(List parentList); + @Override + Foo3.Foo3Builder setParentList(List parentList); + @Override + Foo3.Foo3Builder setStringAttr(FieldWithMetaString stringAttr); + @Override + Foo3.Foo3Builder setStringAttrValue(String stringAttr); + @Override + Foo3.Foo3Builder setNumberAttr(BigInteger numberAttr); + @Override + Foo3.Foo3Builder setParent(Child parent); + @Override + Foo3.Foo3Builder setParentList(ReferenceWithMetaChild parentList); + @Override + Foo3.Foo3Builder setParentListValue(Child parentList); + Foo3.Foo3Builder setNumberAttr(Integer numberAttr); + Foo3.Foo3Builder setParentList(ReferenceWithMetaGrandChild parentList); + Foo3.Foo3Builder setParentListValue(GrandChild parentList); + + @Override + default void process(RosettaPath path, BuilderProcessor processor) { + processor.processBasic(path.newSubPath("attr"), Integer.class, getAttr(), this); + processor.processBasic(path.newSubPath("numberAttr"), Integer.class, getNumberAttrOverriddenAsInteger(), this); + processRosetta(path.newSubPath("parent"), processor, Child.ChildBuilder.class, getParent()); + processRosetta(path.newSubPath("parentList"), processor, ReferenceWithMetaGrandChild.ReferenceWithMetaGrandChildBuilder.class, getParentListOverriddenAsReferenceWithMetaGrandChild()); + processRosetta(path.newSubPath("stringAttr"), processor, FieldWithMetaString.FieldWithMetaStringBuilder.class, getStringAttr()); + } + + + Foo3.Foo3Builder prune(); + } + + /*********************** Immutable Implementation of Foo3 ***********************/ + class Foo3Impl implements Foo3 { + private final Integer attr; + private final Integer numberAttr; + private final Child parent; + private final ReferenceWithMetaGrandChild parentList; + private final FieldWithMetaString stringAttr; + + protected Foo3Impl(Foo3.Foo3Builder builder) { + this.attr = builder.getAttr(); + this.numberAttr = builder.getNumberAttrOverriddenAsInteger(); + this.parent = ofNullable(builder.getParent()).map(f->f.build()).orElse(null); + this.parentList = ofNullable(builder.getParentListOverriddenAsReferenceWithMetaGrandChild()).map(f->f.build()).orElse(null); + this.stringAttr = ofNullable(builder.getStringAttr()).map(f->f.build()).orElse(null); + } + + @Override + @RosettaAttribute("attr") + public Integer getAttr() { + return attr; + } + + @Override + @RosettaAttribute("numberAttr") + public Integer getNumberAttrOverriddenAsInteger() { + return numberAttr; + } + + @Override + public BigInteger getNumberAttrOverriddenAsBigInteger() { + return numberAttr == null ? null : BigInteger.valueOf(numberAttr); + } + + @Override + public BigDecimal getNumberAttr() { + return numberAttr == null ? null : BigDecimal.valueOf(numberAttr); + } + + @Override + @RosettaAttribute("parent") + public Child getParent() { + return parent; + } + + @Override + @RosettaAttribute("parentList") + public ReferenceWithMetaGrandChild getParentListOverriddenAsReferenceWithMetaGrandChild() { + return parentList; + } + + @Override + public ReferenceWithMetaChild getParentListOverriddenAsSingleReferenceWithMetaChild() { + if (parentList == null) { + return null; + } + final GrandChild grandChild = parentList.getValue(); + return grandChild == null ? null : ReferenceWithMetaChild.builder().setValue(grandChild).build(); + } + + @Override + public List getParentList() { + return parentList == null ? Collections.emptyList() : Collections.singletonList(parentList.getValue()); + } + + @Override + @RosettaAttribute("stringAttr") + public FieldWithMetaString getStringAttr() { + return stringAttr; + } + + @Override + public Foo3 build() { + return this; + } + + @Override + public Foo3.Foo3Builder toBuilder() { + Foo3.Foo3Builder builder = builder(); + setBuilderFields(builder); + return builder; + } + + protected void setBuilderFields(Foo3.Foo3Builder builder) { + ofNullable(getAttr()).ifPresent(builder::setAttr); + ofNullable(getNumberAttrOverriddenAsInteger()).ifPresent(builder::setNumberAttr); + ofNullable(getParent()).ifPresent(builder::setParent); + ofNullable(getParentListOverriddenAsReferenceWithMetaGrandChild()).ifPresent(builder::setParentList); + ofNullable(getStringAttr()).ifPresent(builder::setStringAttr); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !(o instanceof RosettaModelObject) || !getType().equals(((RosettaModelObject)o).getType())) return false; + + Foo3 _that = getType().cast(o); + + if (!Objects.equals(attr, _that.getAttr())) return false; + if (!Objects.equals(numberAttr, _that.getNumberAttrOverriddenAsInteger())) return false; + if (!Objects.equals(parent, _that.getParent())) return false; + if (!Objects.equals(parentList, _that.getParentListOverriddenAsReferenceWithMetaGrandChild())) return false; + if (!Objects.equals(stringAttr, _that.getStringAttr())) return false; + return true; + } + + @Override + public int hashCode() { + int _result = 0; + _result = 31 * _result + (attr != null ? attr.hashCode() : 0); + _result = 31 * _result + (numberAttr != null ? numberAttr.hashCode() : 0); + _result = 31 * _result + (parent != null ? parent.hashCode() : 0); + _result = 31 * _result + (parentList != null ? parentList.hashCode() : 0); + _result = 31 * _result + (stringAttr != null ? stringAttr.hashCode() : 0); + return _result; + } + + @Override + public String toString() { + return "Foo3 {" + + "attr=" + this.attr + ", " + + "numberAttr=" + this.numberAttr + ", " + + "parent=" + this.parent + ", " + + "parentList=" + this.parentList + ", " + + "stringAttr=" + this.stringAttr + + '}'; + } + } + + /*********************** Builder Implementation of Foo3 ***********************/ + class Foo3BuilderImpl implements Foo3.Foo3Builder { + + protected Integer attr; + protected Integer numberAttr; + protected Child.ChildBuilder parent; + protected ReferenceWithMetaGrandChild.ReferenceWithMetaGrandChildBuilder parentList; + protected FieldWithMetaString.FieldWithMetaStringBuilder stringAttr; + + @Override + @RosettaAttribute("attr") + public Integer getAttr() { + return attr; + } + + @Override + @RosettaAttribute("numberAttr") + public Integer getNumberAttrOverriddenAsInteger() { + return numberAttr; + } + + @Override + public BigInteger getNumberAttrOverriddenAsBigInteger() { + return numberAttr == null ? null : BigInteger.valueOf(numberAttr); + } + + @Override + public BigDecimal getNumberAttr() { + return numberAttr == null ? null : BigDecimal.valueOf(numberAttr); + } + + @Override + @RosettaAttribute("parent") + public Child.ChildBuilder getParent() { + return parent; + } + + @Override + public Child.ChildBuilder getOrCreateParent() { + Child.ChildBuilder result; + if (parent!=null) { + result = parent; + } + else { + result = parent = Child.builder(); + } + + return result; + } + + @Override + @RosettaAttribute("parentList") + public ReferenceWithMetaGrandChild.ReferenceWithMetaGrandChildBuilder getParentListOverriddenAsReferenceWithMetaGrandChild() { + return parentList; + } + + @Override + public ReferenceWithMetaGrandChild.ReferenceWithMetaGrandChildBuilder getOrCreateParentListOverriddenAsReferenceWithMetaGrandChild() { + ReferenceWithMetaGrandChild.ReferenceWithMetaGrandChildBuilder result; + if (parentList!=null) { + result = parentList; + } + else { + result = parentList = ReferenceWithMetaGrandChild.builder(); + } + + return result; + } + + @Override + public ReferenceWithMetaChild.ReferenceWithMetaChildBuilder getParentListOverriddenAsSingleReferenceWithMetaChild() { + if (parentList == null) { + return null; + } + final GrandChild _grandChild = parentList.getValue(); + return _grandChild == null ? null : ReferenceWithMetaChild.builder().setValue(_grandChild).build().toBuilder(); + } + + @Override + public ReferenceWithMetaChild.ReferenceWithMetaChildBuilder getOrCreateParentListOverriddenAsSingleReferenceWithMetaChild() { + final ReferenceWithMetaGrandChild referenceWithMetaGrandChild0 = getOrCreateParentListOverriddenAsReferenceWithMetaGrandChild(); + if (referenceWithMetaGrandChild0 == null) { + return null; + } + final GrandChild grandChild = referenceWithMetaGrandChild0.getValue(); + return grandChild == null ? null : ReferenceWithMetaChild.builder().setValue(grandChild).build().toBuilder(); + } + + @Override + public List getParentList() { + return parentList == null ? Collections.emptyList() : Collections.singletonList(parentList.getValue().toBuilder()); + } + + @Override + public Parent.ParentBuilder getOrCreateParentList(int _index) { + final ReferenceWithMetaGrandChild referenceWithMetaGrandChild1 = getOrCreateParentListOverriddenAsReferenceWithMetaGrandChild(); + return referenceWithMetaGrandChild1 == null ? null : referenceWithMetaGrandChild1.getValue().toBuilder(); + } + + @Override + @RosettaAttribute("stringAttr") + public FieldWithMetaString.FieldWithMetaStringBuilder getStringAttr() { + return stringAttr; + } + + @Override + public FieldWithMetaString.FieldWithMetaStringBuilder getOrCreateStringAttr() { + FieldWithMetaString.FieldWithMetaStringBuilder result; + if (stringAttr!=null) { + result = stringAttr; + } + else { + result = stringAttr = FieldWithMetaString.builder(); + } + + return result; + } + + @Override + @RosettaAttribute("attr") + public Foo3.Foo3Builder setAttr(Integer _attr) { + this.attr = _attr == null ? null : _attr; + return this; + } + + @Override + @RosettaAttribute("numberAttr") + public Foo3.Foo3Builder setNumberAttr(Integer _numberAttr) { + this.numberAttr = _numberAttr == null ? null : _numberAttr; + return this; + } + + @Override + public Foo3.Foo3Builder setNumberAttr(BigInteger _numberAttr) { + final Integer ifThenElseResult; + if (_numberAttr == null) { + ifThenElseResult = null; + } else { + ifThenElseResult = BigInteger.valueOf(_numberAttr.intValue()).equals(_numberAttr) ? _numberAttr.intValue() : null; + } + return setNumberAttr(ifThenElseResult); + } + + @Override + public Foo3.Foo3Builder setNumberAttr(BigDecimal _numberAttr) { + final Integer ifThenElseResult; + if (_numberAttr == null) { + ifThenElseResult = null; + } else { + ifThenElseResult = BigDecimal.valueOf(_numberAttr.intValue()).compareTo(_numberAttr) == 0 ? _numberAttr.intValue() : null; + } + return setNumberAttr(ifThenElseResult); + } + + @Override + @RosettaAttribute("parent") + public Foo3.Foo3Builder setParent(Child _parent) { + this.parent = _parent == null ? null : _parent.toBuilder(); + return this; + } + + @Override + public Foo3.Foo3Builder setParent(Parent _parent) { + final Child ifThenElseResult; + if (_parent == null) { + ifThenElseResult = null; + } else { + ifThenElseResult = _parent instanceof Child ? Child.class.cast(_parent) : null; + } + return setParent(ifThenElseResult); + } + + @Override + @RosettaAttribute("parentList") + public Foo3.Foo3Builder setParentList(ReferenceWithMetaGrandChild _parentList) { + this.parentList = _parentList == null ? null : _parentList.toBuilder(); + return this; + } + + @Override + public Foo3.Foo3Builder setParentListValue(GrandChild _parentList) { + this.getOrCreateParentListOverriddenAsReferenceWithMetaGrandChild().setValue(_parentList); + return this; + } + + @Override + public Foo3.Foo3Builder setParentList(ReferenceWithMetaChild _parentList) { + final ReferenceWithMetaGrandChild ifThenElseResult; + if (_parentList == null) { + ifThenElseResult = null; + } else { + final Child child = _parentList.getValue(); + if (child == null) { + ifThenElseResult = null; + } else { + ifThenElseResult = child instanceof GrandChild ? ReferenceWithMetaGrandChild.builder().setValue(GrandChild.class.cast(child)).build() : ReferenceWithMetaGrandChild.builder().setValue(null).build(); + } + } + return setParentList(ifThenElseResult); + } + + @Override + public Foo3.Foo3Builder setParentListValue(Child _parentList) { + final GrandChild ifThenElseResult; + if (_parentList == null) { + ifThenElseResult = null; + } else { + ifThenElseResult = _parentList instanceof GrandChild ? GrandChild.class.cast(_parentList) : null; + } + return setParentListValue(ifThenElseResult); + } + + @Override + public Foo3.Foo3Builder addParentList(Parent parentList0) { + final ReferenceWithMetaGrandChild ifThenElseResult; + if (parentList0 == null) { + ifThenElseResult = null; + } else { + ifThenElseResult = parentList0 instanceof GrandChild ? ReferenceWithMetaGrandChild.builder().setValue(GrandChild.class.cast(parentList0)).build() : ReferenceWithMetaGrandChild.builder().setValue(null).build(); + } + return setParentList(ifThenElseResult); + } + + @Override + public Foo3.Foo3Builder addParentList(Parent _parentList, int _idx) { + final ReferenceWithMetaGrandChild ifThenElseResult; + if (_parentList == null) { + ifThenElseResult = null; + } else { + ifThenElseResult = _parentList instanceof GrandChild ? ReferenceWithMetaGrandChild.builder().setValue(GrandChild.class.cast(_parentList)).build() : ReferenceWithMetaGrandChild.builder().setValue(null).build(); + } + return setParentList(ifThenElseResult); + } + + @Override + public Foo3.Foo3Builder addParentList(List parentLists) { + final Parent _parent = MapperC.of(parentLists).get(); + final ReferenceWithMetaGrandChild ifThenElseResult; + if (_parent == null) { + ifThenElseResult = null; + } else { + ifThenElseResult = _parent instanceof GrandChild ? ReferenceWithMetaGrandChild.builder().setValue(GrandChild.class.cast(_parent)).build() : ReferenceWithMetaGrandChild.builder().setValue(null).build(); + } + return setParentList(ifThenElseResult); + } + + @Override + public Foo3.Foo3Builder setParentList(List parentLists) { + final Parent _parent = MapperC.of(parentLists).get(); + final ReferenceWithMetaGrandChild ifThenElseResult; + if (_parent == null) { + ifThenElseResult = null; + } else { + ifThenElseResult = _parent instanceof GrandChild ? ReferenceWithMetaGrandChild.builder().setValue(GrandChild.class.cast(_parent)).build() : ReferenceWithMetaGrandChild.builder().setValue(null).build(); + } + return setParentList(ifThenElseResult); + } + + @Override + @RosettaAttribute("stringAttr") + public Foo3.Foo3Builder setStringAttr(FieldWithMetaString _stringAttr) { + this.stringAttr = _stringAttr == null ? null : _stringAttr.toBuilder(); + return this; + } + + @Override + public Foo3.Foo3Builder setStringAttrValue(String _stringAttr) { + this.getOrCreateStringAttr().setValue(_stringAttr); + return this; + } + + @Override + public Foo3 build() { + return new Foo3.Foo3Impl(this); + } + + @Override + public Foo3.Foo3Builder toBuilder() { + return this; + } + + @SuppressWarnings("unchecked") + @Override + public Foo3.Foo3Builder prune() { + if (parent!=null && !parent.prune().hasData()) parent = null; + if (parentList!=null && !parentList.prune().hasData()) parentList = null; + if (stringAttr!=null && !stringAttr.prune().hasData()) stringAttr = null; + return this; + } + + @Override + public boolean hasData() { + if (getAttr()!=null) return true; + if (getNumberAttrOverriddenAsInteger()!=null) return true; + if (getParent()!=null && getParent().hasData()) return true; + if (getParentListOverriddenAsReferenceWithMetaGrandChild()!=null && getParentListOverriddenAsReferenceWithMetaGrandChild().hasData()) return true; + if (getStringAttr()!=null) return true; + return false; + } + + @SuppressWarnings("unchecked") + @Override + public Foo3.Foo3Builder merge(RosettaModelObjectBuilder other, BuilderMerger merger) { + Foo3.Foo3Builder o = (Foo3.Foo3Builder) other; + + merger.mergeRosetta(getParent(), o.getParent(), this::setParent); + merger.mergeRosetta(getParentListOverriddenAsReferenceWithMetaGrandChild(), o.getParentListOverriddenAsReferenceWithMetaGrandChild(), this::setParentList); + merger.mergeRosetta(getStringAttr(), o.getStringAttr(), this::setStringAttr); + + merger.mergeBasic(getAttr(), o.getAttr(), this::setAttr); + merger.mergeBasic(getNumberAttrOverriddenAsInteger(), o.getNumberAttrOverriddenAsInteger(), this::setNumberAttr); + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !(o instanceof RosettaModelObject) || !getType().equals(((RosettaModelObject)o).getType())) return false; + + Foo3 _that = getType().cast(o); + + if (!Objects.equals(attr, _that.getAttr())) return false; + if (!Objects.equals(numberAttr, _that.getNumberAttrOverriddenAsInteger())) return false; + if (!Objects.equals(parent, _that.getParent())) return false; + if (!Objects.equals(parentList, _that.getParentListOverriddenAsReferenceWithMetaGrandChild())) return false; + if (!Objects.equals(stringAttr, _that.getStringAttr())) return false; + return true; + } + + @Override + public int hashCode() { + int _result = 0; + _result = 31 * _result + (attr != null ? attr.hashCode() : 0); + _result = 31 * _result + (numberAttr != null ? numberAttr.hashCode() : 0); + _result = 31 * _result + (parent != null ? parent.hashCode() : 0); + _result = 31 * _result + (parentList != null ? parentList.hashCode() : 0); + _result = 31 * _result + (stringAttr != null ? stringAttr.hashCode() : 0); + return _result; + } + + @Override + public String toString() { + return "Foo3Builder {" + + "attr=" + this.attr + ", " + + "numberAttr=" + this.numberAttr + ", " + + "parent=" + this.parent + ", " + + "parentList=" + this.parentList + ", " + + "stringAttr=" + this.stringAttr + + '}'; + } + } + } + ''') + } + + @Test + def void testFoo3Validator() { + assertGeneratedCode('com.rosetta.test.model.validation.Foo3Validator', ''' + package com.rosetta.test.model.validation; + + import com.google.common.collect.Lists; + import com.rosetta.model.lib.expression.ComparisonResult; + import com.rosetta.model.lib.path.RosettaPath; + import com.rosetta.model.lib.validation.ValidationResult; + import com.rosetta.model.lib.validation.ValidationResult.ValidationType; + import com.rosetta.model.lib.validation.Validator; + import com.rosetta.model.metafields.FieldWithMetaString; + import com.rosetta.test.model.Child; + import com.rosetta.test.model.Foo3; + import com.rosetta.test.model.metafields.ReferenceWithMetaGrandChild; + import java.util.List; + + import static com.google.common.base.Strings.isNullOrEmpty; + import static com.rosetta.model.lib.expression.ExpressionOperators.checkCardinality; + import static com.rosetta.model.lib.validation.ValidationResult.failure; + import static com.rosetta.model.lib.validation.ValidationResult.success; + import static java.util.stream.Collectors.joining; + import static java.util.stream.Collectors.toList; + + public class Foo3Validator implements Validator { + + private List getComparisonResults(Foo3 o) { + return Lists.newArrayList( + checkCardinality("attr", (Integer) o.getAttr() != null ? 1 : 0, 1, 1), + checkCardinality("numberAttr", (Integer) o.getNumberAttrOverriddenAsInteger() != null ? 1 : 0, 1, 1), + checkCardinality("parent", (Child) o.getParent() != null ? 1 : 0, 1, 1), + checkCardinality("parentList", (ReferenceWithMetaGrandChild) o.getParentListOverriddenAsReferenceWithMetaGrandChild() != null ? 1 : 0, 1, 1), + checkCardinality("stringAttr", (FieldWithMetaString) o.getStringAttr() != null ? 1 : 0, 1, 1) + ); + } + + @Override + public ValidationResult validate(RosettaPath path, Foo3 o) { + String error = getComparisonResults(o) + .stream() + .filter(res -> !res.get()) + .map(res -> res.getError()) + .collect(joining("; ")); + + if (!isNullOrEmpty(error)) { + return failure("Foo3", ValidationType.CARDINALITY, "Foo3", path, "", error); + } + return success("Foo3", ValidationType.CARDINALITY, "Foo3", path, ""); + } + + @Override + public List> getValidationResults(RosettaPath path, Foo3 o) { + return getComparisonResults(o) + .stream() + .map(res -> { + if (!isNullOrEmpty(res.getError())) { + return failure("Foo3", ValidationType.CARDINALITY, "Foo3", path, "", res.getError()); + } + return success("Foo3", ValidationType.CARDINALITY, "Foo3", path, ""); + }) + .collect(toList()); + } + + } + ''') + } + + @Test + def void testFoo3TypeFormatValidator() { + assertGeneratedCode('com.rosetta.test.model.validation.Foo3TypeFormatValidator', ''' + package com.rosetta.test.model.validation; + + import com.google.common.collect.Lists; + import com.rosetta.model.lib.expression.ComparisonResult; + import com.rosetta.model.lib.path.RosettaPath; + import com.rosetta.model.lib.validation.ValidationResult; + import com.rosetta.model.lib.validation.ValidationResult.ValidationType; + import com.rosetta.model.lib.validation.Validator; + import com.rosetta.test.model.Foo3; + import java.util.List; + + import static com.google.common.base.Strings.isNullOrEmpty; + import static com.rosetta.model.lib.expression.ExpressionOperators.checkNumber; + import static com.rosetta.model.lib.expression.ExpressionOperators.checkString; + import static com.rosetta.model.lib.validation.ValidationResult.failure; + import static com.rosetta.model.lib.validation.ValidationResult.success; + import static java.util.Optional.empty; + import static java.util.Optional.of; + import static java.util.stream.Collectors.joining; + import static java.util.stream.Collectors.toList; + + public class Foo3TypeFormatValidator implements Validator { + + private List getComparisonResults(Foo3 o) { + return Lists.newArrayList( + checkNumber("attr", o.getAttr(), empty(), of(0), empty(), empty()), + checkNumber("numberAttr", o.getNumberAttrOverriddenAsInteger(), empty(), of(0), empty(), empty()), + checkString("stringAttr", o.getStringAttr().getValue(), 0, of(42), empty()) + ); + } + + @Override + public ValidationResult validate(RosettaPath path, Foo3 o) { + String error = getComparisonResults(o) + .stream() + .filter(res -> !res.get()) + .map(res -> res.getError()) + .collect(joining("; ")); + + if (!isNullOrEmpty(error)) { + return failure("Foo3", ValidationType.TYPE_FORMAT, "Foo3", path, "", error); + } + return success("Foo3", ValidationType.TYPE_FORMAT, "Foo3", path, ""); + } + + @Override + public List> getValidationResults(RosettaPath path, Foo3 o) { + return getComparisonResults(o) + .stream() + .map(res -> { + if (!isNullOrEmpty(res.getError())) { + return failure("Foo3", ValidationType.TYPE_FORMAT, "Foo3", path, "", res.getError()); + } + return success("Foo3", ValidationType.TYPE_FORMAT, "Foo3", path, ""); + }) + .collect(toList()); + } + + } + ''') + } + + @Test + def void testFoo3OnlyExistsValidator() { + assertGeneratedCode('com.rosetta.test.model.validation.exists.Foo3OnlyExistsValidator', ''' + package com.rosetta.test.model.validation.exists; + + import com.google.common.collect.ImmutableMap; + import com.rosetta.model.lib.path.RosettaPath; + import com.rosetta.model.lib.validation.ExistenceChecker; + import com.rosetta.model.lib.validation.ValidationResult; + import com.rosetta.model.lib.validation.ValidationResult.ValidationType; + import com.rosetta.model.lib.validation.ValidatorWithArg; + import com.rosetta.model.metafields.FieldWithMetaString; + import com.rosetta.test.model.Child; + import com.rosetta.test.model.Foo3; + import com.rosetta.test.model.metafields.ReferenceWithMetaGrandChild; + import java.util.Map; + import java.util.Set; + import java.util.stream.Collectors; + + import static com.rosetta.model.lib.validation.ValidationResult.failure; + import static com.rosetta.model.lib.validation.ValidationResult.success; + + public class Foo3OnlyExistsValidator implements ValidatorWithArg> { + + /* Casting is required to ensure types are output to ensure recompilation in Rosetta */ + @Override + public ValidationResult validate(RosettaPath path, T2 o, Set fields) { + Map fieldExistenceMap = ImmutableMap.builder() + .put("attr", ExistenceChecker.isSet((Integer) o.getAttr())) + .put("numberAttr", ExistenceChecker.isSet((Integer) o.getNumberAttrOverriddenAsInteger())) + .put("parent", ExistenceChecker.isSet((Child) o.getParent())) + .put("parentList", ExistenceChecker.isSet((ReferenceWithMetaGrandChild) o.getParentListOverriddenAsReferenceWithMetaGrandChild())) + .put("stringAttr", ExistenceChecker.isSet((FieldWithMetaString) o.getStringAttr())) + .build(); + + // Find the fields that are set + Set setFields = fieldExistenceMap.entrySet().stream() + .filter(Map.Entry::getValue) + .map(Map.Entry::getKey) + .collect(Collectors.toSet()); + + if (setFields.equals(fields)) { + return success("Foo3", ValidationType.ONLY_EXISTS, "Foo3", path, ""); + } + return failure("Foo3", ValidationType.ONLY_EXISTS, "Foo3", path, "", + String.format("[%s] should only be set. Set fields: %s", fields, setFields)); + } + } + ''') + } +} \ No newline at end of file diff --git a/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/PojoRegressionTest.xtend b/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/PojoRegressionTest.xtend index cc24c3cea..2462d2c84 100644 --- a/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/PojoRegressionTest.xtend +++ b/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/object/PojoRegressionTest.xtend @@ -32,8 +32,8 @@ class PojoRegressionTest { code = ''' type Pojo: [metadata key] - simpleAttr string (1..1) - multiSimpleAttr string (0..*) + simpleAttr string(maxLength: 42) (1..1) + multiSimpleAttr string(maxLength: 42) (0..*) simpleAttrWithMeta string (1..1) [metadata scheme] @@ -88,7 +88,9 @@ class PojoRegressionTest { import com.rosetta.model.metafields.FieldWithMetaString; import com.rosetta.model.metafields.FieldWithMetaString.FieldWithMetaStringBuilder; import com.rosetta.model.metafields.MetaFields; + import com.rosetta.model.metafields.MetaFields.MetaFieldsBuilder; import com.rosetta.test.model.Foo; + import com.rosetta.test.model.Foo.FooBuilder; import com.rosetta.test.model.Pojo; import com.rosetta.test.model.Pojo.PojoBuilder; import com.rosetta.test.model.Pojo.PojoBuilderImpl; @@ -146,7 +148,6 @@ class PojoRegressionTest { return Pojo.class; } - @Override default void process(RosettaPath path, Processor processor) { processor.processBasic(path.newSubPath("simpleAttr"), String.class, getSimpleAttr(), this); @@ -164,65 +165,74 @@ class PojoRegressionTest { /*********************** Builder Interface ***********************/ - interface PojoBuilder extends Pojo, RosettaModelObjectBuilder { + interface PojoBuilder extends Pojo, RosettaModelObjectBuilder, GlobalKey.GlobalKeyBuilder { FieldWithMetaString.FieldWithMetaStringBuilder getOrCreateSimpleAttrWithMeta(); + @Override FieldWithMetaString.FieldWithMetaStringBuilder getSimpleAttrWithMeta(); FieldWithMetaString.FieldWithMetaStringBuilder getOrCreateMultiSimpleAttrWithMeta(int _index); + @Override List getMultiSimpleAttrWithMeta(); FieldWithMetaString.FieldWithMetaStringBuilder getOrCreateSimpleAttrWithId(); + @Override FieldWithMetaString.FieldWithMetaStringBuilder getSimpleAttrWithId(); FieldWithMetaString.FieldWithMetaStringBuilder getOrCreateMultiSimpleAttrWithId(int _index); + @Override List getMultiSimpleAttrWithId(); Foo.FooBuilder getOrCreateComplexAttr(); + @Override Foo.FooBuilder getComplexAttr(); Foo.FooBuilder getOrCreateMultiComplexAttr(int _index); + @Override List getMultiComplexAttr(); ReferenceWithMetaFoo.ReferenceWithMetaFooBuilder getOrCreateComplexAttrWithRef(); + @Override ReferenceWithMetaFoo.ReferenceWithMetaFooBuilder getComplexAttrWithRef(); ReferenceWithMetaFoo.ReferenceWithMetaFooBuilder getOrCreateMultiComplexAttrWithRef(int _index); + @Override List getMultiComplexAttrWithRef(); MetaFields.MetaFieldsBuilder getOrCreateMeta(); + @Override MetaFields.MetaFieldsBuilder getMeta(); Pojo.PojoBuilder setSimpleAttr(String simpleAttr); - Pojo.PojoBuilder addMultiSimpleAttr(String multiSimpleAttr0); - Pojo.PojoBuilder addMultiSimpleAttr(String multiSimpleAttr1, int _idx); - Pojo.PojoBuilder addMultiSimpleAttr(List multiSimpleAttr2); - Pojo.PojoBuilder setMultiSimpleAttr(List multiSimpleAttr3); - Pojo.PojoBuilder setSimpleAttrWithMeta(FieldWithMetaString simpleAttrWithMeta0); - Pojo.PojoBuilder setSimpleAttrWithMetaValue(String simpleAttrWithMeta1); - Pojo.PojoBuilder addMultiSimpleAttrWithMeta(FieldWithMetaString multiSimpleAttrWithMeta0); - Pojo.PojoBuilder addMultiSimpleAttrWithMeta(FieldWithMetaString multiSimpleAttrWithMeta1, int _idx); - Pojo.PojoBuilder addMultiSimpleAttrWithMetaValue(String multiSimpleAttrWithMeta2); - Pojo.PojoBuilder addMultiSimpleAttrWithMetaValue(String multiSimpleAttrWithMeta3, int _idx); - Pojo.PojoBuilder addMultiSimpleAttrWithMeta(List multiSimpleAttrWithMeta4); - Pojo.PojoBuilder setMultiSimpleAttrWithMeta(List multiSimpleAttrWithMeta5); - Pojo.PojoBuilder addMultiSimpleAttrWithMetaValue(List multiSimpleAttrWithMeta6); - Pojo.PojoBuilder setMultiSimpleAttrWithMetaValue(List multiSimpleAttrWithMeta7); - Pojo.PojoBuilder setSimpleAttrWithId(FieldWithMetaString simpleAttrWithId0); - Pojo.PojoBuilder setSimpleAttrWithIdValue(String simpleAttrWithId1); - Pojo.PojoBuilder addMultiSimpleAttrWithId(FieldWithMetaString multiSimpleAttrWithId0); - Pojo.PojoBuilder addMultiSimpleAttrWithId(FieldWithMetaString multiSimpleAttrWithId1, int _idx); - Pojo.PojoBuilder addMultiSimpleAttrWithIdValue(String multiSimpleAttrWithId2); - Pojo.PojoBuilder addMultiSimpleAttrWithIdValue(String multiSimpleAttrWithId3, int _idx); - Pojo.PojoBuilder addMultiSimpleAttrWithId(List multiSimpleAttrWithId4); - Pojo.PojoBuilder setMultiSimpleAttrWithId(List multiSimpleAttrWithId5); - Pojo.PojoBuilder addMultiSimpleAttrWithIdValue(List multiSimpleAttrWithId6); - Pojo.PojoBuilder setMultiSimpleAttrWithIdValue(List multiSimpleAttrWithId7); + Pojo.PojoBuilder addMultiSimpleAttr(String multiSimpleAttr); + Pojo.PojoBuilder addMultiSimpleAttr(String multiSimpleAttr, int _idx); + Pojo.PojoBuilder addMultiSimpleAttr(List multiSimpleAttr); + Pojo.PojoBuilder setMultiSimpleAttr(List multiSimpleAttr); + Pojo.PojoBuilder setSimpleAttrWithMeta(FieldWithMetaString simpleAttrWithMeta); + Pojo.PojoBuilder setSimpleAttrWithMetaValue(String simpleAttrWithMeta); + Pojo.PojoBuilder addMultiSimpleAttrWithMeta(FieldWithMetaString multiSimpleAttrWithMeta); + Pojo.PojoBuilder addMultiSimpleAttrWithMeta(FieldWithMetaString multiSimpleAttrWithMeta, int _idx); + Pojo.PojoBuilder addMultiSimpleAttrWithMetaValue(String multiSimpleAttrWithMeta); + Pojo.PojoBuilder addMultiSimpleAttrWithMetaValue(String multiSimpleAttrWithMeta, int _idx); + Pojo.PojoBuilder addMultiSimpleAttrWithMeta(List multiSimpleAttrWithMeta); + Pojo.PojoBuilder setMultiSimpleAttrWithMeta(List multiSimpleAttrWithMeta); + Pojo.PojoBuilder addMultiSimpleAttrWithMetaValue(List multiSimpleAttrWithMeta); + Pojo.PojoBuilder setMultiSimpleAttrWithMetaValue(List multiSimpleAttrWithMeta); + Pojo.PojoBuilder setSimpleAttrWithId(FieldWithMetaString simpleAttrWithId); + Pojo.PojoBuilder setSimpleAttrWithIdValue(String simpleAttrWithId); + Pojo.PojoBuilder addMultiSimpleAttrWithId(FieldWithMetaString multiSimpleAttrWithId); + Pojo.PojoBuilder addMultiSimpleAttrWithId(FieldWithMetaString multiSimpleAttrWithId, int _idx); + Pojo.PojoBuilder addMultiSimpleAttrWithIdValue(String multiSimpleAttrWithId); + Pojo.PojoBuilder addMultiSimpleAttrWithIdValue(String multiSimpleAttrWithId, int _idx); + Pojo.PojoBuilder addMultiSimpleAttrWithId(List multiSimpleAttrWithId); + Pojo.PojoBuilder setMultiSimpleAttrWithId(List multiSimpleAttrWithId); + Pojo.PojoBuilder addMultiSimpleAttrWithIdValue(List multiSimpleAttrWithId); + Pojo.PojoBuilder setMultiSimpleAttrWithIdValue(List multiSimpleAttrWithId); Pojo.PojoBuilder setComplexAttr(Foo complexAttr); - Pojo.PojoBuilder addMultiComplexAttr(Foo multiComplexAttr0); - Pojo.PojoBuilder addMultiComplexAttr(Foo multiComplexAttr1, int _idx); - Pojo.PojoBuilder addMultiComplexAttr(List multiComplexAttr2); - Pojo.PojoBuilder setMultiComplexAttr(List multiComplexAttr3); - Pojo.PojoBuilder setComplexAttrWithRef(ReferenceWithMetaFoo complexAttrWithRef0); - Pojo.PojoBuilder setComplexAttrWithRefValue(Foo complexAttrWithRef1); - Pojo.PojoBuilder addMultiComplexAttrWithRef(ReferenceWithMetaFoo multiComplexAttrWithRef0); - Pojo.PojoBuilder addMultiComplexAttrWithRef(ReferenceWithMetaFoo multiComplexAttrWithRef1, int _idx); - Pojo.PojoBuilder addMultiComplexAttrWithRefValue(Foo multiComplexAttrWithRef2); - Pojo.PojoBuilder addMultiComplexAttrWithRefValue(Foo multiComplexAttrWithRef3, int _idx); - Pojo.PojoBuilder addMultiComplexAttrWithRef(List multiComplexAttrWithRef4); - Pojo.PojoBuilder setMultiComplexAttrWithRef(List multiComplexAttrWithRef5); - Pojo.PojoBuilder addMultiComplexAttrWithRefValue(List multiComplexAttrWithRef6); - Pojo.PojoBuilder setMultiComplexAttrWithRefValue(List multiComplexAttrWithRef7); + Pojo.PojoBuilder addMultiComplexAttr(Foo multiComplexAttr); + Pojo.PojoBuilder addMultiComplexAttr(Foo multiComplexAttr, int _idx); + Pojo.PojoBuilder addMultiComplexAttr(List multiComplexAttr); + Pojo.PojoBuilder setMultiComplexAttr(List multiComplexAttr); + Pojo.PojoBuilder setComplexAttrWithRef(ReferenceWithMetaFoo complexAttrWithRef); + Pojo.PojoBuilder setComplexAttrWithRefValue(Foo complexAttrWithRef); + Pojo.PojoBuilder addMultiComplexAttrWithRef(ReferenceWithMetaFoo multiComplexAttrWithRef); + Pojo.PojoBuilder addMultiComplexAttrWithRef(ReferenceWithMetaFoo multiComplexAttrWithRef, int _idx); + Pojo.PojoBuilder addMultiComplexAttrWithRefValue(Foo multiComplexAttrWithRef); + Pojo.PojoBuilder addMultiComplexAttrWithRefValue(Foo multiComplexAttrWithRef, int _idx); + Pojo.PojoBuilder addMultiComplexAttrWithRef(List multiComplexAttrWithRef); + Pojo.PojoBuilder setMultiComplexAttrWithRef(List multiComplexAttrWithRef); + Pojo.PojoBuilder addMultiComplexAttrWithRefValue(List multiComplexAttrWithRef); + Pojo.PojoBuilder setMultiComplexAttrWithRefValue(List multiComplexAttrWithRef); Pojo.PojoBuilder setMeta(MetaFields meta); @Override @@ -421,7 +431,7 @@ class PojoRegressionTest { } /*********************** Builder Implementation of Pojo ***********************/ - class PojoBuilderImpl implements Pojo.PojoBuilder, GlobalKeyBuilder { + class PojoBuilderImpl implements Pojo.PojoBuilder { protected String simpleAttr; protected List multiSimpleAttr = new ArrayList<>(); @@ -434,10 +444,7 @@ class PojoRegressionTest { protected ReferenceWithMetaFoo.ReferenceWithMetaFooBuilder complexAttrWithRef; protected List multiComplexAttrWithRef = new ArrayList<>(); protected MetaFields.MetaFieldsBuilder meta; - - public PojoBuilderImpl() { - } - + @Override @RosettaAttribute("simpleAttr") public String getSimpleAttr() { @@ -623,26 +630,30 @@ class PojoRegressionTest { @Override @RosettaAttribute("simpleAttr") - public Pojo.PojoBuilder setSimpleAttr(String simpleAttr) { - this.simpleAttr = simpleAttr==null?null:simpleAttr; + public Pojo.PojoBuilder setSimpleAttr(String _simpleAttr) { + this.simpleAttr = _simpleAttr == null ? null : _simpleAttr; return this; } + @Override @RosettaAttribute("multiSimpleAttr") - public Pojo.PojoBuilder addMultiSimpleAttr(String multiSimpleAttr) { - if (multiSimpleAttr!=null) this.multiSimpleAttr.add(multiSimpleAttr); + public Pojo.PojoBuilder addMultiSimpleAttr(String _multiSimpleAttr) { + if (_multiSimpleAttr != null) { + this.multiSimpleAttr.add(_multiSimpleAttr); + } return this; } @Override - public Pojo.PojoBuilder addMultiSimpleAttr(String multiSimpleAttr, int _idx) { - getIndex(this.multiSimpleAttr, _idx, () -> multiSimpleAttr); + public Pojo.PojoBuilder addMultiSimpleAttr(String _multiSimpleAttr, int _idx) { + getIndex(this.multiSimpleAttr, _idx, () -> _multiSimpleAttr); return this; } + @Override public Pojo.PojoBuilder addMultiSimpleAttr(List multiSimpleAttrs) { if (multiSimpleAttrs != null) { - for (String toAdd : multiSimpleAttrs) { + for (final String toAdd : multiSimpleAttrs) { this.multiSimpleAttr.add(toAdd); } } @@ -651,10 +662,9 @@ class PojoRegressionTest { @Override public Pojo.PojoBuilder setMultiSimpleAttr(List multiSimpleAttrs) { - if (multiSimpleAttrs == null) { + if (multiSimpleAttrs == null) { this.multiSimpleAttr = new ArrayList<>(); - } - else { + } else { this.multiSimpleAttr = multiSimpleAttrs.stream() .collect(Collectors.toCollection(()->new ArrayList<>())); } @@ -663,43 +673,48 @@ class PojoRegressionTest { @Override @RosettaAttribute("simpleAttrWithMeta") - public Pojo.PojoBuilder setSimpleAttrWithMeta(FieldWithMetaString simpleAttrWithMeta) { - this.simpleAttrWithMeta = simpleAttrWithMeta==null?null:simpleAttrWithMeta.toBuilder(); + public Pojo.PojoBuilder setSimpleAttrWithMeta(FieldWithMetaString _simpleAttrWithMeta) { + this.simpleAttrWithMeta = _simpleAttrWithMeta == null ? null : _simpleAttrWithMeta.toBuilder(); return this; } + @Override - public Pojo.PojoBuilder setSimpleAttrWithMetaValue(String simpleAttrWithMeta) { - this.getOrCreateSimpleAttrWithMeta().setValue(simpleAttrWithMeta); + public Pojo.PojoBuilder setSimpleAttrWithMetaValue(String _simpleAttrWithMeta) { + this.getOrCreateSimpleAttrWithMeta().setValue(_simpleAttrWithMeta); return this; } + @Override @RosettaAttribute("multiSimpleAttrWithMeta") - public Pojo.PojoBuilder addMultiSimpleAttrWithMeta(FieldWithMetaString multiSimpleAttrWithMeta) { - if (multiSimpleAttrWithMeta!=null) this.multiSimpleAttrWithMeta.add(multiSimpleAttrWithMeta.toBuilder()); + public Pojo.PojoBuilder addMultiSimpleAttrWithMeta(FieldWithMetaString _multiSimpleAttrWithMeta) { + if (_multiSimpleAttrWithMeta != null) { + this.multiSimpleAttrWithMeta.add(_multiSimpleAttrWithMeta.toBuilder()); + } return this; } @Override - public Pojo.PojoBuilder addMultiSimpleAttrWithMeta(FieldWithMetaString multiSimpleAttrWithMeta, int _idx) { - getIndex(this.multiSimpleAttrWithMeta, _idx, () -> multiSimpleAttrWithMeta.toBuilder()); + public Pojo.PojoBuilder addMultiSimpleAttrWithMeta(FieldWithMetaString _multiSimpleAttrWithMeta, int _idx) { + getIndex(this.multiSimpleAttrWithMeta, _idx, () -> _multiSimpleAttrWithMeta.toBuilder()); return this; } @Override - public Pojo.PojoBuilder addMultiSimpleAttrWithMetaValue(String multiSimpleAttrWithMeta) { - this.getOrCreateMultiSimpleAttrWithMeta(-1).setValue(multiSimpleAttrWithMeta); + public Pojo.PojoBuilder addMultiSimpleAttrWithMetaValue(String _multiSimpleAttrWithMeta) { + this.getOrCreateMultiSimpleAttrWithMeta(-1).setValue(_multiSimpleAttrWithMeta); return this; } @Override - public Pojo.PojoBuilder addMultiSimpleAttrWithMetaValue(String multiSimpleAttrWithMeta, int _idx) { - this.getOrCreateMultiSimpleAttrWithMeta(_idx).setValue(multiSimpleAttrWithMeta); + public Pojo.PojoBuilder addMultiSimpleAttrWithMetaValue(String _multiSimpleAttrWithMeta, int _idx) { + this.getOrCreateMultiSimpleAttrWithMeta(_idx).setValue(_multiSimpleAttrWithMeta); return this; } + @Override public Pojo.PojoBuilder addMultiSimpleAttrWithMeta(List multiSimpleAttrWithMetas) { if (multiSimpleAttrWithMetas != null) { - for (FieldWithMetaString toAdd : multiSimpleAttrWithMetas) { + for (final FieldWithMetaString toAdd : multiSimpleAttrWithMetas) { this.multiSimpleAttrWithMeta.add(toAdd.toBuilder()); } } @@ -708,10 +723,9 @@ class PojoRegressionTest { @Override public Pojo.PojoBuilder setMultiSimpleAttrWithMeta(List multiSimpleAttrWithMetas) { - if (multiSimpleAttrWithMetas == null) { + if (multiSimpleAttrWithMetas == null) { this.multiSimpleAttrWithMeta = new ArrayList<>(); - } - else { + } else { this.multiSimpleAttrWithMeta = multiSimpleAttrWithMetas.stream() .map(_a->_a.toBuilder()) .collect(Collectors.toCollection(()->new ArrayList<>())); @@ -722,7 +736,7 @@ class PojoRegressionTest { @Override public Pojo.PojoBuilder addMultiSimpleAttrWithMetaValue(List multiSimpleAttrWithMetas) { if (multiSimpleAttrWithMetas != null) { - for (String toAdd : multiSimpleAttrWithMetas) { + for (final String toAdd : multiSimpleAttrWithMetas) { this.addMultiSimpleAttrWithMetaValue(toAdd); } } @@ -732,7 +746,7 @@ class PojoRegressionTest { @Override public Pojo.PojoBuilder setMultiSimpleAttrWithMetaValue(List multiSimpleAttrWithMetas) { this.multiSimpleAttrWithMeta.clear(); - if (multiSimpleAttrWithMetas!=null) { + if (multiSimpleAttrWithMetas != null) { multiSimpleAttrWithMetas.forEach(this::addMultiSimpleAttrWithMetaValue); } return this; @@ -740,43 +754,48 @@ class PojoRegressionTest { @Override @RosettaAttribute("simpleAttrWithId") - public Pojo.PojoBuilder setSimpleAttrWithId(FieldWithMetaString simpleAttrWithId) { - this.simpleAttrWithId = simpleAttrWithId==null?null:simpleAttrWithId.toBuilder(); + public Pojo.PojoBuilder setSimpleAttrWithId(FieldWithMetaString _simpleAttrWithId) { + this.simpleAttrWithId = _simpleAttrWithId == null ? null : _simpleAttrWithId.toBuilder(); return this; } + @Override - public Pojo.PojoBuilder setSimpleAttrWithIdValue(String simpleAttrWithId) { - this.getOrCreateSimpleAttrWithId().setValue(simpleAttrWithId); + public Pojo.PojoBuilder setSimpleAttrWithIdValue(String _simpleAttrWithId) { + this.getOrCreateSimpleAttrWithId().setValue(_simpleAttrWithId); return this; } + @Override @RosettaAttribute("multiSimpleAttrWithId") - public Pojo.PojoBuilder addMultiSimpleAttrWithId(FieldWithMetaString multiSimpleAttrWithId) { - if (multiSimpleAttrWithId!=null) this.multiSimpleAttrWithId.add(multiSimpleAttrWithId.toBuilder()); + public Pojo.PojoBuilder addMultiSimpleAttrWithId(FieldWithMetaString _multiSimpleAttrWithId) { + if (_multiSimpleAttrWithId != null) { + this.multiSimpleAttrWithId.add(_multiSimpleAttrWithId.toBuilder()); + } return this; } @Override - public Pojo.PojoBuilder addMultiSimpleAttrWithId(FieldWithMetaString multiSimpleAttrWithId, int _idx) { - getIndex(this.multiSimpleAttrWithId, _idx, () -> multiSimpleAttrWithId.toBuilder()); + public Pojo.PojoBuilder addMultiSimpleAttrWithId(FieldWithMetaString _multiSimpleAttrWithId, int _idx) { + getIndex(this.multiSimpleAttrWithId, _idx, () -> _multiSimpleAttrWithId.toBuilder()); return this; } @Override - public Pojo.PojoBuilder addMultiSimpleAttrWithIdValue(String multiSimpleAttrWithId) { - this.getOrCreateMultiSimpleAttrWithId(-1).setValue(multiSimpleAttrWithId); + public Pojo.PojoBuilder addMultiSimpleAttrWithIdValue(String _multiSimpleAttrWithId) { + this.getOrCreateMultiSimpleAttrWithId(-1).setValue(_multiSimpleAttrWithId); return this; } @Override - public Pojo.PojoBuilder addMultiSimpleAttrWithIdValue(String multiSimpleAttrWithId, int _idx) { - this.getOrCreateMultiSimpleAttrWithId(_idx).setValue(multiSimpleAttrWithId); + public Pojo.PojoBuilder addMultiSimpleAttrWithIdValue(String _multiSimpleAttrWithId, int _idx) { + this.getOrCreateMultiSimpleAttrWithId(_idx).setValue(_multiSimpleAttrWithId); return this; } + @Override public Pojo.PojoBuilder addMultiSimpleAttrWithId(List multiSimpleAttrWithIds) { if (multiSimpleAttrWithIds != null) { - for (FieldWithMetaString toAdd : multiSimpleAttrWithIds) { + for (final FieldWithMetaString toAdd : multiSimpleAttrWithIds) { this.multiSimpleAttrWithId.add(toAdd.toBuilder()); } } @@ -785,10 +804,9 @@ class PojoRegressionTest { @Override public Pojo.PojoBuilder setMultiSimpleAttrWithId(List multiSimpleAttrWithIds) { - if (multiSimpleAttrWithIds == null) { + if (multiSimpleAttrWithIds == null) { this.multiSimpleAttrWithId = new ArrayList<>(); - } - else { + } else { this.multiSimpleAttrWithId = multiSimpleAttrWithIds.stream() .map(_a->_a.toBuilder()) .collect(Collectors.toCollection(()->new ArrayList<>())); @@ -799,7 +817,7 @@ class PojoRegressionTest { @Override public Pojo.PojoBuilder addMultiSimpleAttrWithIdValue(List multiSimpleAttrWithIds) { if (multiSimpleAttrWithIds != null) { - for (String toAdd : multiSimpleAttrWithIds) { + for (final String toAdd : multiSimpleAttrWithIds) { this.addMultiSimpleAttrWithIdValue(toAdd); } } @@ -809,7 +827,7 @@ class PojoRegressionTest { @Override public Pojo.PojoBuilder setMultiSimpleAttrWithIdValue(List multiSimpleAttrWithIds) { this.multiSimpleAttrWithId.clear(); - if (multiSimpleAttrWithIds!=null) { + if (multiSimpleAttrWithIds != null) { multiSimpleAttrWithIds.forEach(this::addMultiSimpleAttrWithIdValue); } return this; @@ -817,26 +835,30 @@ class PojoRegressionTest { @Override @RosettaAttribute("complexAttr") - public Pojo.PojoBuilder setComplexAttr(Foo complexAttr) { - this.complexAttr = complexAttr==null?null:complexAttr.toBuilder(); + public Pojo.PojoBuilder setComplexAttr(Foo _complexAttr) { + this.complexAttr = _complexAttr == null ? null : _complexAttr.toBuilder(); return this; } + @Override @RosettaAttribute("multiComplexAttr") - public Pojo.PojoBuilder addMultiComplexAttr(Foo multiComplexAttr) { - if (multiComplexAttr!=null) this.multiComplexAttr.add(multiComplexAttr.toBuilder()); + public Pojo.PojoBuilder addMultiComplexAttr(Foo _multiComplexAttr) { + if (_multiComplexAttr != null) { + this.multiComplexAttr.add(_multiComplexAttr.toBuilder()); + } return this; } @Override - public Pojo.PojoBuilder addMultiComplexAttr(Foo multiComplexAttr, int _idx) { - getIndex(this.multiComplexAttr, _idx, () -> multiComplexAttr.toBuilder()); + public Pojo.PojoBuilder addMultiComplexAttr(Foo _multiComplexAttr, int _idx) { + getIndex(this.multiComplexAttr, _idx, () -> _multiComplexAttr.toBuilder()); return this; } + @Override public Pojo.PojoBuilder addMultiComplexAttr(List multiComplexAttrs) { if (multiComplexAttrs != null) { - for (Foo toAdd : multiComplexAttrs) { + for (final Foo toAdd : multiComplexAttrs) { this.multiComplexAttr.add(toAdd.toBuilder()); } } @@ -845,10 +867,9 @@ class PojoRegressionTest { @Override public Pojo.PojoBuilder setMultiComplexAttr(List multiComplexAttrs) { - if (multiComplexAttrs == null) { + if (multiComplexAttrs == null) { this.multiComplexAttr = new ArrayList<>(); - } - else { + } else { this.multiComplexAttr = multiComplexAttrs.stream() .map(_a->_a.toBuilder()) .collect(Collectors.toCollection(()->new ArrayList<>())); @@ -858,43 +879,48 @@ class PojoRegressionTest { @Override @RosettaAttribute("complexAttrWithRef") - public Pojo.PojoBuilder setComplexAttrWithRef(ReferenceWithMetaFoo complexAttrWithRef) { - this.complexAttrWithRef = complexAttrWithRef==null?null:complexAttrWithRef.toBuilder(); + public Pojo.PojoBuilder setComplexAttrWithRef(ReferenceWithMetaFoo _complexAttrWithRef) { + this.complexAttrWithRef = _complexAttrWithRef == null ? null : _complexAttrWithRef.toBuilder(); return this; } + @Override - public Pojo.PojoBuilder setComplexAttrWithRefValue(Foo complexAttrWithRef) { - this.getOrCreateComplexAttrWithRef().setValue(complexAttrWithRef); + public Pojo.PojoBuilder setComplexAttrWithRefValue(Foo _complexAttrWithRef) { + this.getOrCreateComplexAttrWithRef().setValue(_complexAttrWithRef); return this; } + @Override @RosettaAttribute("multiComplexAttrWithRef") - public Pojo.PojoBuilder addMultiComplexAttrWithRef(ReferenceWithMetaFoo multiComplexAttrWithRef) { - if (multiComplexAttrWithRef!=null) this.multiComplexAttrWithRef.add(multiComplexAttrWithRef.toBuilder()); + public Pojo.PojoBuilder addMultiComplexAttrWithRef(ReferenceWithMetaFoo _multiComplexAttrWithRef) { + if (_multiComplexAttrWithRef != null) { + this.multiComplexAttrWithRef.add(_multiComplexAttrWithRef.toBuilder()); + } return this; } @Override - public Pojo.PojoBuilder addMultiComplexAttrWithRef(ReferenceWithMetaFoo multiComplexAttrWithRef, int _idx) { - getIndex(this.multiComplexAttrWithRef, _idx, () -> multiComplexAttrWithRef.toBuilder()); + public Pojo.PojoBuilder addMultiComplexAttrWithRef(ReferenceWithMetaFoo _multiComplexAttrWithRef, int _idx) { + getIndex(this.multiComplexAttrWithRef, _idx, () -> _multiComplexAttrWithRef.toBuilder()); return this; } @Override - public Pojo.PojoBuilder addMultiComplexAttrWithRefValue(Foo multiComplexAttrWithRef) { - this.getOrCreateMultiComplexAttrWithRef(-1).setValue(multiComplexAttrWithRef.toBuilder()); + public Pojo.PojoBuilder addMultiComplexAttrWithRefValue(Foo _multiComplexAttrWithRef) { + this.getOrCreateMultiComplexAttrWithRef(-1).setValue(_multiComplexAttrWithRef.toBuilder()); return this; } @Override - public Pojo.PojoBuilder addMultiComplexAttrWithRefValue(Foo multiComplexAttrWithRef, int _idx) { - this.getOrCreateMultiComplexAttrWithRef(_idx).setValue(multiComplexAttrWithRef.toBuilder()); + public Pojo.PojoBuilder addMultiComplexAttrWithRefValue(Foo _multiComplexAttrWithRef, int _idx) { + this.getOrCreateMultiComplexAttrWithRef(_idx).setValue(_multiComplexAttrWithRef.toBuilder()); return this; } + @Override public Pojo.PojoBuilder addMultiComplexAttrWithRef(List multiComplexAttrWithRefs) { if (multiComplexAttrWithRefs != null) { - for (ReferenceWithMetaFoo toAdd : multiComplexAttrWithRefs) { + for (final ReferenceWithMetaFoo toAdd : multiComplexAttrWithRefs) { this.multiComplexAttrWithRef.add(toAdd.toBuilder()); } } @@ -903,10 +929,9 @@ class PojoRegressionTest { @Override public Pojo.PojoBuilder setMultiComplexAttrWithRef(List multiComplexAttrWithRefs) { - if (multiComplexAttrWithRefs == null) { + if (multiComplexAttrWithRefs == null) { this.multiComplexAttrWithRef = new ArrayList<>(); - } - else { + } else { this.multiComplexAttrWithRef = multiComplexAttrWithRefs.stream() .map(_a->_a.toBuilder()) .collect(Collectors.toCollection(()->new ArrayList<>())); @@ -917,7 +942,7 @@ class PojoRegressionTest { @Override public Pojo.PojoBuilder addMultiComplexAttrWithRefValue(List multiComplexAttrWithRefs) { if (multiComplexAttrWithRefs != null) { - for (Foo toAdd : multiComplexAttrWithRefs) { + for (final Foo toAdd : multiComplexAttrWithRefs) { this.addMultiComplexAttrWithRefValue(toAdd); } } @@ -927,7 +952,7 @@ class PojoRegressionTest { @Override public Pojo.PojoBuilder setMultiComplexAttrWithRefValue(List multiComplexAttrWithRefs) { this.multiComplexAttrWithRef.clear(); - if (multiComplexAttrWithRefs!=null) { + if (multiComplexAttrWithRefs != null) { multiComplexAttrWithRefs.forEach(this::addMultiComplexAttrWithRefValue); } return this; @@ -935,8 +960,8 @@ class PojoRegressionTest { @Override @RosettaAttribute("meta") - public Pojo.PojoBuilder setMeta(MetaFields meta) { - this.meta = meta==null?null:meta.toBuilder(); + public Pojo.PojoBuilder setMeta(MetaFields _meta) { + this.meta = _meta == null ? null : _meta.toBuilder(); return this; } @@ -1059,6 +1084,193 @@ class PojoRegressionTest { ''') } + @Test + def void testPojoValidator() { + assertGeneratedCode('com.rosetta.test.model.validation.PojoValidator', ''' + package com.rosetta.test.model.validation; + + import com.google.common.collect.Lists; + import com.rosetta.model.lib.expression.ComparisonResult; + import com.rosetta.model.lib.path.RosettaPath; + import com.rosetta.model.lib.validation.ValidationResult; + import com.rosetta.model.lib.validation.ValidationResult.ValidationType; + import com.rosetta.model.lib.validation.Validator; + import com.rosetta.model.metafields.FieldWithMetaString; + import com.rosetta.test.model.Foo; + import com.rosetta.test.model.Pojo; + import com.rosetta.test.model.metafields.ReferenceWithMetaFoo; + import java.util.List; + + import static com.google.common.base.Strings.isNullOrEmpty; + import static com.rosetta.model.lib.expression.ExpressionOperators.checkCardinality; + import static com.rosetta.model.lib.validation.ValidationResult.failure; + import static com.rosetta.model.lib.validation.ValidationResult.success; + import static java.util.stream.Collectors.joining; + import static java.util.stream.Collectors.toList; + + public class PojoValidator implements Validator { + + private List getComparisonResults(Pojo o) { + return Lists.newArrayList( + checkCardinality("simpleAttr", (String) o.getSimpleAttr() != null ? 1 : 0, 1, 1), + checkCardinality("simpleAttrWithMeta", (FieldWithMetaString) o.getSimpleAttrWithMeta() != null ? 1 : 0, 1, 1), + checkCardinality("simpleAttrWithId", (FieldWithMetaString) o.getSimpleAttrWithId() != null ? 1 : 0, 1, 1), + checkCardinality("complexAttr", (Foo) o.getComplexAttr() != null ? 1 : 0, 1, 1), + checkCardinality("complexAttrWithRef", (ReferenceWithMetaFoo) o.getComplexAttrWithRef() != null ? 1 : 0, 1, 1) + ); + } + + @Override + public ValidationResult validate(RosettaPath path, Pojo o) { + String error = getComparisonResults(o) + .stream() + .filter(res -> !res.get()) + .map(res -> res.getError()) + .collect(joining("; ")); + + if (!isNullOrEmpty(error)) { + return failure("Pojo", ValidationType.CARDINALITY, "Pojo", path, "", error); + } + return success("Pojo", ValidationType.CARDINALITY, "Pojo", path, ""); + } + + @Override + public List> getValidationResults(RosettaPath path, Pojo o) { + return getComparisonResults(o) + .stream() + .map(res -> { + if (!isNullOrEmpty(res.getError())) { + return failure("Pojo", ValidationType.CARDINALITY, "Pojo", path, "", res.getError()); + } + return success("Pojo", ValidationType.CARDINALITY, "Pojo", path, ""); + }) + .collect(toList()); + } + + } + ''') + } + + @Test + def void testPojoTypeFormatValidator() { + assertGeneratedCode('com.rosetta.test.model.validation.PojoTypeFormatValidator', ''' + package com.rosetta.test.model.validation; + + import com.google.common.collect.Lists; + import com.rosetta.model.lib.expression.ComparisonResult; + import com.rosetta.model.lib.path.RosettaPath; + import com.rosetta.model.lib.validation.ValidationResult; + import com.rosetta.model.lib.validation.ValidationResult.ValidationType; + import com.rosetta.model.lib.validation.Validator; + import com.rosetta.test.model.Pojo; + import java.util.List; + + import static com.google.common.base.Strings.isNullOrEmpty; + import static com.rosetta.model.lib.expression.ExpressionOperators.checkString; + import static com.rosetta.model.lib.validation.ValidationResult.failure; + import static com.rosetta.model.lib.validation.ValidationResult.success; + import static java.util.Optional.empty; + import static java.util.Optional.of; + import static java.util.stream.Collectors.joining; + import static java.util.stream.Collectors.toList; + + public class PojoTypeFormatValidator implements Validator { + + private List getComparisonResults(Pojo o) { + return Lists.newArrayList( + checkString("simpleAttr", o.getSimpleAttr(), 0, of(42), empty()), + checkString("multiSimpleAttr", o.getMultiSimpleAttr(), 0, of(42), empty()) + ); + } + + @Override + public ValidationResult validate(RosettaPath path, Pojo o) { + String error = getComparisonResults(o) + .stream() + .filter(res -> !res.get()) + .map(res -> res.getError()) + .collect(joining("; ")); + + if (!isNullOrEmpty(error)) { + return failure("Pojo", ValidationType.TYPE_FORMAT, "Pojo", path, "", error); + } + return success("Pojo", ValidationType.TYPE_FORMAT, "Pojo", path, ""); + } + + @Override + public List> getValidationResults(RosettaPath path, Pojo o) { + return getComparisonResults(o) + .stream() + .map(res -> { + if (!isNullOrEmpty(res.getError())) { + return failure("Pojo", ValidationType.TYPE_FORMAT, "Pojo", path, "", res.getError()); + } + return success("Pojo", ValidationType.TYPE_FORMAT, "Pojo", path, ""); + }) + .collect(toList()); + } + + } + ''') + } + + @Test + def void testPojoOnlyExistsValidator() { + assertGeneratedCode('com.rosetta.test.model.validation.exists.PojoOnlyExistsValidator', ''' + package com.rosetta.test.model.validation.exists; + + import com.google.common.collect.ImmutableMap; + import com.rosetta.model.lib.path.RosettaPath; + import com.rosetta.model.lib.validation.ExistenceChecker; + import com.rosetta.model.lib.validation.ValidationResult; + import com.rosetta.model.lib.validation.ValidationResult.ValidationType; + import com.rosetta.model.lib.validation.ValidatorWithArg; + import com.rosetta.model.metafields.FieldWithMetaString; + import com.rosetta.test.model.Foo; + import com.rosetta.test.model.Pojo; + import com.rosetta.test.model.metafields.ReferenceWithMetaFoo; + import java.util.List; + import java.util.Map; + import java.util.Set; + import java.util.stream.Collectors; + + import static com.rosetta.model.lib.validation.ValidationResult.failure; + import static com.rosetta.model.lib.validation.ValidationResult.success; + + public class PojoOnlyExistsValidator implements ValidatorWithArg> { + + /* Casting is required to ensure types are output to ensure recompilation in Rosetta */ + @Override + public ValidationResult validate(RosettaPath path, T2 o, Set fields) { + Map fieldExistenceMap = ImmutableMap.builder() + .put("simpleAttr", ExistenceChecker.isSet((String) o.getSimpleAttr())) + .put("multiSimpleAttr", ExistenceChecker.isSet((List) o.getMultiSimpleAttr())) + .put("simpleAttrWithMeta", ExistenceChecker.isSet((FieldWithMetaString) o.getSimpleAttrWithMeta())) + .put("multiSimpleAttrWithMeta", ExistenceChecker.isSet((List) o.getMultiSimpleAttrWithMeta())) + .put("simpleAttrWithId", ExistenceChecker.isSet((FieldWithMetaString) o.getSimpleAttrWithId())) + .put("multiSimpleAttrWithId", ExistenceChecker.isSet((List) o.getMultiSimpleAttrWithId())) + .put("complexAttr", ExistenceChecker.isSet((Foo) o.getComplexAttr())) + .put("multiComplexAttr", ExistenceChecker.isSet((List) o.getMultiComplexAttr())) + .put("complexAttrWithRef", ExistenceChecker.isSet((ReferenceWithMetaFoo) o.getComplexAttrWithRef())) + .put("multiComplexAttrWithRef", ExistenceChecker.isSet((List) o.getMultiComplexAttrWithRef())) + .build(); + + // Find the fields that are set + Set setFields = fieldExistenceMap.entrySet().stream() + .filter(Map.Entry::getValue) + .map(Map.Entry::getKey) + .collect(Collectors.toSet()); + + if (setFields.equals(fields)) { + return success("Pojo", ValidationType.ONLY_EXISTS, "Pojo", path, ""); + } + return failure("Pojo", ValidationType.ONLY_EXISTS, "Pojo", path, "", + String.format("[%s] should only be set. Set fields: %s", fields, setFields)); + } + } + ''') + } + @Test def testFieldWithMetaStringCode() { assertGeneratedCode('com.rosetta.model.metafields.FieldWithMetaString', ''' @@ -1127,8 +1339,9 @@ class PojoRegressionTest { /*********************** Builder Interface ***********************/ - interface FieldWithMetaStringBuilder extends FieldWithMetaString, RosettaModelObjectBuilder, GlobalKey.GlobalKeyBuilder, FieldWithMeta.FieldWithMetaBuilder { + interface FieldWithMetaStringBuilder extends FieldWithMetaString, RosettaModelObjectBuilder, FieldWithMeta.FieldWithMetaBuilder, GlobalKey.GlobalKeyBuilder { MetaFields.MetaFieldsBuilder getOrCreateMeta(); + @Override MetaFields.MetaFieldsBuilder getMeta(); FieldWithMetaString.FieldWithMetaStringBuilder setValue(String value); FieldWithMetaString.FieldWithMetaStringBuilder setMeta(MetaFields meta); @@ -1216,10 +1429,7 @@ class PojoRegressionTest { protected String value; protected MetaFields.MetaFieldsBuilder meta; - - public FieldWithMetaStringBuilderImpl() { - } - + @Override @RosettaAttribute("value") public String getValue() { @@ -1247,14 +1457,15 @@ class PojoRegressionTest { @Override @RosettaAttribute("value") - public FieldWithMetaString.FieldWithMetaStringBuilder setValue(String value) { - this.value = value==null?null:value; + public FieldWithMetaString.FieldWithMetaStringBuilder setValue(String _value) { + this.value = _value == null ? null : _value; return this; } + @Override @RosettaAttribute("meta") - public FieldWithMetaString.FieldWithMetaStringBuilder setMeta(MetaFields meta) { - this.meta = meta==null?null:meta.toBuilder(); + public FieldWithMetaString.FieldWithMetaStringBuilder setMeta(MetaFields _meta) { + this.meta = _meta == null ? null : _meta.toBuilder(); return this; } @@ -1339,6 +1550,7 @@ class PojoRegressionTest { import com.rosetta.model.lib.annotations.RosettaDataType; import com.rosetta.model.lib.meta.BasicRosettaMetaData; import com.rosetta.model.lib.meta.Reference; + import com.rosetta.model.lib.meta.Reference.ReferenceBuilder; import com.rosetta.model.lib.meta.ReferenceWithMeta; import com.rosetta.model.lib.meta.ReferenceWithMeta.ReferenceWithMetaBuilder; import com.rosetta.model.lib.meta.RosettaMetaData; @@ -1348,6 +1560,7 @@ class PojoRegressionTest { import com.rosetta.model.lib.process.BuilderProcessor; import com.rosetta.model.lib.process.Processor; import com.rosetta.test.model.Foo; + import com.rosetta.test.model.Foo.FooBuilder; import java.util.Objects; import static java.util.Optional.ofNullable; @@ -1403,8 +1616,10 @@ class PojoRegressionTest { /*********************** Builder Interface ***********************/ interface ReferenceWithMetaFooBuilder extends ReferenceWithMetaFoo, RosettaModelObjectBuilder, ReferenceWithMeta.ReferenceWithMetaBuilder { Foo.FooBuilder getOrCreateValue(); + @Override Foo.FooBuilder getValue(); Reference.ReferenceBuilder getOrCreateReference(); + @Override Reference.ReferenceBuilder getReference(); ReferenceWithMetaFoo.ReferenceWithMetaFooBuilder setValue(Foo value); ReferenceWithMetaFoo.ReferenceWithMetaFooBuilder setGlobalReference(String globalReference); @@ -1522,10 +1737,7 @@ class PojoRegressionTest { protected String globalReference; protected String externalReference; protected Reference.ReferenceBuilder reference; - - public ReferenceWithMetaFooBuilderImpl() { - } - + @Override @RosettaAttribute("value") public Foo.FooBuilder getValue() { @@ -1578,26 +1790,29 @@ class PojoRegressionTest { @Override @RosettaAttribute("value") - public ReferenceWithMetaFoo.ReferenceWithMetaFooBuilder setValue(Foo value) { - this.value = value==null?null:value.toBuilder(); + public ReferenceWithMetaFoo.ReferenceWithMetaFooBuilder setValue(Foo _value) { + this.value = _value == null ? null : _value.toBuilder(); return this; } + @Override @RosettaAttribute("globalReference") - public ReferenceWithMetaFoo.ReferenceWithMetaFooBuilder setGlobalReference(String globalReference) { - this.globalReference = globalReference==null?null:globalReference; + public ReferenceWithMetaFoo.ReferenceWithMetaFooBuilder setGlobalReference(String _globalReference) { + this.globalReference = _globalReference == null ? null : _globalReference; return this; } + @Override @RosettaAttribute("externalReference") - public ReferenceWithMetaFoo.ReferenceWithMetaFooBuilder setExternalReference(String externalReference) { - this.externalReference = externalReference==null?null:externalReference; + public ReferenceWithMetaFoo.ReferenceWithMetaFooBuilder setExternalReference(String _externalReference) { + this.externalReference = _externalReference == null ? null : _externalReference; return this; } + @Override @RosettaAttribute("address") - public ReferenceWithMetaFoo.ReferenceWithMetaFooBuilder setReference(Reference reference) { - this.reference = reference==null?null:reference.toBuilder(); + public ReferenceWithMetaFoo.ReferenceWithMetaFooBuilder setReference(Reference _reference) { + this.reference = _reference == null ? null : _reference.toBuilder(); return this; } @@ -1682,786 +1897,4 @@ class PojoRegressionTest { } ''') } - - @Test - def testMetaFieldsCode() { - assertGeneratedCode('com.rosetta.model.metafields.MetaFields', ''' - package com.rosetta.model.metafields; - - import com.google.common.collect.ImmutableList; - import com.rosetta.model.lib.RosettaModelObject; - import com.rosetta.model.lib.RosettaModelObjectBuilder; - import com.rosetta.model.lib.annotations.RosettaAttribute; - import com.rosetta.model.lib.annotations.RosettaDataType; - import com.rosetta.model.lib.meta.BasicRosettaMetaData; - import com.rosetta.model.lib.meta.GlobalKeyFields; - import com.rosetta.model.lib.meta.GlobalKeyFields.GlobalKeyFieldsBuilder; - import com.rosetta.model.lib.meta.Key; - import com.rosetta.model.lib.meta.MetaDataFields; - import com.rosetta.model.lib.meta.MetaDataFields.MetaDataFieldsBuilder; - import com.rosetta.model.lib.meta.RosettaMetaData; - import com.rosetta.model.lib.path.RosettaPath; - import com.rosetta.model.lib.process.AttributeMeta; - import com.rosetta.model.lib.process.BuilderMerger; - import com.rosetta.model.lib.process.BuilderProcessor; - import com.rosetta.model.lib.process.Processor; - import com.rosetta.util.ListEquals; - import java.util.ArrayList; - import java.util.List; - import java.util.Objects; - import java.util.stream.Collectors; - - import static java.util.Optional.ofNullable; - - /** - * @version 1 - */ - @RosettaDataType(value="MetaFields", builder=MetaFields.MetaFieldsBuilderImpl.class, version="0.0.0") - public interface MetaFields extends RosettaModelObject, GlobalKeyFields, MetaDataFields { - - MetaFieldsMeta metaData = new MetaFieldsMeta(); - - /*********************** Getter Methods ***********************/ - String getScheme(); - String getGlobalKey(); - String getExternalKey(); - List getKey(); - - /*********************** Build Methods ***********************/ - MetaFields build(); - - MetaFields.MetaFieldsBuilder toBuilder(); - - static MetaFields.MetaFieldsBuilder builder() { - return new MetaFields.MetaFieldsBuilderImpl(); - } - - /*********************** Utility Methods ***********************/ - @Override - default RosettaMetaData metaData() { - return metaData; - } - - @Override - default Class getType() { - return MetaFields.class; - } - - - @Override - default void process(RosettaPath path, Processor processor) { - processor.processBasic(path.newSubPath("scheme"), String.class, getScheme(), this, AttributeMeta.META); - processor.processBasic(path.newSubPath("globalKey"), String.class, getGlobalKey(), this, AttributeMeta.META); - processor.processBasic(path.newSubPath("externalKey"), String.class, getExternalKey(), this, AttributeMeta.META); - processRosetta(path.newSubPath("key"), processor, Key.class, getKey()); - } - - - /*********************** Builder Interface ***********************/ - interface MetaFieldsBuilder extends MetaFields, RosettaModelObjectBuilder, GlobalKeyFields.GlobalKeyFieldsBuilder, MetaDataFields.MetaDataFieldsBuilder { - Key.KeyBuilder getOrCreateKey(int _index); - List getKey(); - MetaFields.MetaFieldsBuilder setScheme(String scheme); - MetaFields.MetaFieldsBuilder setGlobalKey(String globalKey); - MetaFields.MetaFieldsBuilder setExternalKey(String externalKey); - MetaFields.MetaFieldsBuilder addKey(Key key0); - MetaFields.MetaFieldsBuilder addKey(Key key1, int _idx); - MetaFields.MetaFieldsBuilder addKey(List key2); - MetaFields.MetaFieldsBuilder setKey(List key3); - - @Override - default void process(RosettaPath path, BuilderProcessor processor) { - processor.processBasic(path.newSubPath("scheme"), String.class, getScheme(), this, AttributeMeta.META); - processor.processBasic(path.newSubPath("globalKey"), String.class, getGlobalKey(), this, AttributeMeta.META); - processor.processBasic(path.newSubPath("externalKey"), String.class, getExternalKey(), this, AttributeMeta.META); - processRosetta(path.newSubPath("key"), processor, Key.KeyBuilder.class, getKey()); - } - - - MetaFields.MetaFieldsBuilder prune(); - } - - /*********************** Immutable Implementation of MetaFields ***********************/ - class MetaFieldsImpl implements MetaFields { - private final String scheme; - private final String globalKey; - private final String externalKey; - private final List key; - - protected MetaFieldsImpl(MetaFields.MetaFieldsBuilder builder) { - this.scheme = builder.getScheme(); - this.globalKey = builder.getGlobalKey(); - this.externalKey = builder.getExternalKey(); - this.key = ofNullable(builder.getKey()).filter(_l->!_l.isEmpty()).map(list -> list.stream().filter(Objects::nonNull).map(f->f.build()).filter(Objects::nonNull).collect(ImmutableList.toImmutableList())).orElse(null); - } - - @Override - @RosettaAttribute("scheme") - public String getScheme() { - return scheme; - } - - @Override - @RosettaAttribute("globalKey") - public String getGlobalKey() { - return globalKey; - } - - @Override - @RosettaAttribute("externalKey") - public String getExternalKey() { - return externalKey; - } - - @Override - @RosettaAttribute("location") - public List getKey() { - return key; - } - - @Override - public MetaFields build() { - return this; - } - - @Override - public MetaFields.MetaFieldsBuilder toBuilder() { - MetaFields.MetaFieldsBuilder builder = builder(); - setBuilderFields(builder); - return builder; - } - - protected void setBuilderFields(MetaFields.MetaFieldsBuilder builder) { - ofNullable(getScheme()).ifPresent(builder::setScheme); - ofNullable(getGlobalKey()).ifPresent(builder::setGlobalKey); - ofNullable(getExternalKey()).ifPresent(builder::setExternalKey); - ofNullable(getKey()).ifPresent(builder::setKey); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !(o instanceof RosettaModelObject) || !getType().equals(((RosettaModelObject)o).getType())) return false; - - MetaFields _that = getType().cast(o); - - if (!Objects.equals(scheme, _that.getScheme())) return false; - if (!Objects.equals(globalKey, _that.getGlobalKey())) return false; - if (!Objects.equals(externalKey, _that.getExternalKey())) return false; - if (!ListEquals.listEquals(key, _that.getKey())) return false; - return true; - } - - @Override - public int hashCode() { - int _result = 0; - _result = 31 * _result + (scheme != null ? scheme.hashCode() : 0); - _result = 31 * _result + (globalKey != null ? globalKey.hashCode() : 0); - _result = 31 * _result + (externalKey != null ? externalKey.hashCode() : 0); - _result = 31 * _result + (key != null ? key.hashCode() : 0); - return _result; - } - - @Override - public String toString() { - return "MetaFields {" + - "scheme=" + this.scheme + ", " + - "globalKey=" + this.globalKey + ", " + - "externalKey=" + this.externalKey + ", " + - "key=" + this.key + - '}'; - } - } - - /*********************** Builder Implementation of MetaFields ***********************/ - class MetaFieldsBuilderImpl implements MetaFields.MetaFieldsBuilder { - - protected String scheme; - protected String globalKey; - protected String externalKey; - protected List key = new ArrayList<>(); - - public MetaFieldsBuilderImpl() { - } - - @Override - @RosettaAttribute("scheme") - public String getScheme() { - return scheme; - } - - @Override - @RosettaAttribute("globalKey") - public String getGlobalKey() { - return globalKey; - } - - @Override - @RosettaAttribute("externalKey") - public String getExternalKey() { - return externalKey; - } - - @Override - @RosettaAttribute("location") - public List getKey() { - return key; - } - - @Override - public Key.KeyBuilder getOrCreateKey(int _index) { - - if (key==null) { - this.key = new ArrayList<>(); - } - Key.KeyBuilder result; - return getIndex(key, _index, () -> { - Key.KeyBuilder newKey = Key.builder(); - return newKey; - }); - } - - @Override - @RosettaAttribute("scheme") - public MetaFields.MetaFieldsBuilder setScheme(String scheme) { - this.scheme = scheme==null?null:scheme; - return this; - } - @Override - @RosettaAttribute("globalKey") - public MetaFields.MetaFieldsBuilder setGlobalKey(String globalKey) { - this.globalKey = globalKey==null?null:globalKey; - return this; - } - @Override - @RosettaAttribute("externalKey") - public MetaFields.MetaFieldsBuilder setExternalKey(String externalKey) { - this.externalKey = externalKey==null?null:externalKey; - return this; - } - @Override - @RosettaAttribute("location") - public MetaFields.MetaFieldsBuilder addKey(Key key) { - if (key!=null) this.key.add(key.toBuilder()); - return this; - } - - @Override - public MetaFields.MetaFieldsBuilder addKey(Key key, int _idx) { - getIndex(this.key, _idx, () -> key.toBuilder()); - return this; - } - @Override - public MetaFields.MetaFieldsBuilder addKey(List keys) { - if (keys != null) { - for (Key toAdd : keys) { - this.key.add(toAdd.toBuilder()); - } - } - return this; - } - - @Override - public MetaFields.MetaFieldsBuilder setKey(List keys) { - if (keys == null) { - this.key = new ArrayList<>(); - } - else { - this.key = keys.stream() - .map(_a->_a.toBuilder()) - .collect(Collectors.toCollection(()->new ArrayList<>())); - } - return this; - } - - - @Override - public MetaFields build() { - return new MetaFields.MetaFieldsImpl(this); - } - - @Override - public MetaFields.MetaFieldsBuilder toBuilder() { - return this; - } - - @SuppressWarnings("unchecked") - @Override - public MetaFields.MetaFieldsBuilder prune() { - key = key.stream().filter(b->b!=null).map(b->b.prune()).filter(b->b.hasData()).collect(Collectors.toList()); - return this; - } - - @Override - public boolean hasData() { - if (getScheme()!=null) return true; - if (getGlobalKey()!=null) return true; - if (getExternalKey()!=null) return true; - if (getKey()!=null && getKey().stream().filter(Objects::nonNull).anyMatch(a->a.hasData())) return true; - return false; - } - - @SuppressWarnings("unchecked") - @Override - public MetaFields.MetaFieldsBuilder merge(RosettaModelObjectBuilder other, BuilderMerger merger) { - MetaFields.MetaFieldsBuilder o = (MetaFields.MetaFieldsBuilder) other; - - merger.mergeRosetta(getKey(), o.getKey(), this::getOrCreateKey); - - merger.mergeBasic(getScheme(), o.getScheme(), this::setScheme); - merger.mergeBasic(getGlobalKey(), o.getGlobalKey(), this::setGlobalKey); - merger.mergeBasic(getExternalKey(), o.getExternalKey(), this::setExternalKey); - return this; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !(o instanceof RosettaModelObject) || !getType().equals(((RosettaModelObject)o).getType())) return false; - - MetaFields _that = getType().cast(o); - - if (!Objects.equals(scheme, _that.getScheme())) return false; - if (!Objects.equals(globalKey, _that.getGlobalKey())) return false; - if (!Objects.equals(externalKey, _that.getExternalKey())) return false; - if (!ListEquals.listEquals(key, _that.getKey())) return false; - return true; - } - - @Override - public int hashCode() { - int _result = 0; - _result = 31 * _result + (scheme != null ? scheme.hashCode() : 0); - _result = 31 * _result + (globalKey != null ? globalKey.hashCode() : 0); - _result = 31 * _result + (externalKey != null ? externalKey.hashCode() : 0); - _result = 31 * _result + (key != null ? key.hashCode() : 0); - return _result; - } - - @Override - public String toString() { - return "MetaFieldsBuilder {" + - "scheme=" + this.scheme + ", " + - "globalKey=" + this.globalKey + ", " + - "externalKey=" + this.externalKey + ", " + - "key=" + this.key + - '}'; - } - } - } - - class MetaFieldsMeta extends BasicRosettaMetaData{ - - } - ''') - } - - @Test - def testMetaAndTemplateFieldsCode() { - assertGeneratedCode('com.rosetta.model.metafields.MetaAndTemplateFields', ''' - package com.rosetta.model.metafields; - - import com.google.common.collect.ImmutableList; - import com.rosetta.model.lib.RosettaModelObject; - import com.rosetta.model.lib.RosettaModelObjectBuilder; - import com.rosetta.model.lib.annotations.RosettaAttribute; - import com.rosetta.model.lib.annotations.RosettaDataType; - import com.rosetta.model.lib.meta.BasicRosettaMetaData; - import com.rosetta.model.lib.meta.GlobalKeyFields; - import com.rosetta.model.lib.meta.GlobalKeyFields.GlobalKeyFieldsBuilder; - import com.rosetta.model.lib.meta.Key; - import com.rosetta.model.lib.meta.MetaDataFields; - import com.rosetta.model.lib.meta.MetaDataFields.MetaDataFieldsBuilder; - import com.rosetta.model.lib.meta.RosettaMetaData; - import com.rosetta.model.lib.meta.TemplateFields; - import com.rosetta.model.lib.meta.TemplateFields.TemplateFieldsBuilder; - import com.rosetta.model.lib.path.RosettaPath; - import com.rosetta.model.lib.process.AttributeMeta; - import com.rosetta.model.lib.process.BuilderMerger; - import com.rosetta.model.lib.process.BuilderProcessor; - import com.rosetta.model.lib.process.Processor; - import com.rosetta.util.ListEquals; - import java.util.ArrayList; - import java.util.List; - import java.util.Objects; - import java.util.stream.Collectors; - - import static java.util.Optional.ofNullable; - - /** - * @version 1 - */ - @RosettaDataType(value="MetaAndTemplateFields", builder=MetaAndTemplateFields.MetaAndTemplateFieldsBuilderImpl.class, version="0.0.0") - public interface MetaAndTemplateFields extends RosettaModelObject, GlobalKeyFields, TemplateFields, MetaDataFields { - - MetaAndTemplateFieldsMeta metaData = new MetaAndTemplateFieldsMeta(); - - /*********************** Getter Methods ***********************/ - String getScheme(); - String getTemplateGlobalReference(); - String getGlobalKey(); - String getExternalKey(); - List getKey(); - - /*********************** Build Methods ***********************/ - MetaAndTemplateFields build(); - - MetaAndTemplateFields.MetaAndTemplateFieldsBuilder toBuilder(); - - static MetaAndTemplateFields.MetaAndTemplateFieldsBuilder builder() { - return new MetaAndTemplateFields.MetaAndTemplateFieldsBuilderImpl(); - } - - /*********************** Utility Methods ***********************/ - @Override - default RosettaMetaData metaData() { - return metaData; - } - - @Override - default Class getType() { - return MetaAndTemplateFields.class; - } - - - @Override - default void process(RosettaPath path, Processor processor) { - processor.processBasic(path.newSubPath("scheme"), String.class, getScheme(), this, AttributeMeta.META); - processor.processBasic(path.newSubPath("templateGlobalReference"), String.class, getTemplateGlobalReference(), this, AttributeMeta.META); - processor.processBasic(path.newSubPath("globalKey"), String.class, getGlobalKey(), this, AttributeMeta.META); - processor.processBasic(path.newSubPath("externalKey"), String.class, getExternalKey(), this, AttributeMeta.META); - processRosetta(path.newSubPath("key"), processor, Key.class, getKey()); - } - - - /*********************** Builder Interface ***********************/ - interface MetaAndTemplateFieldsBuilder extends MetaAndTemplateFields, RosettaModelObjectBuilder, GlobalKeyFields.GlobalKeyFieldsBuilder, TemplateFields.TemplateFieldsBuilder, MetaDataFields.MetaDataFieldsBuilder { - Key.KeyBuilder getOrCreateKey(int _index); - List getKey(); - MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setScheme(String scheme); - MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setTemplateGlobalReference(String templateGlobalReference); - MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setGlobalKey(String globalKey); - MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setExternalKey(String externalKey); - MetaAndTemplateFields.MetaAndTemplateFieldsBuilder addKey(Key key0); - MetaAndTemplateFields.MetaAndTemplateFieldsBuilder addKey(Key key1, int _idx); - MetaAndTemplateFields.MetaAndTemplateFieldsBuilder addKey(List key2); - MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setKey(List key3); - - @Override - default void process(RosettaPath path, BuilderProcessor processor) { - processor.processBasic(path.newSubPath("scheme"), String.class, getScheme(), this, AttributeMeta.META); - processor.processBasic(path.newSubPath("templateGlobalReference"), String.class, getTemplateGlobalReference(), this, AttributeMeta.META); - processor.processBasic(path.newSubPath("globalKey"), String.class, getGlobalKey(), this, AttributeMeta.META); - processor.processBasic(path.newSubPath("externalKey"), String.class, getExternalKey(), this, AttributeMeta.META); - processRosetta(path.newSubPath("key"), processor, Key.KeyBuilder.class, getKey()); - } - - - MetaAndTemplateFields.MetaAndTemplateFieldsBuilder prune(); - } - - /*********************** Immutable Implementation of MetaAndTemplateFields ***********************/ - class MetaAndTemplateFieldsImpl implements MetaAndTemplateFields { - private final String scheme; - private final String templateGlobalReference; - private final String globalKey; - private final String externalKey; - private final List key; - - protected MetaAndTemplateFieldsImpl(MetaAndTemplateFields.MetaAndTemplateFieldsBuilder builder) { - this.scheme = builder.getScheme(); - this.templateGlobalReference = builder.getTemplateGlobalReference(); - this.globalKey = builder.getGlobalKey(); - this.externalKey = builder.getExternalKey(); - this.key = ofNullable(builder.getKey()).filter(_l->!_l.isEmpty()).map(list -> list.stream().filter(Objects::nonNull).map(f->f.build()).filter(Objects::nonNull).collect(ImmutableList.toImmutableList())).orElse(null); - } - - @Override - @RosettaAttribute("scheme") - public String getScheme() { - return scheme; - } - - @Override - @RosettaAttribute("templateGlobalReference") - public String getTemplateGlobalReference() { - return templateGlobalReference; - } - - @Override - @RosettaAttribute("globalKey") - public String getGlobalKey() { - return globalKey; - } - - @Override - @RosettaAttribute("externalKey") - public String getExternalKey() { - return externalKey; - } - - @Override - @RosettaAttribute("location") - public List getKey() { - return key; - } - - @Override - public MetaAndTemplateFields build() { - return this; - } - - @Override - public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder toBuilder() { - MetaAndTemplateFields.MetaAndTemplateFieldsBuilder builder = builder(); - setBuilderFields(builder); - return builder; - } - - protected void setBuilderFields(MetaAndTemplateFields.MetaAndTemplateFieldsBuilder builder) { - ofNullable(getScheme()).ifPresent(builder::setScheme); - ofNullable(getTemplateGlobalReference()).ifPresent(builder::setTemplateGlobalReference); - ofNullable(getGlobalKey()).ifPresent(builder::setGlobalKey); - ofNullable(getExternalKey()).ifPresent(builder::setExternalKey); - ofNullable(getKey()).ifPresent(builder::setKey); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !(o instanceof RosettaModelObject) || !getType().equals(((RosettaModelObject)o).getType())) return false; - - MetaAndTemplateFields _that = getType().cast(o); - - if (!Objects.equals(scheme, _that.getScheme())) return false; - if (!Objects.equals(templateGlobalReference, _that.getTemplateGlobalReference())) return false; - if (!Objects.equals(globalKey, _that.getGlobalKey())) return false; - if (!Objects.equals(externalKey, _that.getExternalKey())) return false; - if (!ListEquals.listEquals(key, _that.getKey())) return false; - return true; - } - - @Override - public int hashCode() { - int _result = 0; - _result = 31 * _result + (scheme != null ? scheme.hashCode() : 0); - _result = 31 * _result + (templateGlobalReference != null ? templateGlobalReference.hashCode() : 0); - _result = 31 * _result + (globalKey != null ? globalKey.hashCode() : 0); - _result = 31 * _result + (externalKey != null ? externalKey.hashCode() : 0); - _result = 31 * _result + (key != null ? key.hashCode() : 0); - return _result; - } - - @Override - public String toString() { - return "MetaAndTemplateFields {" + - "scheme=" + this.scheme + ", " + - "templateGlobalReference=" + this.templateGlobalReference + ", " + - "globalKey=" + this.globalKey + ", " + - "externalKey=" + this.externalKey + ", " + - "key=" + this.key + - '}'; - } - } - - /*********************** Builder Implementation of MetaAndTemplateFields ***********************/ - class MetaAndTemplateFieldsBuilderImpl implements MetaAndTemplateFields.MetaAndTemplateFieldsBuilder { - - protected String scheme; - protected String templateGlobalReference; - protected String globalKey; - protected String externalKey; - protected List key = new ArrayList<>(); - - public MetaAndTemplateFieldsBuilderImpl() { - } - - @Override - @RosettaAttribute("scheme") - public String getScheme() { - return scheme; - } - - @Override - @RosettaAttribute("templateGlobalReference") - public String getTemplateGlobalReference() { - return templateGlobalReference; - } - - @Override - @RosettaAttribute("globalKey") - public String getGlobalKey() { - return globalKey; - } - - @Override - @RosettaAttribute("externalKey") - public String getExternalKey() { - return externalKey; - } - - @Override - @RosettaAttribute("location") - public List getKey() { - return key; - } - - @Override - public Key.KeyBuilder getOrCreateKey(int _index) { - - if (key==null) { - this.key = new ArrayList<>(); - } - Key.KeyBuilder result; - return getIndex(key, _index, () -> { - Key.KeyBuilder newKey = Key.builder(); - return newKey; - }); - } - - @Override - @RosettaAttribute("scheme") - public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setScheme(String scheme) { - this.scheme = scheme==null?null:scheme; - return this; - } - @Override - @RosettaAttribute("templateGlobalReference") - public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setTemplateGlobalReference(String templateGlobalReference) { - this.templateGlobalReference = templateGlobalReference==null?null:templateGlobalReference; - return this; - } - @Override - @RosettaAttribute("globalKey") - public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setGlobalKey(String globalKey) { - this.globalKey = globalKey==null?null:globalKey; - return this; - } - @Override - @RosettaAttribute("externalKey") - public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setExternalKey(String externalKey) { - this.externalKey = externalKey==null?null:externalKey; - return this; - } - @Override - @RosettaAttribute("location") - public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder addKey(Key key) { - if (key!=null) this.key.add(key.toBuilder()); - return this; - } - - @Override - public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder addKey(Key key, int _idx) { - getIndex(this.key, _idx, () -> key.toBuilder()); - return this; - } - @Override - public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder addKey(List keys) { - if (keys != null) { - for (Key toAdd : keys) { - this.key.add(toAdd.toBuilder()); - } - } - return this; - } - - @Override - public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder setKey(List keys) { - if (keys == null) { - this.key = new ArrayList<>(); - } - else { - this.key = keys.stream() - .map(_a->_a.toBuilder()) - .collect(Collectors.toCollection(()->new ArrayList<>())); - } - return this; - } - - - @Override - public MetaAndTemplateFields build() { - return new MetaAndTemplateFields.MetaAndTemplateFieldsImpl(this); - } - - @Override - public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder toBuilder() { - return this; - } - - @SuppressWarnings("unchecked") - @Override - public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder prune() { - key = key.stream().filter(b->b!=null).map(b->b.prune()).filter(b->b.hasData()).collect(Collectors.toList()); - return this; - } - - @Override - public boolean hasData() { - if (getScheme()!=null) return true; - if (getTemplateGlobalReference()!=null) return true; - if (getGlobalKey()!=null) return true; - if (getExternalKey()!=null) return true; - if (getKey()!=null && getKey().stream().filter(Objects::nonNull).anyMatch(a->a.hasData())) return true; - return false; - } - - @SuppressWarnings("unchecked") - @Override - public MetaAndTemplateFields.MetaAndTemplateFieldsBuilder merge(RosettaModelObjectBuilder other, BuilderMerger merger) { - MetaAndTemplateFields.MetaAndTemplateFieldsBuilder o = (MetaAndTemplateFields.MetaAndTemplateFieldsBuilder) other; - - merger.mergeRosetta(getKey(), o.getKey(), this::getOrCreateKey); - - merger.mergeBasic(getScheme(), o.getScheme(), this::setScheme); - merger.mergeBasic(getTemplateGlobalReference(), o.getTemplateGlobalReference(), this::setTemplateGlobalReference); - merger.mergeBasic(getGlobalKey(), o.getGlobalKey(), this::setGlobalKey); - merger.mergeBasic(getExternalKey(), o.getExternalKey(), this::setExternalKey); - return this; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !(o instanceof RosettaModelObject) || !getType().equals(((RosettaModelObject)o).getType())) return false; - - MetaAndTemplateFields _that = getType().cast(o); - - if (!Objects.equals(scheme, _that.getScheme())) return false; - if (!Objects.equals(templateGlobalReference, _that.getTemplateGlobalReference())) return false; - if (!Objects.equals(globalKey, _that.getGlobalKey())) return false; - if (!Objects.equals(externalKey, _that.getExternalKey())) return false; - if (!ListEquals.listEquals(key, _that.getKey())) return false; - return true; - } - - @Override - public int hashCode() { - int _result = 0; - _result = 31 * _result + (scheme != null ? scheme.hashCode() : 0); - _result = 31 * _result + (templateGlobalReference != null ? templateGlobalReference.hashCode() : 0); - _result = 31 * _result + (globalKey != null ? globalKey.hashCode() : 0); - _result = 31 * _result + (externalKey != null ? externalKey.hashCode() : 0); - _result = 31 * _result + (key != null ? key.hashCode() : 0); - return _result; - } - - @Override - public String toString() { - return "MetaAndTemplateFieldsBuilder {" + - "scheme=" + this.scheme + ", " + - "templateGlobalReference=" + this.templateGlobalReference + ", " + - "globalKey=" + this.globalKey + ", " + - "externalKey=" + this.externalKey + ", " + - "key=" + this.key + - '}'; - } - } - } - - class MetaAndTemplateFieldsMeta extends BasicRosettaMetaData{ - - } - ''') - } } \ No newline at end of file diff --git a/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/reports/TabulatorTest.xtend b/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/reports/TabulatorTest.xtend index f6d367838..9b75c7d4c 100644 --- a/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/reports/TabulatorTest.xtend +++ b/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/reports/TabulatorTest.xtend @@ -25,6 +25,7 @@ import static org.hamcrest.MatcherAssert.* import static org.junit.jupiter.api.Assertions.* import static extension com.regnosys.rosetta.tests.util.CustomConfigTestHelper.* +import com.rosetta.model.metafields.MetaFields @InjectWith(RosettaInjectorProvider) @ExtendWith(InjectionExtension) @@ -441,6 +442,7 @@ class TabulatorTest { [ruleReference Basic2] type Report extends BaseReport: + override basic1 string (1..1) basic2 int (1..1) [ruleReference Basic2Modified] basic3 number (1..1) @@ -575,6 +577,7 @@ class TabulatorTest { basic2 int (1..1) type Report extends BaseReport: + override basic1 string (1..1) basic2 int (1..1) basic3 number (1..1) @@ -850,14 +853,12 @@ class TabulatorTest { val rootTabulator = classes.getModel3RootTabulator // bar is set and barReference is set as an unresolved reference - val barMetaFields = classes.createInstanceUsingBuilder(META_PKG, "MetaFields", #{"externalKey" -> "barExtKey", "globalKey" -> "barGlobalKey"}) + val barMetaFields = MetaFields.builder.setExternalKey("barExtKey").setGlobalKey("barGlobalKey") val bar = classes.createInstanceUsingBuilder(MODEL3_PKG, "Bar", #{"meta" -> barMetaFields, "b1" -> "bValue"}) val barReference = classes.createInstanceUsingBuilder(MODEL3_META_PKG, "ReferenceWithMetaBar", #{"externalReference" -> "barExtKey", "globalReference" -> "barGlobalKey"}) val foo = classes.createInstanceUsingBuilder(MODEL3_PKG, "Foo", #{"f1" -> "fValue", "barReference" -> barReference}) val root = classes.createInstanceUsingBuilder(MODEL3_PKG, "Root", #{"r1" -> "rValue", "foo" -> foo, "bar" -> bar}) - assertEquals("Root {r1=rValue, " + - "foo=Foo {f1=fValue, barReference=ReferenceWithMetaBar {value=null, globalReference=barGlobalKey, externalReference=barExtKey, reference=null}}, " + - "bar=Bar {b1=bValue, meta=MetaFields {scheme=null, globalKey=barGlobalKey, externalKey=barExtKey, key=null}}}", + assertEquals("Root {r1=rValue, foo=Foo {f1=fValue, barReference=ReferenceWithMetaBar {value=null, globalReference=barGlobalKey, externalReference=barExtKey, reference=null}}, bar=Bar {b1=bValue, meta=MetaFields {scheme=null, template=null, location=null, address=null, globalKey=barGlobalKey, externalKey=barExtKey, key=null}}}", root.toString) val tabulatedRoot = rootTabulator.tabulate(root) @@ -931,14 +932,12 @@ class TabulatorTest { val rootTabulator = classes.getModel3RootTabulator // bar is set and barReference is set as an unresolved reference - val barMetaFields = classes.createInstanceUsingBuilder(META_PKG, "MetaFields", #{"externalKey" -> "barExtKey", "globalKey" -> "barGlobalKey"}) + val barMetaFields = MetaFields.builder.setExternalKey("barExtKey").setGlobalKey("barGlobalKey") val bar = classes.createInstanceUsingBuilder(MODEL3_PKG, "Bar", #{"meta" -> barMetaFields, "b1" -> "bValue"}) val barReference = classes.createInstanceUsingBuilder(MODEL3_META_PKG, "ReferenceWithMetaBar", #{"externalReference" -> "barExtKey", "globalReference" -> "barGlobalKey"}) val foo = classes.createInstanceUsingBuilder(MODEL3_PKG, "Foo", #{"f1" -> "fValue", "barReferences" -> #[barReference]}) val root = classes.createInstanceUsingBuilder(MODEL3_PKG, "Root", #{"r1" -> "rValue", "foo" -> foo, "bar" -> bar}) - assertEquals("Root {r1=rValue, " + - "foo=Foo {f1=fValue, barReferences=[ReferenceWithMetaBar {value=null, globalReference=barGlobalKey, externalReference=barExtKey, reference=null}]}, " + - "bar=Bar {b1=bValue, meta=MetaFields {scheme=null, globalKey=barGlobalKey, externalKey=barExtKey, key=null}}}", + assertEquals("Root {r1=rValue, foo=Foo {f1=fValue, barReferences=[ReferenceWithMetaBar {value=null, globalReference=barGlobalKey, externalReference=barExtKey, reference=null}]}, bar=Bar {b1=bValue, meta=MetaFields {scheme=null, template=null, location=null, address=null, globalKey=barGlobalKey, externalKey=barExtKey, key=null}}}", root.toString) val tabulatedRoot = rootTabulator.tabulate(root) diff --git a/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/util/ModelGeneratorUtilTest.xtend b/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/util/ModelGeneratorUtilTest.xtend index 8dddda3a3..d5f7404ce 100644 --- a/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/util/ModelGeneratorUtilTest.xtend +++ b/rosetta-testing/src/test/java/com/regnosys/rosetta/generator/java/util/ModelGeneratorUtilTest.xtend @@ -195,7 +195,7 @@ class ModelGeneratorUtilTest { .parseRosetta(model).elements .filter(Data) .filter[name == 'Foo'] - .map[attributes].flatten + .flatMap[attributes] .filter[name == 'bar'] .get(0) diff --git a/rosetta-testing/src/test/java/com/regnosys/rosetta/tests/RosettaParsingTest.xtend b/rosetta-testing/src/test/java/com/regnosys/rosetta/tests/RosettaParsingTest.xtend index 865d6d3d6..50ff23108 100644 --- a/rosetta-testing/src/test/java/com/regnosys/rosetta/tests/RosettaParsingTest.xtend +++ b/rosetta-testing/src/test/java/com/regnosys/rosetta/tests/RosettaParsingTest.xtend @@ -23,6 +23,7 @@ import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.junit.jupiter.api.^extension.ExtendWith +import static com.regnosys.rosetta.rosetta.simple.SimplePackage.Literals.* import static com.regnosys.rosetta.rosetta.expression.ExpressionPackage.Literals.* import static org.junit.jupiter.api.Assertions.* @@ -34,6 +35,40 @@ class RosettaParsingTest { @Inject extension ValidationTestHelper @Inject extension ExpressionParser + @Test + def void testCannotOverrideAttributeOfItself() { + ''' + type Foo: + override attr number (1..1) + attr number (0..1) + '''.parseRosetta + .assertError(ATTRIBUTE, null, "Attribute attr does not exist in supertype") + } + + @Test + def void testCanOverrideAttributeOfParent() { + ''' + type Bar: + attr number (0..1) + + type Foo extends Bar: + override attr number (1..1) + '''.parseRosettaWithNoIssues + } + + @Test + def void testNamespaceDescription() { + ''' + namespace cdm.base.test : <"some description"> + version "test" + + enum TestEnum: + ONE + TWO + + '''.parseRosettaWithNoIssues + } + @Test def void canPassMetadataToFunctions() { ''' diff --git a/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/AttributeValidatorTest.xtend b/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/AttributeValidatorTest.xtend new file mode 100644 index 000000000..afde772f6 --- /dev/null +++ b/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/AttributeValidatorTest.xtend @@ -0,0 +1,275 @@ +package com.regnosys.rosetta.validation + +import com.regnosys.rosetta.tests.util.ModelHelper +import org.eclipse.xtext.testing.InjectWith +import org.eclipse.xtext.testing.extensions.InjectionExtension +import org.eclipse.xtext.testing.validation.ValidationTestHelper +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.^extension.ExtendWith + +import static com.regnosys.rosetta.rosetta.RosettaPackage.Literals.* +import static com.regnosys.rosetta.rosetta.simple.SimplePackage.Literals.* +import static com.regnosys.rosetta.rosetta.expression.ExpressionPackage.Literals.* +import javax.inject.Inject + +@ExtendWith(InjectionExtension) +@InjectWith(MyRosettaInjectorProvider) +class AttributeValidatorTest implements RosettaIssueCodes { + + @Inject extension ValidationTestHelper + @Inject extension ModelHelper + + @Test + def void testAttributeNameShouldStartWithLowerCase() { + val model = + ''' + type PartyIdentifier: + PartyId string (1..1) + '''.parseRosettaWithNoErrors + model.assertWarning(ATTRIBUTE, INVALID_CASE, + "Attribute name should start with a lower case") + } + + @Test + def checkReferenceTypeMustHaveAKey() { + val model = ''' + type WithKey: + + type TypeToUse: + attr WithKey (0..1) + [metadata reference] + '''.parseRosetta + model.assertWarning(ATTRIBUTE, null, + "WithKey must be annotated with [metadata key] as reference annotation is used") + } + + @Test + def void testValidAttributeOverrides() { + ''' + type Foo: + complexAttr Parent (1..1) + listAttr number (0..*) + stringAttr string (1..1) + [metadata scheme] + refAttr Ref (1..1) + [metadata reference] + + type Bar extends Foo: + override complexAttr Child (1..1) + override listAttr int (1..1) + [metadata scheme] + override stringAttr string(maxLength: 42) (1..1) + override refAttr Subref (1..1) + [metadata reference] + barAttr int (1..1) + + // Utility types + type Parent: + + type Child extends Parent: + + type Ref: + [metadata key] + + type Subref extends Ref: + [metadata key] + '''.parseRosettaWithNoIssues + } + + @Test + def void testCannotOverrideNonExistingAttribute() { + ''' + type Foo: + attr number (0..1) + + type Bar extends Foo: + override otherAttr number (0..1) + '''.parseRosetta + .assertError(ATTRIBUTE, null, "Attribute otherAttr does not exist") + } + + @Test + def void testCannotOverrideFunctionAttribute() { + ''' + func Foo: + inputs: + override foo int (1..1) + output: + result int (1..1) + '''.parseRosetta + .assertError(ATTRIBUTE, null, "You can only override the attribute of a type") + } + + @Test + def void testCannotOverrideAttributeToNonSubtype() { + ''' + type Foo: + attr number (0..1) + + type Bar extends Foo: + override attr string (0..1) + '''.parseRosetta + .assertError(ATTRIBUTE, null, "The overridden type should be a subtype of the parent type number") + } + + @Test + def void testCannotOverrideAttributeToDifferentSubtype() { + ''' + type Foo: + attr Parent (0..1) + + type Bar extends Foo: + override attr Child1 (0..1) + + type Qux extends Bar: + override attr Child2 (0..1) + + type Parent: + + type Child1 extends Parent: + + type Child2 extends Parent: + '''.parseRosetta + .assertError(ATTRIBUTE, null, "The overridden type should be a subtype of the parent type Child1") + } + + @Test + def void testCannotBroadenAttributeCardinality() { + ''' + type Foo: + attr string (1..1) + + type Bar extends Foo: + override attr string (0..1) + '''.parseRosetta + .assertError(ATTRIBUTE, null, "Cardinality may not be broader than the cardinality of the parent attribute (1..1)") + } + + @Test + def void testCannotOverrideChoiceTypeToOption() { + // Note: this should be supported once https://github.com/finos/rune-dsl/issues/797 is resolved + ''' + choice StringOrNumber: + string + number + + type Foo: + attr StringOrNumber (1..1) + + type Bar extends Foo: + override attr string (1..1) + '''.parseRosetta + .assertError(ATTRIBUTE, null, "The overridden type should be a subtype of the parent type StringOrNumber") + } + + @Test + def void testCannotOverrideChoiceTypeToSubchoice() { + // Note: this should be supported once https://github.com/finos/rune-dsl/issues/797 is resolved + ''' + choice StringOrNumberOrBoolean: + string + number + boolean + + choice StringOrNumber: + string + number + + type Foo: + attr StringOrNumberOrBoolean (1..1) + + type Bar extends Foo: + override attr StringOrNumber (1..1) + '''.parseRosetta + .assertError(ATTRIBUTE, null, "The overridden type should be a subtype of the parent type StringOrNumberOrBoolean") + } + + @Test + def void testMustOverrideRuleReferenceWhenRestrictingType() { + ''' + type Parent: + type Child extends Parent: + + type Foo: + attr Parent (1..1) + [ruleReference AttrRule] + + type Bar extends Foo: + override attr Child (1..1) + + reporting rule AttrRule from Parent: + item + '''.parseRosetta + .assertError(ATTRIBUTE, null, "The overridden type is incompatible with the inherited rule reference `AttrRule`. Either change the type or override the rule reference") + } + + @Test + def void testMustNotOverrideRuleReferenceWhenRestrictingTypeToCompatibleType() { + ''' + type Parent: + type Child extends Parent: + + type Foo: + attr Parent (1..1) + [ruleReference AttrRule] + + type Bar extends Foo: + override attr Child (1..1) + + reporting rule AttrRule from Child: + item + '''.parseRosettaWithNoIssues + } + + @Test + def void supportDeprecatedAnnotationOnAttribute() { + val model = ''' + type Foo: + attr int (1..1) + [deprecated] + otherAttr int (1..1) + + func Bar: + inputs: + foo Foo (1..1) + output: + result int (1..1) + + set result: + foo -> attr + '''.parseRosetta + + model.assertWarning(ROSETTA_FEATURE_CALL, null, "attr is deprecated") + } + + @Test + def void inheritDeprecatedAnnotationOnAttributeOverride() { + ''' + type Foo: + attr string (1..1) + [deprecated] + + type Bar extends Foo: + override attr string (1..1) + + func Test: + inputs: + bar Bar (1..1) + output: + result string (1..1) + + set result: + bar -> attr + '''.parseRosetta + .assertWarning(ROSETTA_FEATURE_CALL, null, "attr is deprecated") + } + + @Test + def void testCardinalityHasAtLeastOneValue() { + ''' + type Foo: + attr int (2..1) + '''.parseRosetta + .assertError(ROSETTA_CARDINALITY, null, "The upper bound must be greater than the lower bound") + } +} \ No newline at end of file diff --git a/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/EnumValidatorTest.xtend b/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/EnumValidatorTest.xtend index 09b417d3d..61952fcb3 100644 --- a/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/EnumValidatorTest.xtend +++ b/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/EnumValidatorTest.xtend @@ -18,6 +18,17 @@ class EnumValidatorTest implements RosettaIssueCodes { @Inject extension ValidationTestHelper @Inject extension ModelHelper + @Test + def void testEnumNameShouldBeCapitalized() { + val model = + ''' + enum quoteRejectReasonEnum: + Other + '''.parseRosettaWithNoErrors + model.assertWarning(ROSETTA_ENUMERATION, INVALID_CASE, + "Enumeration name should start with a capital") + } + @Test def void testDuplicateEnumValue() { val model = ''' diff --git a/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/RosettaNamespaceDescriptionValidatorTest.xtend b/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/RosettaNamespaceDescriptionValidatorTest.xtend deleted file mode 100644 index 2b9e266b0..000000000 --- a/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/RosettaNamespaceDescriptionValidatorTest.xtend +++ /dev/null @@ -1,38 +0,0 @@ -/* - * generated by Xtext 2.10.0 - */ -package com.regnosys.rosetta.validation - -import com.regnosys.rosetta.tests.RosettaInjectorProvider -import com.regnosys.rosetta.tests.util.ModelHelper -import org.eclipse.xtext.testing.InjectWith -import org.eclipse.xtext.testing.extensions.InjectionExtension -import org.eclipse.xtext.testing.validation.ValidationTestHelper -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.^extension.ExtendWith -import javax.inject.Inject - -@ExtendWith(InjectionExtension) -@InjectWith(RosettaInjectorProvider) -class RosettaNamespaceDescriptionValidatorTest { - - @Inject extension ValidationTestHelper - @Inject extension ModelHelper - - @Test - def void testNamespaceDescription() { - val model = - ''' - namespace cdm.base.test : <"some description"> - version "test" - - enum TestEnum: - one - two - - '''.parseRosettaWithNoErrors - model.assertNoErrors - } - - -} diff --git a/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/RosettaValidatorTest.xtend b/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/RosettaValidatorTest.xtend index 5297f87c7..29c197b12 100644 --- a/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/RosettaValidatorTest.xtend +++ b/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/RosettaValidatorTest.xtend @@ -1589,49 +1589,6 @@ class RosettaValidatorTest implements RosettaIssueCodes { model.assertError(ROSETTA_IMPLICIT_VARIABLE, null, "Expected type `number`, but got `Foo` instead.") } - - @Test - def void testLowerCaseClass() { - val model = - ''' - synonym source FIX - synonym source FpML - - type partyIdentifier: <""> - partyId string (1..1) <""> - [synonym FIX value "PartyID" tag 448] - [synonym FpML value "partyId"] - '''.parseRosettaWithNoErrors - model.assertWarning(DATA, INVALID_CASE, - "Type name should start with a capital") - } - - @Test - def void testLowerCaseEnumeration() { - val model = - ''' - enum quoteRejectReasonEnum: <""> - UnknownSymbol - Other - '''.parseRosettaWithNoErrors - model.assertWarning(ROSETTA_ENUMERATION, INVALID_CASE, - "Enumeration name should start with a capital") - } - - @Test - def void testUpperCaseAttribute() { - val model = - ''' - synonym source FIX - synonym source FpML - type PartyIdentifier: <""> - PartyId string (1..1) <""> - [synonym FIX value "PartyID" tag 448] - [synonym FpML value "partyId"] - '''.parseRosettaWithNoErrors - model.assertWarning(ATTRIBUTE, INVALID_CASE, - "Attribute name should start with a lower case") - } @Test def void testTypeExpectation() { @@ -1835,7 +1792,7 @@ class RosettaValidatorTest implements RosettaIssueCodes { type Bar extends Foo: i int (0..1) '''.parseRosetta - model.assertError(ATTRIBUTE, CARDINALITY_ERROR, "Overriding attribute 'i' with cardinality (0..1) must match the cardinality of the attribute it overrides (1..1)") + model.assertWarning(ATTRIBUTE, null, "Duplicate attribute 'i'. To override the type, cardinality or annotations of this attribute, use the keyword `override`.") } @Test @@ -1847,7 +1804,7 @@ class RosettaValidatorTest implements RosettaIssueCodes { type Bar extends Foo: i int (1..*) '''.parseRosetta - model.assertError(ATTRIBUTE, CARDINALITY_ERROR, "Overriding attribute 'i' with cardinality (1..*) must match the cardinality of the attribute it overrides (1..1)") + model.assertWarning(ATTRIBUTE, null, "Duplicate attribute 'i'. To override the type, cardinality or annotations of this attribute, use the keyword `override`.") } @Test @@ -1859,7 +1816,7 @@ class RosettaValidatorTest implements RosettaIssueCodes { type Bar extends Foo: i string (1..1) '''.parseRosetta - model.assertError(ATTRIBUTE, DUPLICATE_ATTRIBUTE, "Overriding attribute 'i' with type string must match the type of the attribute it overrides (int)") + model.assertWarning(ATTRIBUTE, null, "Duplicate attribute 'i'. To override the type, cardinality or annotations of this attribute, use the keyword `override`.") } @Test @@ -2128,19 +2085,6 @@ class RosettaValidatorTest implements RosettaIssueCodes { "'as-key' can only be used with attributes annotated with [metadata reference] annotation.") } - @Test - def checkAsKeyUsage_03() { - val model = ''' - type WithKey: - - type TypeToUse: - attr WithKey (0..1) - [metadata reference] - '''.parseRosetta - model.assertWarning(ATTRIBUTE, null, - "WithKey must be annotated with [metadata key] as reference annotation is used") - } - @Test def checkAsKeyUsage_04() { val model = ''' diff --git a/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/TypeValidatorTest.xtend b/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/TypeValidatorTest.xtend new file mode 100644 index 000000000..1b312c1b5 --- /dev/null +++ b/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/TypeValidatorTest.xtend @@ -0,0 +1,122 @@ +package com.regnosys.rosetta.validation + +import com.regnosys.rosetta.tests.util.ModelHelper +import org.eclipse.xtext.testing.InjectWith +import org.eclipse.xtext.testing.extensions.InjectionExtension +import org.eclipse.xtext.testing.validation.ValidationTestHelper +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.^extension.ExtendWith + +import static com.regnosys.rosetta.rosetta.RosettaPackage.Literals.* +import static com.regnosys.rosetta.rosetta.simple.SimplePackage.Literals.* +import javax.inject.Inject + +@ExtendWith(InjectionExtension) +@InjectWith(MyRosettaInjectorProvider) +class TypeValidatorTest implements RosettaIssueCodes { + + @Inject extension ValidationTestHelper + @Inject extension ModelHelper + + @Test + def void testTypeNameShouldBeCapitalized() { + ''' + type partyIdentifier: + partyId string (1..1) + '''.parseRosettaWithNoErrors + .assertWarning(DATA, INVALID_CASE, "Type name should start with a capital") + } + + @Test + def void testTypeNameMayStartWithUnderscore() { + ''' + type _PartyIdentifier: + partyId string (1..1) + '''.parseRosettaWithNoIssues + } + + @Test + def void testAttributeOverridesMustComeFirst() { + ''' + type Foo: + attr number (0..1) + + type Bar extends Foo: + barAttr int (1..1) + override attr number (1..1) + '''.parseRosetta + .assertError(ATTRIBUTE, null, "Attribute overrides should come before any new attributes.") + } + + @Test + def void testCannotOverrideAttributeTwice() { + ''' + type Foo: + attr number (0..1) + + type Bar extends Foo: + override attr number (1..1) + override attr int (1..1) + '''.parseRosetta + .assertError(ATTRIBUTE, null, "Duplicate attribute override for 'attr'.") + } + + @Test + def void testOverridingAttributeWithoutKeywordIsDeprecated() { + // Note: once support is dropped, this should become a duplicate attribute error. + ''' + type Foo: + attr string (1..1) + + type Bar extends Foo: + attr string (1..1) + '''.parseRosetta + .assertWarning(ATTRIBUTE, null, "Duplicate attribute 'attr'. To override the type, cardinality or annotations of this attribute, use the keyword `override`.") + } + + @Test + def void testSuperTypeMayNotBeAChoiceType() { + val model = ''' + choice StringOrNumber: + string + number + + type Foo extends StringOrNumber: + '''.parseRosetta + + model.assertWarning(DATA, null, "Extending a choice type is deprecated") + } + + @Test + def void testSuperTypesCannotHaveACycle() { + val model = ''' + type A extends C: + + type B extends A: + + type C extends B: + '''.parseRosetta + + model.assertError(DATA, null, "Cyclic extension: A extends C extends B extends A") + model.assertError(DATA, null, "Cyclic extension: B extends A extends C extends B") + model.assertError(DATA, null, "Cyclic extension: C extends B extends A extends C") + } + + @Test + def void supportDeprecatedAnnotationOnType() { + val model = ''' + type TestTypeDeprecated: + [deprecated] + attr int (1..1) + + func Foo: + output: + result TestTypeDeprecated (1..1) + + set result: + TestTypeDeprecated { attr: 42 } + '''.parseRosetta + + model.assertWarning(TYPE_CALL, null, "TestTypeDeprecated is deprecated") + } +} \ No newline at end of file diff --git a/rosetta-tools/src/main/java/com/regnosys/rosetta/tools/modelimport/XsdTypeImport.java b/rosetta-tools/src/main/java/com/regnosys/rosetta/tools/modelimport/XsdTypeImport.java index 936b4abdf..068710fc0 100644 --- a/rosetta-tools/src/main/java/com/regnosys/rosetta/tools/modelimport/XsdTypeImport.java +++ b/rosetta-tools/src/main/java/com/regnosys/rosetta/tools/modelimport/XsdTypeImport.java @@ -229,6 +229,7 @@ private void completeData(Data data, Stream abstractElements if (choiceGroup.attributes.size() > 1) { Condition choice = SimpleFactory.eINSTANCE.createCondition(); choice.setName("Choice"); + // TODO: shouldn't the count of parent attributes also be taken into account? if (choiceGroup.attributes.size() == data.getAttributes().size() && choiceGroup.required) { OneOfOperation oneOf = ExpressionFactory.eINSTANCE.createOneOfOperation(); oneOf.setOperator("one-of");