Skip to content

Commit cfd7d0f

Browse files
Merge pull request #365 from dmeibusch/parseexception_with_ancestors_fix
Parseexception with ancestors fix
2 parents c78bce5 + f85233b commit cfd7d0f

File tree

4 files changed

+90
-13
lines changed

4 files changed

+90
-13
lines changed

src/main/java/org/cyclonedx/util/deserializer/ComponentWrapperDeserializer.java

+24-4
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,15 @@
2020

2121
import java.io.IOException;
2222
import java.util.Arrays;
23+
import java.util.Collections;
24+
import java.util.List;
2325

2426
import com.fasterxml.jackson.core.JsonParser;
27+
import com.fasterxml.jackson.core.JsonToken;
2528
import com.fasterxml.jackson.databind.DeserializationContext;
2629
import com.fasterxml.jackson.databind.JsonDeserializer;
30+
import com.fasterxml.jackson.databind.JsonNode;
31+
import com.fasterxml.jackson.databind.node.ObjectNode;
2732
import com.fasterxml.jackson.dataformat.xml.deser.FromXmlParser;
2833
import org.cyclonedx.model.Ancestors;
2934
import org.cyclonedx.model.Component;
@@ -72,10 +77,25 @@ public ComponentWrapper deserialize(
7277
return null;
7378
}
7479

75-
Component[] components = parser.readValueAs(Component[].class);
76-
77-
wrapper.setComponents(Arrays.asList(components));
78-
80+
List<Component> components = Collections.emptyList();
81+
JsonToken currentToken = parser.currentToken();
82+
if (currentToken == JsonToken.START_ARRAY) {
83+
components = Arrays.asList(parser.readValueAs(Component[].class));
84+
} else if (currentToken == JsonToken.START_OBJECT) {
85+
// This is possible for XML input when tree has been read, then parsed with token buffer parser
86+
ObjectNode node = parser.readValueAs(ObjectNode.class);
87+
if (node.has("component")) {
88+
JsonNode component = node.get("component");
89+
JsonParser componentsParser = component.traverse(parser.getCodec());
90+
if (component.isArray()) {
91+
components = Arrays.asList(componentsParser.readValueAs(Component[].class));
92+
} else {
93+
components = Collections.singletonList(componentsParser.readValueAs(Component.class));
94+
}
95+
}
96+
}
97+
wrapper.setComponents(components);
7998
return wrapper;
99+
80100
}
81101
}

src/main/java/org/cyclonedx/util/deserializer/MetadataDeserializer.java

+13-8
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import java.io.IOException;
44
import java.text.ParseException;
55
import java.text.SimpleDateFormat;
6-
import java.util.Date;
7-
import java.util.List;
86
import java.util.ArrayList;
97
import java.util.Collections;
8+
import java.util.Date;
9+
import java.util.List;
1010

