Skip to content

Commit

Permalink
Merge pull request #365 from dmeibusch/parseexception_with_ancestors_fix
Browse files Browse the repository at this point in the history
Parseexception with ancestors fix
  • Loading branch information
stevespringett authored May 14, 2024
2 parents c78bce5 + f85233b commit cfd7d0f
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,15 @@

import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.dataformat.xml.deser.FromXmlParser;
import org.cyclonedx.model.Ancestors;
import org.cyclonedx.model.Component;
Expand Down Expand Up @@ -72,10 +77,25 @@ public ComponentWrapper deserialize(
return null;
}

Component[] components = parser.readValueAs(Component[].class);

wrapper.setComponents(Arrays.asList(components));

List<Component> components = Collections.emptyList();
JsonToken currentToken = parser.currentToken();
if (currentToken == JsonToken.START_ARRAY) {
components = Arrays.asList(parser.readValueAs(Component[].class));
} else if (currentToken == JsonToken.START_OBJECT) {
// This is possible for XML input when tree has been read, then parsed with token buffer parser
ObjectNode node = parser.readValueAs(ObjectNode.class);
if (node.has("component")) {
JsonNode component = node.get("component");
JsonParser componentsParser = component.traverse(parser.getCodec());
if (component.isArray()) {
components = Arrays.asList(componentsParser.readValueAs(Component[].class));
} else {
components = Collections.singletonList(componentsParser.readValueAs(Component.class));
}
}
}
wrapper.setComponents(components);
return wrapper;

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
Expand All @@ -28,8 +28,6 @@
public class MetadataDeserializer
extends JsonDeserializer<Metadata> {

private final ObjectMapper mapper = new ObjectMapper();

private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");

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

Metadata metadata = new Metadata();

ObjectMapper mapper;
if (jsonParser.getCodec() instanceof ObjectMapper) {
mapper = (ObjectMapper) jsonParser.getCodec();
} else {
mapper = new ObjectMapper();
}

// Parsing other fields in the Metadata object
if (node.has("authors")) {
JsonNode authorsNode = node.get("authors");
Expand Down Expand Up @@ -127,10 +132,10 @@ else if (toolsNode.has("tool")) {
else {
ToolInformation toolInformation = new ToolInformation();
if (toolsNode.has("components")) {
parseComponents(toolsNode.get("components"), toolInformation);
parseComponents(toolsNode.get("components"), toolInformation, mapper);
}
if (toolsNode.has("services")) {
parseServices(toolsNode.get("services"), toolInformation);
parseServices(toolsNode.get("services"), toolInformation, mapper);
}
metadata.setToolChoice(toolInformation);
}
Expand All @@ -139,7 +144,7 @@ else if (toolsNode.has("tool")) {
return metadata;
}

private void parseComponents(JsonNode componentsNode, ToolInformation toolInformation) {
private void parseComponents(JsonNode componentsNode, ToolInformation toolInformation, ObjectMapper mapper) {
if (componentsNode != null) {
if (componentsNode.isArray()) {
List<Component> components = mapper.convertValue(componentsNode, new TypeReference<List<Component>>() {});
Expand All @@ -151,7 +156,7 @@ private void parseComponents(JsonNode componentsNode, ToolInformation toolInform
}
}

private void parseServices(JsonNode servicesNode, ToolInformation toolInformation) {
private void parseServices(JsonNode servicesNode, ToolInformation toolInformation, ObjectMapper mapper) {
if (servicesNode != null) {
if (servicesNode.isArray()) {
List<Service> services = mapper.convertValue(servicesNode, new TypeReference<List<Service>>() {});
Expand Down
19 changes: 18 additions & 1 deletion src/test/java/org/cyclonedx/parsers/XmlParserTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
*/
package org.cyclonedx.parsers;

import org.cyclonedx.CycloneDxSchema;
import org.cyclonedx.CycloneDxSchema.Version;
import org.cyclonedx.Version;
import org.cyclonedx.model.Bom;
import org.cyclonedx.model.Component;
Expand Down Expand Up @@ -74,6 +76,7 @@
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;

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

@Test
public void testValid12BomWithMetadataPedigree() throws Exception {
final File file = new File(Objects.requireNonNull(this.getClass().getResource("/bom-1.2-metadata-pedigree.xml")).getFile());
final XmlParser parser = new XmlParser();
final boolean valid = parser.isValid(file, CycloneDxSchema.Version.VERSION_12);
assertTrue(valid);

final Bom bom = parser.parse(file);
Pedigree pedigree = bom.getMetadata().getComponent().getPedigree();
assertEquals(2, pedigree.getAncestors().getComponents().size());
assertEquals(1, pedigree.getDescendants().getComponents().size());
assertEquals(0, pedigree.getVariants().getComponents().size());
}

@Test
public void testParsedObjects10Bom() throws Exception {
final Bom bom = getXmlBom("bom-1.0.xml");
Expand Down Expand Up @@ -388,7 +405,7 @@ public void testIssue336Regression() throws Exception {
assertEquals("foo", bom.getMetadata().getComponent().getProperties().get(0).getName());
assertEquals("bar", bom.getMetadata().getComponent().getProperties().get(0).getValue());
}

@Test
public void testIssue338RegressionWithSingleTool() throws Exception {
final Bom bom = getXmlBom("regression/issue338-single-tool.xml");
Expand Down
35 changes: 35 additions & 0 deletions src/test/resources/bom-1.2-metadata-pedigree.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.2"
serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79"
version="1">
<metadata>
<component type="library">
<group>com.acme</group>
<name>sample-library</name>
<version>1.0.0</version>
<pedigree>
<ancestors>
<component type="library">
<group>org.example</group>
<name>sample-library-ancestor-1</name>
<version>1.0.0</version>
</component>
<component type="library">
<group>org.example</group>
<name>sample-library-ancestor-2</name>
<version>1.0.0</version>
</component>
</ancestors>
<descendants>
<component type="library">
<group>org.example</group>
<name>sample-library-descendant</name>
<version>1.0.1</version>
</component>
</descendants>
<variants>
</variants>
</pedigree>
</component>
</metadata>
</bom>

0 comments on commit cfd7d0f

Please sign in to comment.