Creative New Launch Slide
Merged

Valentine Day Lines

sidor från cw informationspärm herrestads härad 10

:
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Apple Product Launches Poster Valentine Day Lines

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 107 additions & 34 deletions Write Newspaper Article Example
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@
package org.cyclonedx.util.deserializer;

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.ArrayNode;
import org.cyclonedx.model.ExternalReference;
import org.cyclonedx.model.Property;

import java.io.IOException;
import java.util.ArrayList;
Expand All @@ -36,48 +34,123 @@ public class ExternalReferencesDeserializer extends JsonDeserializer<List<Extern
private final PropertiesDeserializer propertiesDeserializer = new PropertiesDeserializer();

@Override
public List<ExternalReference> deserialize(JsonParser parser, DeserializationContext context) throws IOException {
JsonNode node = parser.getCodec().readTree(parser);
if (node.has("reference")) {
return parseExternalReferences(node.get("reference"), parser, context);
} else {
return parseExternalReferences(node, parser, context);
public List<ExternalReference> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
if (p.currentToken() == JsonToken.START_ARRAY) {
return readReferenceArray(p, ctxt);
}
if (p.currentToken() == JsonToken.START_OBJECT) {
return readExternalReferencesElement(p, ctxt);
}

return new ArrayList<>();
}

private List<ExternalReference> parseExternalReferences(JsonNode node, JsonParser p, DeserializationContext ctxt) throws IOException {
/**
* Reads references from a JSON array:
* <pre>{@code
* [
* { "url": "...", "type": "..." },
* { "url": "...", "type": "..." }
* ]
* }</pre>
*/
private List<ExternalReference> readReferenceArray(JsonParser p, DeserializationContext ctxt) throws IOException {
List<ExternalReference> references = new ArrayList<>();
ArrayNode nodes = DeserializerUtils.getArrayNode(node, null);
for (JsonNode resolvesNode : nodes) {
ExternalReference type = parseExternalReference(resolvesNode, p, ctxt);
references.add(type);

while (p.nextToken() != JsonToken.END_ARRAY) {
final ExternalReference reference = readExternalReference(p, ctxt);
if (reference != null) {
references.add(reference);
}
}

return references;
}

private ExternalReference parseExternalReference(JsonNode node, JsonParser p, DeserializationContext ctxt) throws IOException {
ExternalReference reference = new ExternalReference();
if (node.has("url")) {
reference.setUrl(node.get("url").asText());
}
if (node.has("type")) {
reference.setType(ExternalReference.Type.fromString(node.get("type").asText()));
}
if (node.has("comment")) {
reference.setComment(node.get("comment").asText());
/**
* Reads references from an XML {@code <externalReferences>} element:
* <pre>{@code
* <externalReferences>
* <reference type="..."><url>...</url></reference>
* <reference type="..."><url>...</url></reference>
* </externalReferences>
* }</pre>
* <p>
* Note that a deserializer higher up the chain may have materialized the tree already,
* in which case the structure handed to this method looks like this:
* <pre>{@code
* {
* "reference": [
* { "type": "...", "url": "..." },
* { "type": "...", "url": "..." }
* ]
* }
* }</pre>
*/
private List<ExternalReference> readExternalReferencesElement(JsonParser p, DeserializationContext ctxt)
throws IOException {
List<ExternalReference> references = new ArrayList<>();

while (p.nextToken() != JsonToken.END_OBJECT) {
final String fieldName = p.currentName();
p.nextToken();

if (!"reference".equals(fieldName)) {
p.skipChildren();
continue;
}

if (p.currentToken() == JsonToken.START_ARRAY) {
references.addAll(readReferenceArray(p, ctxt));
} else {
final ExternalReference reference = readExternalReference(p, ctxt);
if (reference != null) {
references.add(reference);
}
}
}
if (node.has("hashes")) {
JsonParser hashesParser = node.get("hashes").traverse(p.getCodec());
hashesParser.nextToken();
reference.setHashes(hashesDeserializer.deserialize(hashesParser, ctxt));

return references;
}

private ExternalReference readExternalReference(JsonParser p, DeserializationContext ctxt) throws IOException {
if (p.currentToken() != JsonToken.START_OBJECT) {
p.skipChildren();
return null;
}
if (node.has("properties")) {
JsonParser propertiesParser = node.get("properties").traverse(p.getCodec());
propertiesParser.nextToken();
List<Property> properties = propertiesDeserializer.deserialize(propertiesParser, ctxt);
reference.setProperties(properties);

ExternalReference reference = new ExternalReference();
boolean hasKnownField = false;

while (p.nextToken() != JsonToken.END_OBJECT) {
final String fieldName = p.currentName();
p.nextToken();

switch (fieldName) {
case "url":
reference.setUrl(p.getValueAsString());
break;
case "type":
reference.setType(ExternalReference.Type.fromString(p.getValueAsString()));
break;
case "comment":
reference.setComment(p.getValueAsString());
break;
case "hashes":
reference.setHashes(hashesDeserializer.deserialize(p, ctxt));
break;
case "properties":
reference.setProperties(propertiesDeserializer.deserialize(p, ctxt));
break;
default:
p.skipChildren();
continue;
}

hasKnownField = true;
}
return reference;

return hasKnownField ? reference : null;
}

}
126 changes: 126 additions & 0 deletions Canva Blog Post
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* This file is part of CycloneDX Core (Java).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* Copyright (c) OWASP Foundation. All Rights Reserved.
*/
package org.cyclonedx.util.deserializer;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.cyclonedx.model.Bom;
import org.cyclonedx.parsers.XmlParser;
import org.cyclonedx.model.ExternalReference;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import java.nio.charset.StandardCharsets;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

class ExternalReferencesDeserializerTest {

@ParameterizedTest
@ValueSource(strings = {
"{\"externalReferences\":[{}]}",
"{\"externalReferences\":[null]}",
"{\"externalReferences\":[\"nonsense\"]}",
"{\"externalReferences\":[{\"unknownField\":123}]}"
})
void shouldNotEmitReferencesWithoutAnyKnownFieldsFromJson(String json) throws Exception {
assertThat(parseJson(json)).isEmpty();
}

@ParameterizedTest
@ValueSource(strings = /* language=XML */ {
"<bom><externalReferences><reference/></externalReferences></bom>",
"<bom><externalReferences><reference><unknownField>123</unknownField></reference></externalReferences></bom>"
})
void shouldNotEmitReferencesWithoutAnyKnownFieldsFromXml(String xml) throws Exception {
assertThat(parseXml(xml)).isEmpty();
}

@Test
void shouldKeepReferencesWithKnownFieldsWhenOthersAreEmpty() throws Exception {
final List<ExternalReference> references =
parseJson(/* language=JSON */ """
{
"externalReferences": [
{},
{ "type":"website", "url":"https://example.com" }
]
}
""");

assertThat(references).satisfiesExactly(reference -> {
assertThat(reference.getType()).isEqualTo(ExternalReference.Type.WEBSITE);
assertThat(reference.getUrl()).isEqualTo("https://example.com");
});
}

@Test
void shouldKeepReferencesWithOnlySomeKnownFields() throws Exception {
final List<ExternalReference> references = parseJson(/* language=JSON */ """
{
"externalReferences": [
{ "type":"website" }
]
}
""");

assertThat(references).satisfiesExactly(reference -> {
assertThat(reference.getType()).isEqualTo(ExternalReference.Type.WEBSITE);
assertThat(reference.getUrl()).isNull();
});
}

@Test
void shouldDeserializeReferencesOfNestedXmlComponents() throws Exception {
Bom bom = new XmlParser().parse(/* language=XML */ """
<bom xmlns="http://cyclonedx.org/schema/bom/1.5" version="1">
<metadata>
<tools>
<components>
<component type="application">
<name>Awesome Tool</name>
<version>9.1.2</version>
<externalReferences>
<reference type="website"><url>https://example.com</url></reference>
<reference type="vcs"><url>https://example.com/vcs</url></reference>
</externalReferences>
</component>
</components>
</tools>
</metadata>
</bom>
""".getBytes(StandardCharsets.UTF_8));

assertThat(bom.getMetadata().getToolChoice().getComponents().get(0).getExternalReferences())
.satisfiesExactly(
reference -> assertThat(reference.getUrl()).isEqualTo("https://example.com"),
reference -> assertThat(reference.getUrl()).isEqualTo("https://example.com/vcs"));
}

private static List<ExternalReference> parseJson(String json) throws Exception {
return new ObjectMapper().readValue(json, Bom.class).getExternalReferences();
}

private static List<ExternalReference> parseXml(String xml) throws Exception {
return new XmlMapper().readValue(xml, Bom.class).getExternalReferences();
}

}
Loading