diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 00000000..108b134f --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2026-07-02 - String.format in loops +**Learning:** `String.format` is slow for hex conversion inside loops. +**Action:** Replace it with `HexFormat.of().formatHex(bytes)` which is significantly faster and doesn't do intermediate string creations. diff --git a/src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java b/src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java index 454b0448..33e5fe4e 100644 --- a/src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java +++ b/src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java @@ -38,6 +38,8 @@ @Service public class ArtifactLinkService { + private static final java.util.HexFormat HEX_FORMAT = java.util.HexFormat.of(); + /** * Query parameter used by PDF.js-compatible artifact URLs. */ @@ -423,11 +425,7 @@ private static String sha256Hex(byte[] bytes) { try { MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] raw = digest.digest(bytes); - StringBuilder hex = new StringBuilder(raw.length * 2); - for (byte b : raw) { - hex.append(String.format("%02x", b)); - } - return hex.toString(); + return HEX_FORMAT.formatHex(raw); } catch (GeneralSecurityException ex) { throw new IllegalStateException("SHA-256 digest unavailable", ex); } diff --git a/src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java b/src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java index b8787f35..7ef568b5 100644 --- a/src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java +++ b/src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java @@ -26,6 +26,8 @@ @Service public class DefaultDocumentConversionService implements DocumentConversionService { + private static final java.util.HexFormat HEX_FORMAT = java.util.HexFormat.of(); + private final ConversionJobRepository repository; private final ConversionJobStateStore stateStore; private final DocumentValidationService validationService; @@ -160,12 +162,7 @@ private String contentHash(MultipartFile file) { } byte[] raw = digest.digest(); - StringBuilder hex = new StringBuilder(raw.length * 2); - for (byte b : raw) { - hex.append(String.format("%02x", b)); - } - - return hex.toString(); + return HEX_FORMAT.formatHex(raw); } catch (NoSuchAlgorithmException ex) { throw new IllegalStateException("SHA-256 digest unavailable", ex); } catch (IOException ex) {