diff --git a/pom.xml b/pom.xml index 486aa22..8db339c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ lunatic-model jar - 3.12.0 + 3.13.0 Lunatic Model Classes and converters for the Lunatic model https://inseefr.github.io/Lunatic-Model/ diff --git a/src/main/java/fr/insee/lunatic/model/flat/variable/CalculatedVariableType.java b/src/main/java/fr/insee/lunatic/model/flat/variable/CalculatedVariableType.java index dd4efc4..f3f02f2 100644 --- a/src/main/java/fr/insee/lunatic/model/flat/variable/CalculatedVariableType.java +++ b/src/main/java/fr/insee/lunatic/model/flat/variable/CalculatedVariableType.java @@ -1,6 +1,8 @@ package fr.insee.lunatic.model.flat.variable; +import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; import fr.insee.lunatic.model.flat.LabelType; import lombok.Getter; import lombok.Setter; @@ -11,8 +13,6 @@ /** * A calculated variable contains an expression to be evaluated at runtime. */ -@Getter -@Setter public class CalculatedVariableType extends VariableType { public CalculatedVariableType() { @@ -20,14 +20,53 @@ public CalculatedVariableType() { } /** Expression of the calculated variable. */ + @Getter @Setter protected LabelType expression; /** Name of collected and/or external variables that are required to evaluate the expression. */ + @Getter @Setter @JsonInclude(JsonInclude.Include.NON_EMPTY) protected List bindingDependencies = new ArrayList<>(); - /** Name of the collected variable that define the 'shape' of the variable. - * To be replaced with iteration reference and dimension. */ - protected String shapeFrom; + /** Name of the collected variables that determine the 'shape' of the variable. */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + protected List shapeFrom = new ArrayList<>(); + + /** + * Returns the list of the 'shape from' variable names. + * @return A list of variable names. + */ + @JsonProperty("shapeFrom") + public List getShapeFromList() { + return shapeFrom; + } + + @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) + public void setShapeFrom(List variableNames) { + this.shapeFrom = variableNames; + } + + /** + * Get the first variable in the shape from variables list. + * @return A variable name. + * @deprecated The shape from property is a list now so this method will be removed at some point. + */ + @Deprecated(since = "3.13.0") + public String getShapeFrom() { + if (shapeFrom.isEmpty()) + return null; + return shapeFrom.getFirst(); + } + + /** + * Set shape from variable. + * @param variableName Variable name. + * @deprecated The shape from property is now a list of variable names. + */ + @Deprecated(since = "3.13.0") + public void setShapeFrom(String variableName) { + shapeFrom.clear(); + shapeFrom.add(variableName); + } } diff --git a/src/test/java/fr/insee/lunatic/conversion/variable/CalculatedVariableSerializationTest.java b/src/test/java/fr/insee/lunatic/conversion/variable/CalculatedVariableSerializationTest.java index f7c35d7..be753eb 100644 --- a/src/test/java/fr/insee/lunatic/conversion/variable/CalculatedVariableSerializationTest.java +++ b/src/test/java/fr/insee/lunatic/conversion/variable/CalculatedVariableSerializationTest.java @@ -54,7 +54,7 @@ class CalculatedVariableSerializationTest { "value": "", "type": "VTL" }, - "shapeFrom": "SOME_COLLECTED_VARIABLE" + "shapeFrom": ["SOME_COLLECTED_VARIABLE"] } ] }"""; @@ -90,7 +90,7 @@ void serializeCalculatedVariable_withShapeFrom() throws SerializationException, calculatedVariableType.setExpression(new LabelType()); calculatedVariableType.getExpression().setValue(""); calculatedVariableType.getExpression().setType(LabelTypeEnum.VTL); - calculatedVariableType.setShapeFrom("SOME_COLLECTED_VARIABLE"); + calculatedVariableType.getShapeFromList().add("SOME_COLLECTED_VARIABLE"); questionnaire.getVariables().add(calculatedVariableType); // String result = jsonSerializer.serialize(questionnaire); @@ -124,8 +124,53 @@ void deserializeCalculatedVariable_withShapeFrom() throws SerializationException assertEquals(1, questionnaire.getVariables().size()); CalculatedVariableType calculatedVariableType = assertInstanceOf(CalculatedVariableType.class, questionnaire.getVariables().getFirst()); - assertEquals("SOME_COLLECTED_VARIABLE", calculatedVariableType.getShapeFrom()); + assertEquals(1, calculatedVariableType.getShapeFromList().size()); + assertEquals("SOME_COLLECTED_VARIABLE", calculatedVariableType.getShapeFromList().getFirst()); assertEquals(1, calculatedVariableType.getDimension().value()); } + @Test + void deserializeShapeFrom_twoVariables() throws SerializationException { + // + String jsonInput = """ + {"componentType":"Questionnaire","variables":[ + {"variableType":"CALCULATED","shapeFrom":["VAR1", "VAR2"]} + ]}"""; + // + Questionnaire deserialized = jsonDeserializer.deserialize(new ByteArrayInputStream(jsonInput.getBytes())); + // + CalculatedVariableType calculatedVariable = (CalculatedVariableType) deserialized.getVariables().getFirst(); + assertEquals(List.of("VAR1", "VAR2"), calculatedVariable.getShapeFromList()); + } + + @Test + void serializeShapeFrom_twoVariables() throws SerializationException, JSONException { + // + Questionnaire questionnaire = new Questionnaire(); + CalculatedVariableType calculatedVariable = new CalculatedVariableType(); + calculatedVariable.setShapeFrom(List.of("VAR1", "VAR2")); + questionnaire.getVariables().add(calculatedVariable); + // + String serialized = jsonSerializer.serialize(questionnaire); + // + String expected = """ + {"componentType":"Questionnaire","variables":[ + {"variableType":"CALCULATED","shapeFrom":["VAR1", "VAR2"]} + ]}"""; + JSONAssert.assertEquals(expected, serialized, JSONCompareMode.STRICT); + } + + @Test + void stringShapeFrom_backwardCompatibility() throws SerializationException { + // + String stringShapeFrom = """ + {"componentType":"Questionnaire","variables":[ + {"variableType":"CALCULATED","shapeFrom":"FOO"} + ]}"""; + // + Questionnaire deserialized = jsonDeserializer.deserialize(new ByteArrayInputStream(stringShapeFrom.getBytes())); + CalculatedVariableType calculatedVariable = (CalculatedVariableType) deserialized.getVariables().getFirst(); + assertEquals("FOO", calculatedVariable.getShapeFromList().getFirst()); + } + }