@@ -31,11 +31,13 @@ namespace CycloneDX.Json
3131 /// </summary>
3232 public static class Validator
3333 {
34+ private static readonly Dictionary < SpecificationVersion , JsonSchema > _bomSchemas = new Dictionary < SpecificationVersion , JsonSchema > ( ) ;
35+
3436 static Validator ( )
3537 {
36- // I think the global schema registry is not thread safe
37- // well, I'm pretty sure, it's the only thing I can think of that would explain the sporadic test failures
38- // might as well just do it once on initialisation
38+ // The global schema registry is not thread safe, and JsonSchema.FromText
39+ // registers schemas internally. Pre-load everything once at initialisation
40+ // to avoid concurrent registration conflicts during parallel test execution.
3941 var assembly = typeof ( Validator ) . GetTypeInfo ( ) . Assembly ;
4042 using ( var spdxStream = assembly . GetManifestResourceStream ( "CycloneDX.Core.Schemas.spdx.schema.json" ) )
4143 using ( var spdxStreamReader = new StreamReader ( spdxStream ) )
@@ -55,6 +57,26 @@ static Validator()
5557 var cryptoDefsSchema = JsonSchema . FromText ( cryptoDefsStreamReader . ReadToEnd ( ) ) ;
5658 SchemaRegistry . Global . Register ( new Uri ( "http://cyclonedx.org/schema/cryptography-defs.schema.json" ) , cryptoDefsSchema ) ;
5759 }
60+
61+ // Pre-load all BOM schemas (v1.2+) so they are never parsed concurrently
62+ var jsonVersions = new [ ]
63+ {
64+ SpecificationVersion . v1_2 ,
65+ SpecificationVersion . v1_3 ,
66+ SpecificationVersion . v1_4 ,
67+ SpecificationVersion . v1_5 ,
68+ SpecificationVersion . v1_6 ,
69+ SpecificationVersion . v1_7 ,
70+ } ;
71+ foreach ( var version in jsonVersions )
72+ {
73+ var versionString = SchemaVersionResourceFilenameString ( version ) ;
74+ using ( var stream = assembly . GetManifestResourceStream ( $ "CycloneDX.Core.Schemas.bom-{ versionString } .schema.json") )
75+ using ( var reader = new StreamReader ( stream ) )
76+ {
77+ _bomSchemas [ version ] = JsonSchema . FromText ( reader . ReadToEnd ( ) ) ;
78+ }
79+ }
5880 }
5981
6082 /// <summary>
@@ -71,14 +93,9 @@ public static async Task<ValidationResult> ValidateAsync(Stream jsonStream, Spec
7193 }
7294
7395 var schemaVersionString = SchemaVersionResourceFilenameString ( specificationVersion ) ;
74- var assembly = typeof ( Validator ) . GetTypeInfo ( ) . Assembly ;
75-
76- using ( var schemaStream = assembly . GetManifestResourceStream ( $ "CycloneDX.Core.Schemas.bom-{ schemaVersionString } .schema.json") )
77- {
78- var jsonSchema = await JsonSchema . FromStream ( schemaStream ) . ConfigureAwait ( false ) ;
79- var jsonDocument = await JsonDocument . ParseAsync ( jsonStream ) . ConfigureAwait ( false ) ;
80- return Validate ( jsonSchema , jsonDocument , schemaVersionString ) ;
81- }
96+ var jsonSchema = _bomSchemas [ specificationVersion ] ;
97+ var jsonDocument = await JsonDocument . ParseAsync ( jsonStream ) . ConfigureAwait ( false ) ;
98+ return Validate ( jsonSchema , jsonDocument , schemaVersionString ) ;
8299 }
83100
84101 /// <summary>
@@ -162,25 +179,19 @@ public static ValidationResult Validate(string jsonString, SpecificationVersion
162179 }
163180
164181 var schemaVersionString = SchemaVersionResourceFilenameString ( specificationVersion ) ;
165- var assembly = typeof ( Validator ) . GetTypeInfo ( ) . Assembly ;
166-
167- using ( var schemaStream = assembly . GetManifestResourceStream ( $ "CycloneDX.Core.Schemas.bom-{ schemaVersionString } .schema.json") )
168- using ( var schemaStreamReader = new StreamReader ( schemaStream ) )
182+ var jsonSchema = _bomSchemas [ specificationVersion ] ;
183+ try
169184 {
170- var jsonSchema = JsonSchema . FromText ( schemaStreamReader . ReadToEnd ( ) ) ;
171- try
172- {
173- var jsonDocument = JsonDocument . Parse ( jsonString ) ;
174- return Validate ( jsonSchema , jsonDocument , schemaVersionString ) ;
175- }
176- catch ( JsonException exc )
185+ var jsonDocument = JsonDocument . Parse ( jsonString ) ;
186+ return Validate ( jsonSchema , jsonDocument , schemaVersionString ) ;
187+ }
188+ catch ( JsonException exc )
189+ {
190+ return new ValidationResult
177191 {
178- return new ValidationResult
179- {
180- Valid = false ,
181- Messages = new List < string > { exc . Message }
182- } ;
183- }
192+ Valid = false ,
193+ Messages = new List < string > { exc . Message }
194+ } ;
184195 }
185196 }
186197
@@ -232,7 +243,7 @@ private static ValidationResult Validate(JsonSchema schema, JsonDocument jsonDoc
232243 continue ;
233244 }
234245
235- if ( detail . HasErrors )
246+ if ( detail . Errors != null )
236247 {
237248 foreach ( var error in detail . Errors )
238249 {
0 commit comments