From 525864ff2c0bc9b8d47b1f4c86ff406127503b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Sz=C3=BCcs?= Date: Fri, 14 Nov 2025 21:36:21 +0100 Subject: [PATCH] refactor(service): make validation methods non-static in VeraPDFService MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Changed `validatePDF` and `validateAllDeclaredStandards` methods from static to instance methods - Updated comments to include explicit null checks for better NPE prevention in warning logic Signed-off-by: Balázs Szücs --- .../software/SPDF/service/VeraPDFService.java | 194 +++++++++--------- 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/app/core/src/main/java/stirling/software/SPDF/service/VeraPDFService.java b/app/core/src/main/java/stirling/software/SPDF/service/VeraPDFService.java index 7ddb146ea..002a91543 100644 --- a/app/core/src/main/java/stirling/software/SPDF/service/VeraPDFService.java +++ b/app/core/src/main/java/stirling/software/SPDF/service/VeraPDFService.java @@ -61,90 +61,37 @@ public class VeraPDFService { } } - public static PDFVerificationResult validatePDF(InputStream pdfStream, String standardString) - throws IOException, ValidationException, ModelParsingException, EncryptedPdfException { - - byte[] pdfBytes = pdfStream.readAllBytes(); - PDFAFlavour validationFlavour = PDFAFlavour.fromString(standardString); - Optional declaredPdfaFlavour = extractDeclaredPdfaFlavour(pdfBytes); - - try (PDFAParser parser = - Foundries.defaultInstance() - .createParser(new ByteArrayInputStream(pdfBytes), validationFlavour)) { - PDFAValidator validator = - Foundries.defaultInstance().createValidator(validationFlavour, false); - ValidationResult result = validator.validate(parser); - - return convertToVerificationResult( - result, declaredPdfaFlavour.orElse(null), validationFlavour); + private static boolean isWarningByMessage(String message) { + // Check for null or blank message - explicit null check is necessary to avoid NPE + if (message == null || message.isBlank()) { + return false; } + + String normalized = message.toLowerCase(Locale.ROOT); + + return normalized.contains("recommended") + || normalized.contains("should") + || normalized.contains("optional") + || normalized.contains("missing recommended"); } - public static List validateAllDeclaredStandards(InputStream pdfStream) - throws IOException, ValidationException, ModelParsingException, EncryptedPdfException { - - byte[] pdfBytes = pdfStream.readAllBytes(); - Optional declaredPdfaFlavour = extractDeclaredPdfaFlavour(pdfBytes); - List results = new ArrayList<>(); - - List detectedFlavours; - try (PDFAParser detectionParser = - Foundries.defaultInstance().createParser(new ByteArrayInputStream(pdfBytes))) { - detectedFlavours = detectionParser.getFlavours(); + private static boolean isWarningByClause(String clause) { + // Check for null or blank clause - explicit null check is necessary to avoid NPE + if (clause == null || clause.isBlank()) { + return false; } - List flavoursToValidate = new ArrayList<>(); + if (clause.startsWith("6.7")) { + return true; + } - declaredPdfaFlavour.ifPresent(flavoursToValidate::add); - - for (PDFAFlavour flavour : detectedFlavours) { - if (PDFFlavours.isFlavourFamily(flavour, PDFAFlavour.SpecificationFamily.PDF_A)) { - if (declaredPdfaFlavour.isPresent() && !declaredPdfaFlavour.get().equals(flavour)) { - flavoursToValidate.add(flavour); - } else if (declaredPdfaFlavour.isEmpty()) { - log.debug( - "Ignoring detected PDF/A flavour {} because no PDF/A declaration exists in XMP", - flavour.getId()); - } - } else if (PDFFlavours.isFlavourFamily(flavour, PDFAFlavour.SpecificationFamily.PDF_UA) - || PDFFlavours.isFlavourFamily( - flavour, PDFAFlavour.SpecificationFamily.WTPDF)) { - flavoursToValidate.add(flavour); + for (String criticalPrefix : CRITICAL_CLAUSE_PREFIXES) { + if (clause.startsWith(criticalPrefix)) { + return false; } } - if (declaredPdfaFlavour.isEmpty()) { - results.add(createNoPdfaDeclarationResult()); - } - - if (flavoursToValidate.isEmpty()) { - log.info("No verifiable PDF/A, PDF/UA, or WTPDF standards declared via XMP metadata"); - return results; - } - - for (PDFAFlavour flavour : flavoursToValidate) { - try (PDFAParser parser = - Foundries.defaultInstance() - .createParser(new ByteArrayInputStream(pdfBytes), flavour)) { - PDFAValidator validator = - Foundries.defaultInstance().createValidator(flavour, false); - ValidationResult result = validator.validate(parser); - PDFAFlavour declaredForResult = - PDFFlavours.isFlavourFamily(flavour, PDFAFlavour.SpecificationFamily.PDF_A) - ? declaredPdfaFlavour.orElse(null) - : flavour; - results.add(convertToVerificationResult(result, declaredForResult, flavour)); - } catch (Exception e) { - log.error("Error validating standard {}: {}", flavour.getId(), e.getMessage()); - results.add( - buildErrorResult( - declaredPdfaFlavour, - flavour, - "Validation error: " + e.getMessage())); - } - } - - return results; + return true; } private static PDFVerificationResult convertToVerificationResult( @@ -264,37 +211,90 @@ public class VeraPDFService { return ruleId != null && WARNING_RULES.contains(ruleId); } - private static boolean isWarningByMessage(String message) { - // isBlank() already handles null and empty strings - if (message == null || message.isBlank()) { - return false; + public PDFVerificationResult validatePDF(InputStream pdfStream, String standardString) + throws IOException, ValidationException, ModelParsingException, EncryptedPdfException { + + byte[] pdfBytes = pdfStream.readAllBytes(); + PDFAFlavour validationFlavour = PDFAFlavour.fromString(standardString); + Optional declaredPdfaFlavour = extractDeclaredPdfaFlavour(pdfBytes); + + try (PDFAParser parser = + Foundries.defaultInstance() + .createParser(new ByteArrayInputStream(pdfBytes), validationFlavour)) { + PDFAValidator validator = + Foundries.defaultInstance().createValidator(validationFlavour, false); + ValidationResult result = validator.validate(parser); + + return convertToVerificationResult( + result, declaredPdfaFlavour.orElse(null), validationFlavour); } - - String normalized = message.toLowerCase(Locale.ROOT); - - return normalized.contains("recommended") - || normalized.contains("should") - || normalized.contains("optional") - || normalized.contains("missing recommended"); } - private static boolean isWarningByClause(String clause) { - // isBlank() already handles null and empty strings - if (clause == null || clause.isBlank()) { - return false; + public List validateAllDeclaredStandards(InputStream pdfStream) + throws IOException, ValidationException, ModelParsingException, EncryptedPdfException { + + byte[] pdfBytes = pdfStream.readAllBytes(); + Optional declaredPdfaFlavour = extractDeclaredPdfaFlavour(pdfBytes); + List results = new ArrayList<>(); + + List detectedFlavours; + try (PDFAParser detectionParser = + Foundries.defaultInstance().createParser(new ByteArrayInputStream(pdfBytes))) { + detectedFlavours = detectionParser.getFlavours(); } - if (clause.startsWith("6.7")) { - return true; - } + List flavoursToValidate = new ArrayList<>(); - for (String criticalPrefix : CRITICAL_CLAUSE_PREFIXES) { - if (clause.startsWith(criticalPrefix)) { - return false; + declaredPdfaFlavour.ifPresent(flavoursToValidate::add); + + for (PDFAFlavour flavour : detectedFlavours) { + if (PDFFlavours.isFlavourFamily(flavour, PDFAFlavour.SpecificationFamily.PDF_A)) { + if (declaredPdfaFlavour.isPresent() && !declaredPdfaFlavour.get().equals(flavour)) { + flavoursToValidate.add(flavour); + } else if (declaredPdfaFlavour.isEmpty()) { + log.debug( + "Ignoring detected PDF/A flavour {} because no PDF/A declaration exists in XMP", + flavour.getId()); + } + } else if (PDFFlavours.isFlavourFamily(flavour, PDFAFlavour.SpecificationFamily.PDF_UA) + || PDFFlavours.isFlavourFamily( + flavour, PDFAFlavour.SpecificationFamily.WTPDF)) { + flavoursToValidate.add(flavour); } } - return true; + if (declaredPdfaFlavour.isEmpty()) { + results.add(createNoPdfaDeclarationResult()); + } + + if (flavoursToValidate.isEmpty()) { + log.info("No verifiable PDF/A, PDF/UA, or WTPDF standards declared via XMP metadata"); + return results; + } + + for (PDFAFlavour flavour : flavoursToValidate) { + try (PDFAParser parser = + Foundries.defaultInstance() + .createParser(new ByteArrayInputStream(pdfBytes), flavour)) { + PDFAValidator validator = + Foundries.defaultInstance().createValidator(flavour, false); + ValidationResult result = validator.validate(parser); + PDFAFlavour declaredForResult = + PDFFlavours.isFlavourFamily(flavour, PDFAFlavour.SpecificationFamily.PDF_A) + ? declaredPdfaFlavour.orElse(null) + : flavour; + results.add(convertToVerificationResult(result, declaredForResult, flavour)); + } catch (Exception e) { + log.error("Error validating standard {}: {}", flavour.getId(), e.getMessage()); + results.add( + buildErrorResult( + declaredPdfaFlavour, + flavour, + "Validation error: " + e.getMessage())); + } + } + + return results; } private static PDFVerificationResult createNoPdfaDeclarationResult() {