Skip to content

Commit e74c780

Browse files
Story/948/4954 - circular dependency support (#806)
* task:4954 - change tabulator to generate an interface with an inner class impl * task:4954 - change tabulator to skip references * task:4954 - change tabulator to generate code is slightly different style * task:4954 - change tabulator to generate code is slightly different style * task:4954 - add test to confirm circular dependency fix * task:4954 - deprecate * task:4954 - fix tests * task:4954 - fix tests * task:4954 - make inner class public
1 parent f320ef7 commit e74c780

File tree

7 files changed

+283
-397
lines changed

7 files changed

+283
-397
lines changed

Diff for: rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/reports/TabulatorGenerator.xtend

+63-78
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import com.regnosys.rosetta.rosetta.RosettaRule
3535
import com.regnosys.rosetta.generator.java.types.JavaTypeUtil
3636
import com.regnosys.rosetta.rosetta.simple.Function
3737
import com.regnosys.rosetta.config.RosettaConfiguration
38+
import com.google.inject.ImplementedBy
3839

3940
class TabulatorGenerator {
4041
private interface TabulatorContext {
@@ -247,38 +248,35 @@ class TabulatorGenerator {
247248
val innerTabulatorClass = context.toTabulatorJavaClass(inputType)
248249
val innerTabulatorInstance = classScope.createUniqueIdentifier("tabulator")
249250
'''
250-
public class «tabulatorClass» implements «Tabulator»<«inputClass»> {
251-
private final «innerTabulatorClass» «innerTabulatorInstance»;
252-
253-
@«Inject»
254-
public «tabulatorClass»(«innerTabulatorClass» «innerTabulatorInstance») {
255-
this.«innerTabulatorInstance» = «innerTabulatorInstance»;
256-
}
257-
258-
@Override
259-
public «List»<«Field»> getFields() {
260-
return «innerTabulatorInstance».getFields();
261-
}
262-
263-
@Override
264-
public «List»<«FieldValue»> tabulate(«inputClass» «inputParam») {
265-
return «innerTabulatorInstance».tabulate(«inputParam»);
251+
@«ImplementedBy»(«tabulatorClass».Impl.class)
252+
public interface «tabulatorClass» extends «Tabulator»<«inputClass»> {
253+
public class Impl implements «tabulatorClass» {
254+
private final «innerTabulatorClass» «innerTabulatorInstance»;
255+
256+
@«Inject»
257+
public Impl(«innerTabulatorClass» «innerTabulatorInstance») {
258+
this.«innerTabulatorInstance» = «innerTabulatorInstance»;
259+
}
260+
261+
@Override
262+
public «List»<«FieldValue»> tabulate(«inputClass» «inputParam») {
263+
return «innerTabulatorInstance».tabulate(«inputParam»);
264+
}
266265
}
267266
}
268267
'''
269268
} else {
270269
// There is no available tabulator for `inputType`,
271270
// so we generate a dummy implementation.
272271
'''
273-
public class «tabulatorClass» implements «Tabulator»<«inputClass»> {
274-
@Override
275-
public «List»<«Field»> getFields() {
276-
return «Arrays».asList();
277-
}
278-
279-
@Override
280-
public «List»<«FieldValue»> tabulate(«inputClass» «inputParam») {
281-
return «Arrays».asList();
272+
@«ImplementedBy»(«tabulatorClass».Impl.class)
273+
public interface «tabulatorClass» extends «Tabulator»<«inputClass»> {
274+
class Impl implements «tabulatorClass» {
275+
276+
@Override
277+
public «List»<«FieldValue»> tabulate(«inputClass» «inputParam») {
278+
return «Arrays».asList();
279+
}
282280
}
283281
}
284282
'''
@@ -291,41 +289,38 @@ class TabulatorGenerator {
291289
val classScope = topScope.classScope(tabulatorClass.simpleName)
292290
val tabulatedFields = findTabulatedFieldsAndCreateIdentifiers(inputType, context, classScope)
293291
val nestedTabulatorInstances = findNestedTabulatorsAndCreateIdentifiers(inputType, context, classScope)
294-
295292
val tabulateScope = classScope.methodScope("tabulate")
296293
val inputParam = tabulateScope.createUniqueIdentifier("input")
297294
'''
298-
public class «tabulatorClass» implements «Tabulator»<«inputClass»> {
299-
«FOR attr : inputType.allNonOverridesAttributes»
300-
«IF context.isTabulated(attr)»
301-
«val fieldId = classScope.getIdentifierOrThrow(attr)»
302-
private final «Field» «fieldId»;
303-
«ENDIF»
304-
«ENDFOR»
305-
«IF !nestedTabulatorInstances.empty»
306-
307-
«FOR tabInst : nestedTabulatorInstances»
308-
private final «context.toTabulatorJavaClass(tabInst.type)» «classScope.getIdentifierOrThrow(tabInst)»;
309-
«ENDFOR»
310-
«ENDIF»
311-
312-
«IF !nestedTabulatorInstances.empty»@«Inject»«ENDIF»
313-
public «tabulatorClass»(«FOR tabInst : nestedTabulatorInstances SEPARATOR ", "»«context.toTabulatorJavaClass(tabInst.type)» «classScope.getIdentifierOrThrow(tabInst)»«ENDFOR») {
295+
@«ImplementedBy»(«tabulatorClass».Impl.class)
296+
public interface «tabulatorClass» extends «Tabulator»<«inputClass»> {
297+
public class Impl implements «tabulatorClass» {
298+
«FOR attr : inputType.allNonOverridesAttributes»
299+
«IF context.isTabulated(attr)»
300+
«val fieldId = classScope.getIdentifierOrThrow(attr)»
301+
private final «Field» «fieldId»;
302+
«ENDIF»
303+
«ENDFOR»
304+
«IF !nestedTabulatorInstances.empty»
305+
314306
«FOR tabInst : nestedTabulatorInstances»
315-
this.«classScope.getIdentifierOrThrow(tabInst)» = «classScope.getIdentifierOrThrow(tabInst)»;
307+
private final «context.toTabulatorJavaClass(tabInst.type)» «classScope.getIdentifierOrThrow(tabInst)»;
316308
«ENDFOR»
317-
«initializeFields(inputType, context, classScope)»
318-
}
319-
320-
@Override
321-
public «List»<«Field»> getFields() {
322-
return «Arrays».asList(«FOR field : tabulatedFields SEPARATOR ", "»«classScope.getIdentifierOrThrow(field)»«ENDFOR»);
323-
}
324-
325-
@Override
326-
public «List»<«FieldValue»> tabulate(«inputClass» «inputParam») {
327-
«computeFieldValues(inputType, inputParam, context, tabulateScope)»
328-
return «fieldValuesAsList(inputType, context, tabulateScope)»;
309+
«ENDIF»
310+
311+
«IF !nestedTabulatorInstances.empty»@«Inject»«ENDIF»
312+
public Impl(«FOR tabInst : nestedTabulatorInstances SEPARATOR ", "»«context.toTabulatorJavaClass(tabInst.type)» «classScope.getIdentifierOrThrow(tabInst)»«ENDFOR») {
313+
«FOR tabInst : nestedTabulatorInstances»
314+
this.«classScope.getIdentifierOrThrow(tabInst)» = «classScope.getIdentifierOrThrow(tabInst)»;
315+
«ENDFOR»
316+
«initializeFields(inputType, context, classScope)»
317+
}
318+
319+
@Override
320+
public «List»<«FieldValue»> tabulate(«inputClass» «inputParam») {
321+
«computeFieldValues(inputType, inputParam, context, tabulateScope)»
322+
return «fieldValuesAsList(inputType, context, tabulateScope)»;
323+
}
329324
}
330325
}
331326
'''
@@ -352,11 +347,7 @@ class TabulatorGenerator {
352347
«attr.card.isMany»,
353348
«rule.map[model].map[name].map[new ModelSymbolId(DottedPath.splitOnDots(it), rule.get.name).toModelSymbolCode].toOptionalCode»,
354349
«rule.map[identifier].map['"' + it + '"'].toOptionalCode»,
355-
«IF attrType instanceof Data»
356-
«scope.getIdentifierOrThrow(attrType.toNestedTabulatorInstance)».getFields()
357-
«ELSE»
358-
«Arrays».asList()
359-
«ENDIF»
350+
«Arrays».asList()
360351
);
361352
«ENDIF»
362353
«ENDFOR»
@@ -383,6 +374,7 @@ class TabulatorGenerator {
383374
«ENDFOR»
384375
'''
385376
}
377+
386378
private def StringConcatenationClient fieldValue(Attribute attr, GeneratedIdentifier inputParam, JavaScope scope) {
387379
val rType = typeProvider.getRTypeOfSymbol(attr)
388380

@@ -404,28 +396,31 @@ class TabulatorGenerator {
404396
val attrType = rType.data
405397
val nestedTabulator = scope.getIdentifierOrThrow(attrType.toNestedTabulatorInstance)
406398
'''
407-
«Optional»<«resultType»> «resultId» = «Optional».ofNullable(«inputParam».get«attr.name.toFirstUpper»())
399+
«FieldValue» «resultId» = «Optional».ofNullable(«inputParam».get«attr.name.toFirstUpper»())
408400
«IF attr.card.isMany»
409401
.map(«lambdaParam» -> «lambdaParam».stream()
410402
.map(«nestedLambdaParam» -> «nestedTabulator».tabulate(«nestedLambdaParam»«IF !attr.metaAnnotations.empty».getValue()«ENDIF»))
411-
.collect(«Collectors».toList()));
403+
.collect(«Collectors».toList()))
404+
.map(fieldValues -> new «MultiNestedFieldValueImpl»(«scope.getIdentifierOrThrow(attr)», Optional.of(fieldValues)))
405+
.orElse(new «MultiNestedFieldValueImpl»(«scope.getIdentifierOrThrow(attr)», Optional.empty()));
412406
«ELSE»
413-
.map(«lambdaParam» -> «nestedTabulator».tabulate(«lambdaParam»«IF !attr.metaAnnotations.empty».getValue()«ENDIF»));
407+
.map(«lambdaParam» -> new «NestedFieldValueImpl»(«scope.getIdentifierOrThrow(attr)», Optional.of(«nestedTabulator».tabulate(«lambdaParam»«IF !attr.metaAnnotations.empty».getValue()«ENDIF»))))
408+
.orElse(new «NestedFieldValueImpl»(«scope.getIdentifierOrThrow(attr)», Optional.empty()));
414409
«ENDIF»
415410
'''
416411
} else {
417412
val resultType = rType.toPolymorphicListOrSingleJavaType(attr.card.isMany)
418413
'''
419414
«IF attr.metaAnnotations.empty»
420-
«Optional»<«resultType»> «resultId» = «Optional».ofNullable(«inputParam».get«attr.name.toFirstUpper»());
415+
«FieldValue» «resultId» = new «FieldValueImpl»(«scope.getIdentifierOrThrow(attr)», «Optional».ofNullable(«inputParam».get«attr.name.toFirstUpper»()));
421416
«ELSEIF attr.card.isMany»
422-
«Optional»<«resultType»> «resultId» = «Optional».ofNullable(«inputParam».get«attr.name.toFirstUpper»())
417+
«FieldValue» «resultId» = new «FieldValueImpl»(«scope.getIdentifierOrThrow(attr)», «Optional».ofNullable(«inputParam».get«attr.name.toFirstUpper»())
423418
.map(«lambdaParam» -> «lambdaParam».stream()
424419
.map(«nestedLambdaParam» -> «nestedLambdaParam».getValue())
425420
.collect(«Collectors».toList()));
426421
«ELSE»
427-
«Optional»<«resultType»> «resultId» = «Optional».ofNullable(«inputParam».get«attr.name.toFirstUpper»())
428-
.map(«lambdaParam» -> «lambdaParam».getValue());
422+
«FieldValue» «resultId» = new «FieldValueImpl»(«scope.getIdentifierOrThrow(attr)», «Optional».ofNullable(«inputParam».get«attr.name.toFirstUpper»())
423+
.map(«lambdaParam» -> «lambdaParam».getValue()));
429424
«ENDIF»
430425
'''
431426
}
@@ -435,17 +430,7 @@ class TabulatorGenerator {
435430
'''
436431
«Arrays».asList(
437432
«FOR attr : type.allNonOverridesAttributes.filter[context.isTabulated(it)] SEPARATOR ","»
438-
«val attrType = attr.typeCall.type»
439-
«val valueClass = if (attrType instanceof Data) {
440-
if (attr.card.isMany) {
441-
MultiNestedFieldValueImpl
442-
} else {
443-
NestedFieldValueImpl
444-
}
445-
} else {
446-
FieldValueImpl
447-
448-
new «valueClass»(«scope.getIdentifierOrThrow(attr)», «scope.getIdentifierOrThrow(attr.toComputedField)»)
433+
«scope.getIdentifier(attr.toComputedField)»
449434
«ENDFOR»
450435
)'''
451436
}

Diff for: rosetta-runtime/src/main/java/com/rosetta/model/lib/reports/Tabulator.java

+10-23
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.rosetta.model.lib.reports;
1818

19+
import java.util.Arrays;
1920
import java.util.List;
2021
import java.util.Objects;
2122
import java.util.Optional;
@@ -27,7 +28,14 @@
2728

2829
public interface Tabulator<T> {
2930

30-
List<Field> getFields();
31+
/**
32+
* Deprecated because it was only used in tests
33+
* @return Arrays.asList()
34+
*/
35+
@Deprecated
36+
default List<Field> getFields() {
37+
return Arrays.asList();
38+
}
3139
List<FieldValue> tabulate(T report);
3240

3341
public interface Field {
@@ -67,10 +75,8 @@ public interface FieldValueVisitor<C> {
6775
void visitNested(NestedFieldValue fieldValue, C context);
6876
void visitMultiNested(MultiNestedFieldValue fieldValue, C context);
6977
}
70-
7178
public static class FieldImpl implements Field {
7279
private String attributeName;
73-
7480
private boolean isMulti;
7581
private Optional<ModelSymbolId> ruleId;
7682
private Optional<String> identifier;
@@ -87,36 +93,29 @@ public FieldImpl(String attributeName, boolean isMulti, Optional<ModelSymbolId>
8793
this.identifier = identifier;
8894
this.children = children;
8995
}
90-
9196
@Override
9297
public String getName() {
9398
return identifier.orElse(attributeName);
9499
}
95-
96100
@Override
97101
public String getAttributeName() {
98102
return attributeName;
99103
}
100-
101104
@Override
102105
public boolean isMulti() {
103106
return isMulti;
104107
}
105-
106108
public Optional<ModelSymbolId> getRuleId() {
107109
return ruleId;
108110
}
109-
110111
@Override
111112
public List<Field> getChildren() {
112113
return children;
113114
}
114-
115115
@Override
116116
public int hashCode() {
117117
return Objects.hash(attributeName, children, identifier, isMulti, ruleId);
118118
}
119-
120119
@Override
121120
public boolean equals(Object obj) {
122121
if (this == obj)
@@ -141,7 +140,6 @@ public FieldValueImpl(Field field, Optional<? extends Object> value) {
141140
this.field = field;
142141
this.value = value;
143142
}
144-
145143
@Override
146144
public Field getField() {
147145
return field;
@@ -150,17 +148,14 @@ public Field getField() {
150148
public Optional<? extends Object> getValue() {
151149
return value;
152150
}
153-
154151
@Override
155152
public String toString() {
156-
return "<" + field.getName() + ", " + value.map(Object::toString).orElse("<empty>") + ">";
153+
return String.format("<%s, %s, alreadyReferenced [%b], referencedField [%s]>", field.getName(), value.map(Object::toString).orElse("<empty>"));
157154
}
158-
159155
@Override
160156
public int hashCode() {
161157
return Objects.hash(field, value);
162158
}
163-
164159
@Override
165160
public boolean equals(Object obj) {
166161
if (this == obj)
@@ -186,7 +181,6 @@ public NestedFieldValueImpl(Field field, Optional<? extends List<? extends Field
186181
this.field = field;
187182
this.value = value;
188183
}
189-
190184
@Override
191185
public Field getField() {
192186
return field;
@@ -195,7 +189,6 @@ public Field getField() {
195189
public Optional<? extends List<? extends FieldValue>> getValue() {
196190
return value;
197191
}
198-
199192
@Override
200193
public String toString() {
201194
String valueRepr = value
@@ -205,12 +198,10 @@ public String toString() {
205198
.orElse("<empty>");
206199
return "<" + field.getName() + ", " + valueRepr + ">";
207200
}
208-
209201
@Override
210202
public int hashCode() {
211203
return Objects.hash(field, value);
212204
}
213-
214205
@Override
215206
public boolean equals(Object obj) {
216207
if (this == obj)
@@ -237,7 +228,6 @@ public MultiNestedFieldValueImpl(Field field, Optional<? extends List<? extends
237228
this.field = field;
238229
this.value = value;
239230
}
240-
241231
@Override
242232
public Field getField() {
243233
return field;
@@ -246,7 +236,6 @@ public Field getField() {
246236
public Optional<? extends List<? extends List<? extends FieldValue>>> getValue() {
247237
return value;
248238
}
249-
250239
@Override
251240
public String toString() {
252241
String valueRepr = value
@@ -258,12 +247,10 @@ public String toString() {
258247
.orElse("<empty>");
259248
return "<" + field.getName() + ", " + valueRepr + ">";
260249
}
261-
262250
@Override
263251
public int hashCode() {
264252
return Objects.hash(field, value);
265253
}
266-
267254
@Override
268255
public boolean equals(Object obj) {
269256
if (this == obj)

0 commit comments

Comments
 (0)