From 3c56d87299b7a4289beee60b63f67ef5ca21a197 Mon Sep 17 00:00:00 2001 From: nscuro Date: Tue, 17 Oct 2023 14:49:56 +0200 Subject: [PATCH] Fix XML deserialization of legacy `Tool`s Fixes #338 Signed-off-by: nscuro --- .../util/deserializer/MetadataDeserializer.java | 15 +++++++++++++-- .../org/cyclonedx/parsers/JsonParserTest.java | 13 +++++++++++++ .../org/cyclonedx/parsers/XmlParserTest.java | 13 +++++++++++++ .../regression/issue338-multiple-tools.json | 16 ++++++++++++++++ .../regression/issue338-multiple-tools.xml | 17 +++++++++++++++++ .../regression/issue338-single-tool.json | 13 +++++++++++++ .../regression/issue338-single-tool.xml | 13 +++++++++++++ 7 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 src/test/resources/regression/issue338-multiple-tools.json create mode 100644 src/test/resources/regression/issue338-multiple-tools.xml create mode 100644 src/test/resources/regression/issue338-single-tool.json create mode 100644 src/test/resources/regression/issue338-single-tool.xml diff --git a/src/main/java/org/cyclonedx/util/deserializer/MetadataDeserializer.java b/src/main/java/org/cyclonedx/util/deserializer/MetadataDeserializer.java index ce10becb6..0314ac251 100644 --- a/src/main/java/org/cyclonedx/util/deserializer/MetadataDeserializer.java +++ b/src/main/java/org/cyclonedx/util/deserializer/MetadataDeserializer.java @@ -105,8 +105,19 @@ public Metadata deserialize(JsonParser jsonParser, DeserializationContext ctxt) metadata.setTools(tools); } else if (toolsNode.has("tool")) { - Tool tool = mapper.convertValue(toolsNode.get("tool"), Tool.class); - metadata.setTools(Collections.singletonList(tool)); + final JsonNode toolNode = toolsNode.get("tool"); + // When deserializing XML BOMs, and multiple tools are provided, Jackson's internal + // representation looks like this: + // {"tool": [{"name": "foo"}, {"name": "bar"}]} + // If only a single tool is provided, it looks like this: + // {"tool": {"name": "foo"}} + if (toolNode.isArray()) { + List tools = mapper.convertValue(toolsNode.get("tool"), new TypeReference>() { }); + metadata.setTools(tools); + } else { + Tool tool = mapper.convertValue(toolsNode.get("tool"), Tool.class); + metadata.setTools(Collections.singletonList(tool)); + } } else { ToolInformation toolInformation = new ToolInformation(); diff --git a/src/test/java/org/cyclonedx/parsers/JsonParserTest.java b/src/test/java/org/cyclonedx/parsers/JsonParserTest.java index bf062158a..790a36435 100644 --- a/src/test/java/org/cyclonedx/parsers/JsonParserTest.java +++ b/src/test/java/org/cyclonedx/parsers/JsonParserTest.java @@ -185,4 +185,17 @@ public void testParsedObjects15Bom_validTools() throws Exception { assertCommonBomProperties(bom, Version.VERSION_15); assertMetadata_validTools(bom.getMetadata()); } + + @Test + public void testIssue338RegressionWithSingleTool() throws Exception { + final Bom bom = getJsonBom("regression/issue338-single-tool.json"); + assertEquals("acme-tool-a", bom.getMetadata().getTools().get(0).getName()); + } + + @Test + public void testIssue338RegressionWithMultipleTools() throws Exception { + final Bom bom = getJsonBom("regression/issue338-multiple-tools.json"); + assertEquals("acme-tool-a", bom.getMetadata().getTools().get(0).getName()); + assertEquals("acme-tool-b", bom.getMetadata().getTools().get(1).getName()); + } } diff --git a/src/test/java/org/cyclonedx/parsers/XmlParserTest.java b/src/test/java/org/cyclonedx/parsers/XmlParserTest.java index a1b2d9e92..845d2d48e 100644 --- a/src/test/java/org/cyclonedx/parsers/XmlParserTest.java +++ b/src/test/java/org/cyclonedx/parsers/XmlParserTest.java @@ -341,4 +341,17 @@ public void testParsedObjects14Bom_WithVulnsExtension() throws Exception { assertEquals(1, bom.getVersion()); assertNull(bom.getVulnerabilities()); } + + @Test + public void testIssue338RegressionWithSingleTool() throws Exception { + final Bom bom = getXmlBom("regression/issue338-single-tool.xml"); + assertEquals("acme-tool-a", bom.getMetadata().getTools().get(0).getName()); + } + + @Test + public void testIssue338RegressionWithMultipleTools() throws Exception { + final Bom bom = getXmlBom("regression/issue338-multiple-tools.xml"); + assertEquals("acme-tool-a", bom.getMetadata().getTools().get(0).getName()); + assertEquals("acme-tool-b", bom.getMetadata().getTools().get(1).getName()); + } } diff --git a/src/test/resources/regression/issue338-multiple-tools.json b/src/test/resources/regression/issue338-multiple-tools.json new file mode 100644 index 000000000..52ed13217 --- /dev/null +++ b/src/test/resources/regression/issue338-multiple-tools.json @@ -0,0 +1,16 @@ +{ + "bomFormat" : "CycloneDX", + "specVersion" : "1.4", + "serialNumber": "urn:uuid:1624fa6f-aebe-4dba-8ead-f2c876c9b832", + "version" : 1, + "metadata": { + "tools": [ + { + "name": "acme-tool-a" + }, + { + "name": "acme-tool-b" + } + ] + } +} \ No newline at end of file diff --git a/src/test/resources/regression/issue338-multiple-tools.xml b/src/test/resources/regression/issue338-multiple-tools.xml new file mode 100644 index 000000000..c6f354873 --- /dev/null +++ b/src/test/resources/regression/issue338-multiple-tools.xml @@ -0,0 +1,17 @@ + + + + + + acme-tool-a + 1.0.0 + + + acme-tool-b + 2.0.0 + + + + \ No newline at end of file diff --git a/src/test/resources/regression/issue338-single-tool.json b/src/test/resources/regression/issue338-single-tool.json new file mode 100644 index 000000000..ff5fa2774 --- /dev/null +++ b/src/test/resources/regression/issue338-single-tool.json @@ -0,0 +1,13 @@ +{ + "bomFormat" : "CycloneDX", + "specVersion" : "1.4", + "serialNumber": "urn:uuid:1624fa6f-aebe-4dba-8ead-f2c876c9b832", + "version" : 1, + "metadata": { + "tools": [ + { + "name": "acme-tool-a" + } + ] + } +} \ No newline at end of file diff --git a/src/test/resources/regression/issue338-single-tool.xml b/src/test/resources/regression/issue338-single-tool.xml new file mode 100644 index 000000000..e157dc260 --- /dev/null +++ b/src/test/resources/regression/issue338-single-tool.xml @@ -0,0 +1,13 @@ + + + + + + acme-tool-a + 1.0.0 + + + + \ No newline at end of file