diff options
author | lukegleeson <luke.gleeson@est.tech> | 2021-08-30 10:24:30 +0100 |
---|---|---|
committer | lukegleeson <luke.gleeson@est.tech> | 2021-09-03 09:42:02 +0100 |
commit | 008abaee59bb542d5a60e89fa7f4231cecf7bdf5 (patch) | |
tree | 9e0c3468fc62827cf15841fd0813aa5141299f29 | |
parent | 0af60de4fbb3a3e6c828e179c667b173b1539b62 (diff) |
Ensure Leaf value retains Integer type
BUG
GSON.fromJson() is unable to parse numerical values and defaults values to Doubles
Added a datatype conversion which forces Double values which can be Integers to being Integers
Issue-ID: CPS-591
Signed-off-by: lukegleeson <luke.gleeson@est.tech>
Change-Id: I72d54ad06823a8755ee407f39104f3edf9a8cc75
3 files changed, 52 insertions, 4 deletions
diff --git a/cps-ri/pom.xml b/cps-ri/pom.xml index 273cb2e72f..9072a52011 100644 --- a/cps-ri/pom.xml +++ b/cps-ri/pom.xml @@ -96,6 +96,10 @@ <groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ </dependency>
<!-- T E S T D E P E N D E N C I E S -->
<dependency>
<groupId>org.codehaus.groovy</groupId>
@@ -140,6 +144,7 @@ </dependency>
</dependencies>
+
<build>
<plugins>
<plugin>
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java index af010f4fcd..7b3b726284 100644 --- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java @@ -24,12 +24,15 @@ package org.onap.cps.spi.impl; import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet.Builder; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -50,6 +53,7 @@ import org.onap.cps.spi.exceptions.AlreadyDefinedException; import org.onap.cps.spi.exceptions.ConcurrencyException; import org.onap.cps.spi.exceptions.CpsPathException; import org.onap.cps.spi.exceptions.DataNodeNotFoundException; +import org.onap.cps.spi.exceptions.DataValidationException; import org.onap.cps.spi.model.DataNode; import org.onap.cps.spi.model.DataNodeBuilder; import org.onap.cps.spi.repository.AnchorRepository; @@ -68,6 +72,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService private FragmentRepository fragmentRepository; + private final ObjectMapper objectMapper; + /** * Constructor. * @@ -80,6 +86,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService this.dataspaceRepository = dataspaceRepository; this.anchorRepository = anchorRepository; this.fragmentRepository = fragmentRepository; + this.objectMapper = new ObjectMapper(); } private static final Gson GSON = new GsonBuilder().create(); @@ -236,17 +243,27 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService return ancestorXpath; } - private static DataNode toDataNode(final FragmentEntity fragmentEntity, + private DataNode toDataNode(final FragmentEntity fragmentEntity, final FetchDescendantsOption fetchDescendantsOption) { - final Map<String, Object> leaves = GSON.fromJson(fragmentEntity.getAttributes(), Map.class); final List<DataNode> childDataNodes = getChildDataNodes(fragmentEntity, fetchDescendantsOption); + Map<String, Object> leaves = new HashMap<>(); + if (fragmentEntity.getAttributes() != null) { + try { + leaves = objectMapper.readValue(fragmentEntity.getAttributes(), Map.class); + } catch (final JsonProcessingException jsonProcessingException) { + final String message = "Parsing error occurred while processing fragmentEntity attributes."; + log.error(message); + throw new DataValidationException(message, + jsonProcessingException.getMessage(), jsonProcessingException); + } + } return new DataNodeBuilder() .withXpath(fragmentEntity.getXpath()) .withLeaves(leaves) .withChildDataNodes(childDataNodes).build(); } - private static List<DataNode> getChildDataNodes(final FragmentEntity fragmentEntity, + private List<DataNode> getChildDataNodes(final FragmentEntity fragmentEntity, final FetchDescendantsOption fetchDescendantsOption) { if (fetchDescendantsOption == INCLUDE_ALL_DESCENDANTS) { return fragmentEntity.getChildFragments().stream() diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy index 5ed3ae3e8c..9fcd550bd1 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy @@ -19,6 +19,7 @@ package org.onap.cps.spi.impl import org.hibernate.StaleStateException +import org.onap.cps.spi.FetchDescendantsOption import org.onap.cps.spi.entities.FragmentEntity import org.onap.cps.spi.exceptions.ConcurrencyException import org.onap.cps.spi.model.DataNodeBuilder @@ -68,5 +69,30 @@ class CpsDataPersistenceServiceSpec extends Specification { assert concurrencyException.getDetails().contains(parentXpath) } - + def 'Retrieving a data node with a property JSON value of #scenario'() { + given: 'a fragment with a property JSON value of #scenario' + mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, _) >> { + new FragmentEntity(childFragments: Collections.emptySet(), + attributes: "{\"some attribute\": ${dataString}}") + } + when: 'getting the data node represented by this fragment' + def dataNode = objectUnderTest.getDataNode('my-dataspace', 'my-anchor', + 'parent-01', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) + then: 'the leaf is of the correct value and data type' + def attributeValue = dataNode.leaves.get('some attribute') + assert attributeValue == expectedValue + assert attributeValue.class == expectedDataClass + where: 'the following Data Type is passed' + scenario | dataString || expectedValue | expectedDataClass + 'just numbers' | '15174' || 15174 | Integer + 'number with dot' | '15174.32' || 15174.32 | Double + 'number with 0 value after dot' | '15174.0' || 15174.0 | Double + 'number with 0 value before dot' | '0.32' || 0.32 | Double + 'number higher than max int' | '2147483648' || 2147483648 | Long + 'just text' | '"Test"' || 'Test' | String + 'number with exponent' | '1.2345e5' || 1.2345e5 | Double + 'number higher than max int with dot' | '123456789101112.0' || 123456789101112.0 | Double + 'text and numbers' | '"String = \'1234\'"' || "String = '1234'" | String + 'number as String' | '"12345"' || '12345' | String + } } |