Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Story- 711 new data structure regulation validation #721

Closed
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import com.regnosys.rosetta.generator.java.reports.ReportGenerator
import javax.inject.Inject
import com.regnosys.rosetta.rosetta.RosettaRule
import com.regnosys.rosetta.rosetta.RosettaReport
import com.regnosys.rosetta.generator.java.validator.ValidatorGenerator

/**
* Generates code from your model files on save.
Expand All @@ -57,6 +58,7 @@ class RosettaGenerator implements IGenerator2 {

@Inject ModelObjectGenerator dataGenerator
@Inject ValidatorsGenerator validatorsGenerator
@Inject ValidatorGenerator validatorGenerator
@Inject extension RosettaFunctionExtensions
@Inject FunctionGenerator funcGenerator
@Inject ReportGenerator reportGenerator
Expand Down Expand Up @@ -146,10 +148,13 @@ class RosettaGenerator implements IGenerator2 {
Data: {
dataGenerator.generate(packages, fsa, it, version)
metaGenerator.generate(packages, fsa, it, version)
//legacy
validatorsGenerator.generate(packages, fsa, it, version)
it.conditions.forEach [ cond |
conditionGenerator.generate(packages, fsa, it, cond, version)
]
//new
validatorGenerator.generate(packages, fsa, it, version)
tabulatorGenerator.generate(fsa, it, Optional.empty)
}
Function: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.regnosys.rosetta.generator.java.condition

import com.google.inject.ImplementedBy
import com.regnosys.rosetta.RosettaExtensions
import com.regnosys.rosetta.generator.java.JavaIdentifierRepresentationService
import com.regnosys.rosetta.generator.java.JavaScope
import com.regnosys.rosetta.generator.java.RosettaJavaPackages.RootPackage
import com.regnosys.rosetta.generator.java.expression.ExpressionGenerator
import com.regnosys.rosetta.generator.java.function.FunctionDependencyProvider
import com.regnosys.rosetta.generator.java.types.JavaTypeTranslator
import com.regnosys.rosetta.generator.java.types.JavaTypeUtil
import com.regnosys.rosetta.generator.java.util.ImportManagerExtension
import com.regnosys.rosetta.generator.java.util.RosettaGrammarUtil
import com.regnosys.rosetta.rosetta.simple.Condition
Expand All @@ -15,17 +17,15 @@ import com.regnosys.rosetta.types.RDataType
import com.rosetta.model.lib.annotations.RosettaDataRule
import com.rosetta.model.lib.expression.ComparisonResult
import com.rosetta.model.lib.path.RosettaPath
import com.rosetta.model.lib.validation.ConditionValidationData
import com.rosetta.model.lib.validation.ValidationResult
import com.rosetta.model.lib.validation.Validator
import javax.inject.Inject
import org.eclipse.xtend2.lib.StringConcatenationClient
import org.eclipse.xtext.generator.IFileSystemAccess2

import static com.regnosys.rosetta.generator.java.util.ModelGeneratorUtil.*
import static com.regnosys.rosetta.rosetta.simple.SimplePackage.Literals.CONDITION__EXPRESSION
import javax.inject.Inject
import com.google.inject.ImplementedBy
import com.rosetta.model.lib.validation.ValidationResult.ValidationType
import com.regnosys.rosetta.generator.java.types.JavaTypeUtil

class ConditionGenerator {
@Inject ExpressionGenerator expressionHandler
Expand Down Expand Up @@ -85,7 +85,7 @@ class ConditionGenerator {
String NAME = "«ruleName»";
String DEFINITION = «definition»;

«ValidationResult»<«rosettaClass.name»> validate(«RosettaPath» «pathId», «rosettaClass.name» «validateScope.createIdentifier(implicitVarRepr, rosettaClass.name.toFirstLower)»);
«ValidationResult» validate(«RosettaPath» «pathId», «rosettaClass.name» «validateScope.createIdentifier(implicitVarRepr, rosettaClass.name.toFirstLower)»);

class «defaultClassName» implements «className» {

Expand All @@ -94,17 +94,17 @@ class ConditionGenerator {

«ENDFOR»
@Override
public «ValidationResult»<«rosettaClass.name»> validate(«RosettaPath» «defaultClassPathId», «rosettaClass.name» «defaultClassValidateScope.createIdentifier(implicitVarRepr, rosettaClass.name.toFirstLower)») {
public «ValidationResult» validate(«RosettaPath» «defaultClassPathId», «rosettaClass.name» «defaultClassValidateScope.createIdentifier(implicitVarRepr, rosettaClass.name.toFirstLower)») {
«ComparisonResult» «defaultClassResultId» = executeDataRule(«defaultClassValidateScope.getIdentifierOrThrow(implicitVarRepr)»);
if (result.get()) {
return «ValidationResult».success(NAME, ValidationResult.ValidationType.DATA_RULE, "«rosettaClass.name»", «defaultClassPathId», DEFINITION);
return «ValidationResult».success(«defaultClassPathId»);
}

String «defaultClassFailureMessageId» = «defaultClassResultId».getError();
if («defaultClassFailureMessageId» == null || «defaultClassFailureMessageId».contains("Null") || «defaultClassFailureMessageId» == "") {
«defaultClassFailureMessageId» = "Condition has failed.";
}
return «ValidationResult».failure(NAME, «ValidationType».DATA_RULE, "«rosettaClass.name»", «defaultClassPathId», DEFINITION, «defaultClassFailureMessageId»);
return «ValidationResult».failure(«defaultClassPathId», «defaultClassFailureMessageId», new «ConditionValidationData»());
}

private «ComparisonResult» executeDataRule(«rosettaClass.name» «defaultClassExecuteScope.createIdentifier(implicitVarRepr, rosettaClass.name.toFirstLower)») {
Expand All @@ -120,8 +120,8 @@ class ConditionGenerator {
class «noOpClassName» implements «className» {

@Override
public «ValidationResult»<«rosettaClass.name»> validate(«RosettaPath» «noOpClassPathId», «rosettaClass.name» «noOpClassValidateScope.createIdentifier(implicitVarRepr, rosettaClass.name.toFirstLower)») {
return «ValidationResult».success(NAME, ValidationResult.ValidationType.DATA_RULE, "«rosettaClass.name»", «noOpClassPathId», DEFINITION);
public «ValidationResult» validate(«RosettaPath» «noOpClassPathId», «rosettaClass.name» «noOpClassValidateScope.createIdentifier(implicitVarRepr, rosettaClass.name.toFirstLower)») {
return «ValidationResult».success(«noOpClassPathId»);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ import com.rosetta.model.lib.expression.ExpressionOperators
import com.rosetta.model.lib.expression.MapperMaths
import com.rosetta.model.lib.mapper.MapperC
import com.rosetta.model.lib.mapper.MapperS
import com.rosetta.model.lib.validation.ValidationResult.ChoiceRuleValidationMethod
import com.rosetta.model.lib.validation.ChoiceRuleValidationMethod
import java.math.BigDecimal
import java.time.LocalTime
import java.time.format.DateTimeFormatter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,16 @@ class ModelMetaGenerator {
«ENDIF»
}

@Deprecated
@Override
public «Validator»<? super «dataClass»> validator() {
return new «validator»();
throw new «UnsupportedOperationException»();
}

@Deprecated
@Override
public «Validator»<? super «dataClass»> typeFormatValidator() {
return new «typeFormatValidator»();
throw new «UnsupportedOperationException»();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import com.rosetta.model.lib.expression.ExpressionOperators
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.ValidationType
import com.rosetta.model.lib.validation.Validator
import com.rosetta.model.lib.validation.ValidatorWithArg
import java.util.Map
Expand Down Expand Up @@ -51,78 +51,22 @@ class ValidatorsGenerator {

def generate(RootPackage root, IFileSystemAccess2 fsa, Data data, String version) {
val t = new RDataType(data)
fsa.generateFile(t.toValidatorClass.canonicalName.withForwardSlashes + ".java",
generateClass(root, data, version))
fsa.generateFile(t.toTypeFormatValidatorClass.canonicalName.withForwardSlashes + ".java",
generateTypeFormatValidator(root, data, version))
fsa.generateFile(t.toOnlyExistsValidatorClass.canonicalName.withForwardSlashes + ".java",
generateOnlyExistsValidator(root, data, version))
}

private def generateClass(RootPackage root, Data d, String version) {
val scope = new JavaScope(root.typeValidation)
buildClass(root.typeValidation, new RDataType(d).classBody(version, d.allNonOverridesAttributes), scope)
}

private def generateTypeFormatValidator(RootPackage root, Data d, String version) {
val scope = new JavaScope(root.typeValidation)
buildClass(root.typeValidation, new RDataType(d).typeFormatClassBody(version, d.allNonOverridesAttributes), scope)
}

private def generateOnlyExistsValidator(RootPackage root, Data d, String version) {
val scope = new JavaScope(root.existsValidation)
buildClass(root.existsValidation, new RDataType(d).onlyExistsClassBody(version, d.allNonOverridesAttributes), scope)
}

def private StringConcatenationClient classBody(RDataType t, String version, Iterable<Attribute> attributes) '''
public class «t.toValidatorClass» implements «Validator»<«t.toJavaType»> {

@Override
public «ValidationResult»<«t.toJavaType»> validate(«RosettaPath» path, «t.toJavaType» o) {
/* Casting is required to ensure types are output to ensure recompilation in Rosetta */
String error =
«Lists».<«ComparisonResult»>newArrayList(
«FOR attrCheck : attributes.map[checkCardinality(toExpandedAttribute)].filter[it !== null] SEPARATOR ", "»
«attrCheck»
«ENDFOR»
).stream().filter(res -> !res.get()).map(res -> res.getError()).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, "success")»("«t.name»", «ValidationResult.ValidationType».CARDINALITY, "«t.name»", path, "");
}

}
'''

def private StringConcatenationClient typeFormatClassBody(RDataType t, String version, Iterable<Attribute> attributes) '''
public class «t.toTypeFormatValidatorClass» implements «Validator»<«t.toJavaType»> {

@Override
public «ValidationResult»<«t.toJavaType»> validate(«RosettaPath» path, «t.toJavaType» o) {
String error =
«Lists».<«ComparisonResult»>newArrayList(
«FOR attrCheck : attributes.map[checkTypeFormat].filter[it !== null] SEPARATOR ", "»
«attrCheck»
«ENDFOR»
).stream().filter(res -> !res.get()).map(res -> res.getError()).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, "success")»("«t.name»", «ValidationResult.ValidationType».TYPE_FORMAT, "«t.name»", path, "");
}

}
'''

def private StringConcatenationClient onlyExistsClassBody(RDataType t, String version, Iterable<Attribute> attributes) '''
public class «t.toOnlyExistsValidatorClass» implements «ValidatorWithArg»<«t.toJavaType», «Set»<String>> {

/* Casting is required to ensure types are output to ensure recompilation in Rosetta */
@Override
public <T2 extends «t.toJavaType»> «ValidationResult»<«t.toJavaType»> validate(«RosettaPath» path, T2 o, «Set»<String> fields) {
public <T2 extends «t.toJavaType»> «ValidationResult» validate(«RosettaPath» path, T2 o, «Set»<String> fields) {
«Map»<String, Boolean> fieldExistenceMap = «ImmutableMap».<String, Boolean>builder()
«FOR attr : attributes»
.put("«attr.name»", «ExistenceChecker».isSet((«attr.toExpandedAttribute.toMultiMetaOrRegularJavaType») o.get«attr.name?.toFirstUpper»()))
Expand All @@ -136,84 +80,11 @@ 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")»(path);
}
return «method(ValidationResult, "failure")»("«t.name»", «ValidationType».ONLY_EXISTS, "«t.name»", path, "",
String.format("[%s] should only be set. Set fields: %s", fields, setFields));
return «method(ValidationResult, "failure")»(path,
String.format("[%s] should only be set. Set fields: %s", fields, setFields), null);
}
}
'''

private def StringConcatenationClient checkCardinality(ExpandedAttribute attr) {
if (attr.inf === 0 && attr.isUnbound) {
null
} else {
/* Casting is required to ensure types are output to ensure recompilation in Rosetta */
'''
«IF attr.isMultiple»
«method(ExpressionOperators, "checkCardinality")»("«attr.name»", («attr.toMultiMetaOrRegularJavaType») o.get«attr.name?.toFirstUpper»() == null ? 0 : ((«attr.toMultiMetaOrRegularJavaType») o.get«attr.name?.toFirstUpper»()).size(), «attr.inf», «attr.sup»)
«ELSE»
«method(ExpressionOperators, "checkCardinality")»("«attr.name»", («attr.toMultiMetaOrRegularJavaType») o.get«attr.name?.toFirstUpper»() != null ? 1 : 0, «attr.inf», «attr.sup»)
«ENDIF»
'''
}
}

private def StringConcatenationClient checkTypeFormat(Attribute attr) {
val t = attr.RTypeOfSymbol.stripFromTypeAliases
if (t instanceof RStringType) {
if (t != UNCONSTRAINED_STRING) {
val min = t.interval.minBound
val max = t.interval.max.optional
val pattern = t.pattern.optionalPattern

return '''«method(ExpressionOperators, "checkString")»("«attr.name»", «attr.attributeValue», «min», «max», «pattern»)'''
}
} else if (t instanceof RNumberType) {
if (t != UNCONSTRAINED_NUMBER) {
val digits = t.digits.optional
val fractionalDigits = t.fractionalDigits.optional
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 null
}

private def StringConcatenationClient getAttributeValue(Attribute attr) {
if (attr.metaAnnotations.empty) {
'''o.get«attr.name?.toFirstUpper»()'''
} else {
val jt = attr.toExpandedAttribute.toMultiMetaOrRegularJavaType
if (jt.isList) {
val itemType = jt.itemType
'''o.get«attr.name?.toFirstUpper»().stream().map(«itemType»::getValue).collect(«Collectors».toList())'''
} else {
'''o.get«attr.name?.toFirstUpper»().getValue()'''
}
}
}
private def StringConcatenationClient optional(Optional<? extends Object> v) {
if (v.isPresent) {
'''«method(Optional, "of")»(«v.get»)'''
} else {
'''«method(Optional, "empty")»()'''
}
}
private def StringConcatenationClient optionalPattern(Optional<Pattern> v) {
if (v.isPresent) {
'''«method(Optional, "of")»(«Pattern».compile("«StringEscapeUtils.escapeJava(v.get.toString)»"))'''
} else {
'''«method(Optional, "empty")»()'''
}
}
private def StringConcatenationClient optionalBigDecimal(Optional<BigDecimal> v) {
if (v.isPresent) {
'''«method(Optional, "of")»(new «BigDecimal»("«StringEscapeUtils.escapeJava(v.get.toString)»"))'''
} else {
'''«method(Optional, "empty")»()'''
}
}
}
Loading