diff --git a/rosetta-integration-tests/src/test/java/com/regnosys/rosetta/generator/java/function/FunctionGeneratorMetaTest.java b/rosetta-integration-tests/src/test/java/com/regnosys/rosetta/generator/java/function/FunctionGeneratorMetaTest.java index 91c1c425b..a7ea966e2 100644 --- a/rosetta-integration-tests/src/test/java/com/regnosys/rosetta/generator/java/function/FunctionGeneratorMetaTest.java +++ b/rosetta-integration-tests/src/test/java/com/regnosys/rosetta/generator/java/function/FunctionGeneratorMetaTest.java @@ -107,8 +107,6 @@ result Foo (1..1) var code = generatorTestHelper.generateCode(model); - generatorTestHelper.writeClasses(code, "canSetMetaAddressOnFunctionObjectOutput"); - var classes = generatorTestHelper.compileToClasses(code); var myFunc = functionGeneratorHelper.createFunc(classes, "MyFunc"); @@ -188,7 +186,7 @@ result string (1..1) } - @Disabled //TODO: implement nested setting of meta and then complete this + @Disabled //TODO: is this syntax needed? if so we need to find a way to get key as a feature from a Data type @Test void canSetExternalKeyOnFunctionObjectOutput() { var model = """ @@ -211,7 +209,7 @@ result Foo (1..1) var code = generatorTestHelper.generateCode(model); } - + @Test void canSetExternalReferenceOnFunctionObjectOutput() { var model = """ @@ -231,7 +229,7 @@ result Foo (1..1) [metadata reference] set result -> reference: myKey """; - + var code = generatorTestHelper.generateCode(model); var classes = generatorTestHelper.compileToClasses(code); @@ -246,10 +244,9 @@ result Foo (1..1) assertEquals(expected, result); } - @Disabled //TODO: implement setting nested meta @Test void canSetMetaOnFunctionObjectOutputAndNestedBasicMetaField() { - var model = """ + var model = """ type Foo: a string (1..1) b string (1..1) @@ -266,6 +263,7 @@ result Foo (1..1) """; var code = generatorTestHelper.generateCode(model); + var classes = generatorTestHelper.compileToClasses(code); var myFunc = functionGeneratorHelper.createFunc(classes, "MyFunc"); 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 6fd904bde..8caaf0c07 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 @@ -458,8 +458,13 @@ class FunctionGenerator { for (var pathIndex=0; pathIndex < intermediarySegmentSize; pathIndex++) { val seg = op.pathTail.get(pathIndex) - val prop = findPojoProperty(seg, expr.expressionType.itemType) + if (expr.expressionType.itemType instanceof RJavaWithMetaValue) { + val metaExpr = expr + expr = JavaExpression.from('''«metaExpr».getOrCreateValue()''', (expr.expressionType.itemType as RJavaWithMetaValue).valueType) + } + + val prop = getPojoProperty(seg, expr.expressionType.itemType) val oldExpr = expr val itemType = prop.type.itemType expr = JavaExpression.from( @@ -468,43 +473,50 @@ class FunctionGenerator { .«prop.getOrCreateName»(«IF prop.type.isList»0«ENDIF»)''', itemType ) - if (itemType instanceof RJavaWithMetaValue) { - val metaExpr = expr - expr = JavaExpression.from('''«metaExpr».getOrCreateValue()''', itemType.valueType) - } } //end of path val seg = op.pathTail.get(op.pathTail.length - 1) - - val oldExpr = expr + val oldExpr = expr val outputExpressionType = expr.expressionType.itemType - val prop = findPojoProperty(seg, outputExpressionType) - val pojoPropertyType = prop.type.itemType + val prop = getPojoProperty(seg, outputExpressionType) - if (outputExpressionType instanceof RJavaWithMetaValue) { - expr = JavaExpression.from( - ''' - «oldExpr» - «generateMetaWrapperCreator(seg, prop, outputExpressionType)».«IF op.ROperationType == ROperationType.ADD»add«ELSE»set«ENDIF»«seg.toPojoPropertyNames.toFirstUpper»(«it»)''', - JavaPrimitiveType.VOID - ) - } else { - expr = JavaExpression.from( - ''' - «oldExpr» - .«IF op.ROperationType == ROperationType.ADD»add«ELSE»set«ENDIF»«prop.name.toFirstUpper»«IF pojoPropertyType instanceof RJavaWithMetaValue && !op.assignAsKey»Value«ENDIF»(«it»)''', - JavaPrimitiveType.VOID - ) - } + val propertySetterName = getPropertySetterName(outputExpressionType, prop, seg) + val requiresValueSetter = requiresValueSetter(outputExpressionType, prop, seg, op) + expr = JavaExpression.from( + ''' + «oldExpr» + «generateMetaWrapperCreator(seg, prop, outputExpressionType)».«IF op.ROperationType == ROperationType.ADD»add«ELSE»set«ENDIF»«propertySetterName»«IF requiresValueSetter»Value«ENDIF»(«it»)''', + JavaPrimitiveType.VOID + ) expr ].completeAsExpressionStatement } } - private def StringConcatenationClient generateMetaWrapperCreator(RFeature seg, JavaPojoProperty prop, RJavaWithMetaValue outputExpressionType) { - switch (outputExpressionType) { + private def String getPropertySetterName(JavaType outputExpressionType, JavaPojoProperty prop, RFeature segment) { + if (outputExpressionType instanceof RJavaWithMetaValue) { + segment.toPojoPropertyNames.toFirstUpper + } else { + prop.name.toFirstUpper + } + } + + private def boolean requiresValueSetter(JavaType outputExpressionType, JavaPojoProperty outerPojoProperty, RFeature segment, ROperation op) { + val outerPropertyType = outerPojoProperty.type.itemType + val innerProp = if (outputExpressionType instanceof RJavaWithMetaValue && outerPropertyType instanceof JavaPojoInterface) { + getPojoProperty(segment, outerPropertyType) + } else { + outerPojoProperty + } + + val innerPropType = innerProp.type.itemType + innerPropType instanceof RJavaWithMetaValue && !op.assignAsKey + } + + private def StringConcatenationClient generateMetaWrapperCreator(RFeature seg, JavaPojoProperty prop, JavaType expressionType) { + switch (expressionType) { RJavaFieldWithMeta: '''«IF seg instanceof RMetaAttribute».getOrCreateMeta()«ELSE».«prop.getOrCreateName»()«ENDIF»''' RJavaReferenceWithMeta case seg instanceof RMetaAttribute && seg.name == "address": '''.«prop.getOrCreateName»()''' RJavaReferenceWithMeta case !(seg instanceof RMetaAttribute): '''.getOrCreateValue()''' @@ -513,7 +525,7 @@ class FunctionGenerator { } //The type of the output expression to be set and the pojo property type are not the same when working with meta - private def JavaPojoProperty findPojoProperty(RFeature seg, JavaType outputExpressionType) { + private def JavaPojoProperty getPojoProperty(RFeature seg, JavaType outputExpressionType) { if (seg instanceof RMetaAttribute && outputExpressionType.itemType instanceof RJavaFieldWithMeta) { (outputExpressionType as JavaPojoInterface).findProperty("meta") } else if (seg instanceof RMetaAttribute && outputExpressionType.itemType instanceof RJavaReferenceWithMeta) { 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 ce09426b3..f82552f91 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 @@ -146,8 +146,7 @@ class RosettaScopeProvider extends ImportedNamespaceAwareLocalScopeProvider { // Case handles the head of the segment Operation: { val receiverType = typeProvider.getRTypeOfSymbol(context.assignRoot) - val features = receiverType.allFeatures(context, [t| !(t instanceof REnumType)]) - return Scopes.scopeFor(features) //TODO: don't get all features (i.e enum atrs) + return Scopes.scopeFor(receiverType.allFeatures(context, [t| !(t instanceof REnumType)])) } // Case handles the tail of the segment Segment: { @@ -155,7 +154,7 @@ class RosettaScopeProvider extends ImportedNamespaceAwareLocalScopeProvider { if (prev !== null) { if (prev.feature.isResolved) { val receiverType = typeProvider.getRTypeOfFeature(prev.feature, context) - return Scopes.scopeFor(receiverType.allFeatures(context, [t| !(t instanceof REnumType)])) //TODO: don't get all features (i.e enum atrs) + return Scopes.scopeFor(receiverType.allFeatures(context, [t| !(t instanceof REnumType)])) } } if (context.eContainer instanceof Operation) {