From 8e5767f0b647840dd9f158eaf54adb80b6095990 Mon Sep 17 00:00:00 2001 From: nscuro Date: Fri, 14 Aug 2026 14:06:20 +0200 Subject: [PATCH] Fix JSON validation messages not containing instance locations Validation errors are close to useless without knowing WHERE in the input document they occurred. Regression of the `json-schema-validator` update to 2.x. Signed-off-by: nscuro --- .../org/cyclonedx/parsers/JsonParser.java | 11 ++++++++-- .../org/cyclonedx/parsers/JsonParserTest.java | 22 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/cyclonedx/parsers/JsonParser.java b/src/main/java/org/cyclonedx/parsers/JsonParser.java index 352644f4b..41caddb7d 100644 --- a/src/main/java/org/cyclonedx/parsers/JsonParser.java +++ b/src/main/java/org/cyclonedx/parsers/JsonParser.java @@ -187,8 +187,15 @@ public List validate(final JsonNode bomJson, final Version schem } List errors = getJsonSchema(schemaVersion, mapper).validate(mapper.readTree(bomJson.toString())); - for (Error message: errors) { - exceptions.add(new ParseException(message.getMessage())); + for (Error error : errors) { + final boolean hasLocation = + error.getInstanceLocation() != null + && error.getInstanceLocation().getNameCount() > 0; + exceptions.add( + new ParseException( + hasLocation + ? error.getInstanceLocation() + ": " + error.getMessage() + : error.getMessage())); } return exceptions; diff --git a/src/test/java/org/cyclonedx/parsers/JsonParserTest.java b/src/test/java/org/cyclonedx/parsers/JsonParserTest.java index c1cc3cfef..5d2dc7a5e 100644 --- a/src/test/java/org/cyclonedx/parsers/JsonParserTest.java +++ b/src/test/java/org/cyclonedx/parsers/JsonParserTest.java @@ -19,6 +19,7 @@ package org.cyclonedx.parsers; import org.cyclonedx.Version; +import org.cyclonedx.exception.ParseException; import org.cyclonedx.model.Bom; import org.cyclonedx.model.Citation; import org.cyclonedx.model.Component; @@ -99,6 +100,27 @@ public void testValid12Bom() throws Exception { System.out.println(bom.getSerialNumber()); } + @Test + public void testValidationErrorsIncludeInstanceLocation() throws Exception { + final String bomJson = /* language=JSON */ """ + { + "bomFormat": "CycloneDX", + "specVersion": "1.6", + "components": [ + { + "type": "no-such-type", + "name": "acme-lib" + } + ] + } + """; + final List exceptions = + new JsonParser().validate(bomJson, Version.VERSION_16); + assertThat(exceptions) + .isNotEmpty() + .anySatisfy(e -> assertThat(e.getMessage()).startsWith("/components/0/type: ")); + } + @Test public void testValid12BomWithUtf8ByteOrderMarker() throws Exception { final File file = new File(Objects.requireNonNull(this.getClass().getResource("/bom-1.2-utf8bom.json")).getFile());