Skip to content

Commit ebd53d0

Browse files
committed
Create import references for listed licenses
When serializing with useExternalListedElements set to true, add an import entry for every listed license. This is needed to validate using some of the SPDX SHACL validate tools. Signed-off-by: Gary O'Neall <gary@sourceauditor.com>
1 parent 09d062f commit ebd53d0

File tree

1 file changed

+47
-7
lines changed

1 file changed

+47
-7
lines changed

src/main/java/org/spdx/v3jsonldstore/JsonLDSerializer.java

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public class JsonLDSerializer {
6161

6262
static final Logger logger = LoggerFactory.getLogger(JsonLDSerializer.class);
6363

64-
static final Comparator<JsonNode> NODE_COMPARATOR = new Comparator<JsonNode>() {
64+
static final Comparator<JsonNode> NODE_COMPARATOR = new Comparator<>() {
6565

6666
@Override
6767
public int compare(JsonNode arg0, JsonNode arg1) {
@@ -176,7 +176,7 @@ public JsonLDSerializer(ObjectMapper jsonMapper, boolean pretty, boolean useExte
176176
}
177177

178178
/**
179-
* @param objectToSerialize optional SPDX Document or single element to serialize
179+
* @param objectToSerialize optional SPDX Document or single element to serialize
180180
* @return the root node of the JSON serialization
181181
* @throws InvalidSPDXAnalysisException on errors retrieving the information for serialization
182182
*/
@@ -197,7 +197,7 @@ public JsonNode serialize(@Nullable CoreModelObject objectToSerialize) throws In
197197
/**
198198
* Serialize SPDX document metadata and ALL elements listed in the root + all
199199
* elements listed in the elements list
200-
*
200+
* <p>
201201
* All references to SPDX elements not in the root or elements lists will be
202202
* external.
203203
*
@@ -236,7 +236,8 @@ private JsonNode serializeSpdxDocument(SpdxDocument spdxDocument) throws Invalid
236236
idToSerializedId.put(anonId, documentSpdxId);
237237
logger.warn(NON_URI_WARNING, spdxDocument.getObjectUri(), documentSpdxId);
238238
}
239-
graph.add(spdxDocumentToJsonNode(spdxDocument, documentSpdxId, idToSerializedId));
239+
ObjectNode docJsonNode = spdxDocumentToJsonNode(spdxDocument, documentSpdxId, idToSerializedId);
240+
graph.add(docJsonNode);
240241
for (String type:jsonLDSchema.getElementTypes()) {
241242
for (Element element:elementsToCopy) {
242243
if (type.equals(element.getType())) {
@@ -247,7 +248,9 @@ private JsonNode serializeSpdxDocument(SpdxDocument spdxDocument) throws Invalid
247248
idToSerializedId.put(anonId, serializedId);
248249
logger.warn(NON_URI_WARNING, element.getObjectUri(), serializedId);
249250
}
250-
if (!(useExternalListedElements && element.getObjectUri().startsWith(SpdxConstantsV3.SPDX_LISTED_LICENSE_NAMESPACE))) {
251+
if (useExternalListedElements && element.getObjectUri().startsWith(SpdxConstantsV3.SPDX_LISTED_LICENSE_NAMESPACE)) {
252+
addExternalLicenseReference(element.getObjectUri(), docJsonNode);
253+
} else {
251254
graph.add(modelObjectToJsonNode(element, serializedId, idToSerializedId));
252255
}
253256
}
@@ -263,6 +266,40 @@ private JsonNode serializeSpdxDocument(SpdxDocument spdxDocument) throws Invalid
263266
}
264267
}
265268

269+
/**
270+
* Adds the listed license reference to the document external map if it is not already present
271+
* @param licenseUri listed license URI
272+
* @param docJsonNode JSON Node for the SPDX document
273+
*/
274+
private void addExternalLicenseReference(String licenseUri, ObjectNode docJsonNode) {
275+
JsonNode importsNode = docJsonNode.get("import");
276+
ArrayNode imports;
277+
if (Objects.isNull(importsNode) || !importsNode.isArray()) {
278+
imports = jsonMapper.createArrayNode();
279+
docJsonNode.set("import", imports);
280+
} else {
281+
imports = (ArrayNode)importsNode;
282+
}
283+
boolean found = false;
284+
for (JsonNode exMap : imports) {
285+
if (exMap.isObject()) {
286+
Optional<JsonNode> externalId = exMap.optional("externalSpdxId");
287+
if (externalId.isPresent() && externalId.get().asText().equals(licenseUri)) {
288+
found = true;
289+
break;
290+
}
291+
}
292+
}
293+
if (!found) {
294+
ObjectNode externalMap = jsonMapper.createObjectNode();
295+
externalMap.set("type", new TextNode("ExternalMap"));
296+
externalMap.set("externalSpdxId", new TextNode(licenseUri));
297+
externalMap.set("locationHint", new TextNode(
298+
licenseUri.replace("http://", "https://") + ".jsonld"));
299+
imports.add(externalMap);
300+
}
301+
}
302+
266303
/**
267304
* Serialize on the required portions of the SPDX document
268305
*
@@ -272,7 +309,7 @@ private JsonNode serializeSpdxDocument(SpdxDocument spdxDocument) throws Invalid
272309
* @return a JSON node representation of the spdxDocument
273310
* @throws InvalidSPDXAnalysisException on any SPDX related error
274311
*/
275-
private JsonNode spdxDocumentToJsonNode(SpdxDocument spdxDocument,
312+
private ObjectNode spdxDocumentToJsonNode(SpdxDocument spdxDocument,
276313
String serializedId, Map<String, String> idToSerializedId) throws InvalidSPDXAnalysisException {
277314
ObjectNode retval = jsonMapper.createObjectNode();
278315
retval.set(JsonLDDeserializer.SPDX_ID_PROP, new TextNode(serializedId));
@@ -466,7 +503,7 @@ private JsonNode objectToJsonNode(Object object, IModelStore fromModelStore, Map
466503
} else if (object instanceof Integer) {
467504
return new IntNode((Integer) object);
468505
} else if (object instanceof Double) {
469-
return new DoubleNode((Double)object);
506+
return new TextNode(object.toString());
470507
} else if (object instanceof IndividualUriValue) {
471508
// it's an Enum, Individual or external element
472509
String individualUri = ((IndividualUriValue)object).getIndividualURI();
@@ -546,6 +583,9 @@ private JsonNode inlinedJsonNode(TypedValue tv, IModelStore fromModelStore,
546583
*/
547584
private String typeToJsonType(String type) {
548585
String[] parts = type.split("\\.");
586+
if (parts.length == 1) {
587+
return type;
588+
}
549589
if ("Core".equals(parts[0])) {
550590
return JsonLDSchema.REVERSE_JAVA_WORDS.getOrDefault(parts[1], parts[1]);
551591
} else {

0 commit comments

Comments
 (0)