Skip to content

Commit cc41ba6

Browse files
committed
fix(spdx): adds support for reading ReferenceCategories with hyphens (fixes CycloneDX#267)
Signed-off-by: Wessel Terpstra <[email protected]>
1 parent 1e3886b commit cc41ba6

13 files changed

+2226
-2
lines changed

src/CycloneDX.Spdx/Models/v2_2/ExternalRef.cs

+30-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// Copyright (c) OWASP Foundation. All Rights Reserved.
1717

1818
using System;
19+
using System.Text.Json.Serialization;
1920
using System.Xml.Serialization;
2021

2122
namespace CycloneDX.Spdx.Models.v2_2
@@ -28,8 +29,36 @@ public class ExternalRef
2829
/// <summary>
2930
/// Category for the external reference
3031
/// </summary>
31-
[XmlElement("referenceCategory")]
32+
[XmlIgnore]
3233
public ExternalRefCategory ReferenceCategory { get; set; }
34+
35+
/// <summary>
36+
/// Category for the external reference, adjusted to allow values with hyphens and underscores
37+
/// </summary>
38+
[XmlElement("referenceCategory")]
39+
[JsonIgnore]
40+
public string ReferenceCategoryAsString
41+
{
42+
get => ReferenceCategory.ToString();
43+
set
44+
{
45+
switch (value.ToUpperInvariant())
46+
{
47+
case "OTHER":
48+
ReferenceCategory = ExternalRefCategory.OTHER;
49+
break;
50+
case "SECURITY":
51+
ReferenceCategory = ExternalRefCategory.SECURITY;
52+
break;
53+
case "PACKAGE_MANAGER":
54+
case "PACKAGE-MANAGER":
55+
ReferenceCategory = ExternalRefCategory.PACKAGE_MANAGER;
56+
break;
57+
default:
58+
throw new InvalidOperationException();
59+
}
60+
}
61+
}
3362

3463
/// <summary>
3564
/// The unique string with no spaces necessary to access the package-specific information, metadata, or content within the target location. The format of the locator is subject to constraints defined by the &lt;type&gt;.

src/CycloneDX.Spdx/Schemas/spdx-2.2.schema.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@
317317
"referenceCategory" : {
318318
"description" : "Category for the external reference",
319319
"type" : "string",
320-
"enum" : [ "OTHER", "PERSISTENT_ID", "SECURITY", "PACKAGE_MANAGER" ]
320+
"enum" : [ "OTHER", "PERSISTENT_ID", "SECURITY", "PACKAGE_MANAGER", "PACKAGE-MANAGER", "PERSISTENT-ID" ]
321321
},
322322
"referenceLocator" : {
323323
"description" : "The unique string with no spaces necessary to access the package-specific information, metadata, or content within the target location. The format of the locator is subject to constraints defined by the <type>.",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// This file is part of CycloneDX Library for .NET
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the “License”);
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an “AS IS” BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
// SPDX-License-Identifier: Apache-2.0
16+
// Copyright (c) OWASP Foundation. All Rights Reserved.
17+
18+
using System;
19+
using System.Diagnostics.Contracts;
20+
using System.Text.Json;
21+
using System.Text.Json.Serialization;
22+
23+
namespace CycloneDX.Spdx.Serialization.Converters
24+
{
25+
26+
public class HyphenToUnderscoreEnumConverter<T> : JsonConverter<T> where T: struct
27+
{
28+
public override T Read(
29+
ref Utf8JsonReader reader,
30+
Type typeToConvert,
31+
JsonSerializerOptions options)
32+
{
33+
if (reader.TokenType == JsonTokenType.Null
34+
|| reader.TokenType != JsonTokenType.String)
35+
{
36+
throw new JsonException();
37+
}
38+
39+
var enumString = reader.GetString();
40+
41+
T enumValue;
42+
var success = Enum.TryParse<T>(enumString.Replace("-", "_"), ignoreCase: true, out enumValue);
43+
if (success)
44+
{
45+
return enumValue;
46+
}
47+
else
48+
{
49+
throw new JsonException();
50+
}
51+
}
52+
53+
public override void Write(
54+
Utf8JsonWriter writer,
55+
T value,
56+
JsonSerializerOptions options)
57+
{
58+
Contract.Requires(writer != null);
59+
writer.WriteStringValue(value.ToString());
60+
}
61+
}
62+
}

src/CycloneDX.Spdx/Serialization/JsonSerializer.cs

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
using System.Text.Json;
2222
using System.Text.Json.Serialization;
2323
using System.Threading.Tasks;
24+
using CycloneDX.Spdx.Models.v2_2;
25+
using CycloneDX.Spdx.Serialization.Converters;
2426

2527
namespace CycloneDX.Spdx.Serialization
2628
{
@@ -38,6 +40,7 @@ public static JsonSerializerOptions GetJsonSerializerOptions_v2_2()
3840
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
3941
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
4042
};
43+
options.Converters.Add(new HyphenToUnderscoreEnumConverter<ExternalRefCategory>());
4144
options.Converters.Add(new JsonStringEnumConverter());
4245
return options;
4346
}

tests/CycloneDX.Spdx.Tests/JsonSerializerTests.cs

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public class JsonSerializerTests
2929
{
3030
[Theory]
3131
[InlineData("document")]
32+
[InlineData("document-with-hyphens-in-external-reference-category")]
3233
public void JsonRoundTripTest(string baseFilename)
3334
{
3435
var resourceFilename = Path.Join("Resources", "v2.2", baseFilename + ".json");
@@ -42,6 +43,7 @@ public void JsonRoundTripTest(string baseFilename)
4243

4344
[Theory]
4445
[InlineData("document")]
46+
[InlineData("document-with-hyphens-in-external-reference-category")]
4547
public async Task JsonAsyncRoundTripTest(string baseFilename)
4648
{
4749
var resourceFilename = Path.Join("Resources", "v2.2", baseFilename + ".json");

tests/CycloneDX.Spdx.Tests/JsonValidatorTests.cs

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public class JsonValidatorTests
2929
{
3030
[Theory]
3131
[InlineData("document")]
32+
[InlineData("document-with-hyphens-in-external-reference-category")]
3233
public void ValidateJsonStringTest(string baseFilename)
3334
{
3435
var resourceFilename = Path.Join("Resources", "v2.2", baseFilename + ".json");
@@ -41,6 +42,7 @@ public void ValidateJsonStringTest(string baseFilename)
4142

4243
[Theory]
4344
[InlineData("document")]
45+
[InlineData("document-with-hyphens-in-external-reference-category")]
4446
public async Task ValidateJsonStreamTest(string baseFilename)
4547
{
4648
var resourceFilename = Path.Join("Resources", "v2.2", baseFilename + ".json");

0 commit comments

Comments
 (0)