1111
import com.fasterxml.jackson.core.JsonParser;
1212
import com.fasterxml.jackson.core.type.TypeReference;
@@ -28,8 +28,6 @@
2828
public class MetadataDeserializer
2929
extends JsonDeserializer<Metadata> {
3030

31-
private final ObjectMapper mapper = new ObjectMapper();
32-
3331
private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
3432

3533
private final LifecycleDeserializer lifecycleDeserializer = new LifecycleDeserializer();
@@ -42,6 +40,13 @@ public Metadata deserialize(JsonParser jsonParser, DeserializationContext ctxt)
4240

4341
Metadata metadata = new Metadata();
4442

43+
ObjectMapper mapper;
44+
if (jsonParser.getCodec() instanceof ObjectMapper) {
45+
mapper = (ObjectMapper) jsonParser.getCodec();
46+
} else {
47+
mapper = new ObjectMapper();
48+
}
49+
4550
// Parsing other fields in the Metadata object
4651
if (node.has("authors")) {
4752
JsonNode authorsNode = node.get("authors");
@@ -127,10 +132,10 @@ else if (toolsNode.has("tool")) {
127132
else {
128133
ToolInformation toolInformation = new ToolInformation();
129134
if (toolsNode.has("components")) {
130-
parseComponents(toolsNode.get("components"), toolInformation);
135+
parseComponents(toolsNode.get("components"), toolInformation, mapper);
131136
}
132137
if (toolsNode.has("services")) {
133-
parseServices(toolsNode.get("services"), toolInformation);
138+
parseServices(toolsNode.get("services"), toolInformation, mapper);
134139
}
135140
metadata.setToolChoice(toolInformation);
136141
}
@@ -139,7 +144,7 @@ else if (toolsNode.has("tool")) {
139144
return metadata;
140145
}
141146

142-
private void parseComponents(JsonNode componentsNode, ToolInformation toolInformation) {
147+
private void parseComponents(JsonNode componentsNode, ToolInformation toolInformation, ObjectMapper mapper) {
143148
if (componentsNode != null) {
144149
if (componentsNode.isArray()) {
145150
List<Component> components = mapper.convertValue(componentsNode, new TypeReference<List<Component>>() {});
@@ -151,7 +156,7 @@ private void parseComponents(JsonNode componentsNode, ToolInformation toolInform
151156
}
152157
}
153158

154-
private void parseServices(JsonNode servicesNode, ToolInformation toolInformation) {
159+
private void parseServices(JsonNode servicesNode, ToolInformation toolInformation, ObjectMapper mapper) {
155160
if (servicesNode != null) {
156161
if (servicesNode.isArray()) {
157162
List<Service> services = mapper.convertValue(servicesNode, new TypeReference<List<Service>>() {});

src/test/java/org/cyclonedx/parsers/XmlParserTest.java

+18-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
*/
1919
package org.cyclonedx.parsers;
2020

21+
import org.cyclonedx.CycloneDxSchema;
22+
import org.cyclonedx.CycloneDxSchema.Version;
2123
import org.cyclonedx.Version;
2224
import org.cyclonedx.model.Bom;
2325
import org.cyclonedx.model.Component;
@@ -74,6 +76,7 @@
7476
import static org.junit.jupiter.api.Assertions.assertNotNull;
7577
import static org.junit.jupiter.api.Assertions.assertNull;
7678
import static org.junit.jupiter.api.Assertions.assertTrue;
79+
import org.junit.jupiter.api.Test;
7780

7881
public class XmlParserTest
7982
extends AbstractParserTest
@@ -165,6 +168,20 @@ private void testPedigreeFromExample(final Pedigree pedigree) {
165168
assertEquals(2, pedigree.getPatches().get(1).getResolves().size());
166169
}
167170

171+
@Test
172+
public void testValid12BomWithMetadataPedigree() throws Exception {
173+
final File file = new File(Objects.requireNonNull(this.getClass().getResource("/bom-1.2-metadata-pedigree.xml")).getFile());
174+
final XmlParser parser = new XmlParser();
175+
final boolean valid = parser.isValid(file, CycloneDxSchema.Version.VERSION_12);
176+
assertTrue(valid);
177+
178+
final Bom bom = parser.parse(file);
179+
Pedigree pedigree = bom.getMetadata().getComponent().getPedigree();
180+
assertEquals(2, pedigree.getAncestors().getComponents().size());
181+
assertEquals(1, pedigree.getDescendants().getComponents().size());
182+
assertEquals(0, pedigree.getVariants().getComponents().size());
183+
}
184+
168185
@Test
169186
public void testParsedObjects10Bom() throws Exception {
170187
final Bom bom = getXmlBom("bom-1.0.xml");
@@ -388,7 +405,7 @@ public void testIssue336Regression() throws Exception {
388405
assertEquals("foo", bom.getMetadata().getComponent().getProperties().get(0).getName());
389406
assertEquals("bar", bom.getMetadata().getComponent().getProperties().get(0).getValue());
390407
}
391-
408+
392409
@Test
393410
public void testIssue338RegressionWithSingleTool() throws Exception {
394411
final Bom bom = getXmlBom("regression/issue338-single-tool.xml");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<bom xmlns="http://cyclonedx.org/schema/bom/1.2"
3+
serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79"
4+
version="1">
5+
<metadata>
6+
<component type="library">
7+
<group>com.acme</group>
8+
<name>sample-library</name>
9+
<version>1.0.0</version>
10+
<pedigree>
11+
<ancestors>
12+
<component type="library">
13+
<group>org.example</group>
14+
<name>sample-library-ancestor-1</name>
15+
<version>1.0.0</version>
16+
</component>
17+
<component type="library">
18+
<group>org.example</group>
19+
<name>sample-library-ancestor-2</name>
20+
<version>1.0.0</version>
21+
</component>
22+
</ancestors>
23+
<descendants>
24+
<component type="library">
25+
<group>org.example</group>
26+
<name>sample-library-descendant</name>
27+
<version>1.0.1</version>
28+
</component>
29+
</descendants>
30+
<variants>
31+
</variants>
32+
</pedigree>
33+
</component>
34+
</metadata>
35+
</bom>

0 commit comments

Comments
 (0)