Improve Type-Safe Casting with Pattern Matching (#2990)

# Description of Changes

Please provide a summary of the changes, including:

This PR refactors multiple instances of type casting throughout the
codebase by replacing them with Java's pattern matching for
`instanceof`. This approach eliminates redundant type casting, improves
code readability, and reduces the chances of `ClassCastException`. The
changes primarily affect authentication handling, PDF processing, and
certificate validation.

### Key Changes:
- Replaced traditional `instanceof` checks followed by explicit casting
with pattern matching.
- Improved readability and maintainability of type-related operations.
- Applied changes across security modules, PDF utilities, and image
processing functions.

This refactor does not introduce new functionality but enhances the
robustness and clarity of the existing code.

pending until #2818 is published

---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing)
for more details.
This commit is contained in:
Ludy
2025-02-25 22:31:50 +01:00
committed by GitHub
parent a1f7bb3e4a
commit 2ab951e080
27 changed files with 175 additions and 165 deletions

View File

@@ -297,14 +297,14 @@ public class UserController {
for (Object principal : principals) {
List<SessionInformation> sessionsInformation =
sessionRegistry.getAllSessions(principal, false);
if (principal instanceof UserDetails) {
userNameP = ((UserDetails) principal).getUsername();
} else if (principal instanceof OAuth2User) {
userNameP = ((OAuth2User) principal).getName();
} else if (principal instanceof CustomSaml2AuthenticatedPrincipal) {
userNameP = ((CustomSaml2AuthenticatedPrincipal) principal).name();
} else if (principal instanceof String) {
userNameP = (String) principal;
if (principal instanceof UserDetails detailsUser) {
userNameP = detailsUser.getUsername();
} else if (principal instanceof OAuth2User oAuth2User) {
userNameP = oAuth2User.getName();
} else if (principal instanceof CustomSaml2AuthenticatedPrincipal saml2User) {
userNameP = saml2User.name();
} else if (principal instanceof String stringUser) {
userNameP = stringUser;
}
if (userNameP.equalsIgnoreCase(username)) {
for (SessionInformation sessionInfo : sessionsInformation) {

View File

@@ -61,8 +61,8 @@ public class AutoSplitPdfController {
private static String decodeQRCode(BufferedImage bufferedImage) {
LuminanceSource source;
if (bufferedImage.getRaster().getDataBuffer() instanceof DataBufferByte) {
byte[] pixels = ((DataBufferByte) bufferedImage.getRaster().getDataBuffer()).getData();
if (bufferedImage.getRaster().getDataBuffer() instanceof DataBufferByte dataBufferByte) {
byte[] pixels = dataBufferByte.getData();
source =
new PlanarYUVLuminanceSource(
pixels,
@@ -73,8 +73,9 @@ public class AutoSplitPdfController {
bufferedImage.getWidth(),
bufferedImage.getHeight(),
false);
} else if (bufferedImage.getRaster().getDataBuffer() instanceof DataBufferInt) {
int[] pixels = ((DataBufferInt) bufferedImage.getRaster().getDataBuffer()).getData();
} else if (bufferedImage.getRaster().getDataBuffer()
instanceof DataBufferInt dataBufferInt) {
int[] pixels = dataBufferInt.getData();
byte[] newPixels = new byte[pixels.length];
for (int i = 0; i < pixels.length; i++) {
newPixels[i] = (byte) (pixels[i] & 0xff);
@@ -91,7 +92,8 @@ public class AutoSplitPdfController {
false);
} else {
throw new IllegalArgumentException(
"BufferedImage must have 8-bit gray scale, 24-bit RGB, 32-bit ARGB (packed int), byte gray, or 3-byte/4-byte RGB image data");
"BufferedImage must have 8-bit gray scale, 24-bit RGB, 32-bit ARGB (packed"
+ " int), byte gray, or 3-byte/4-byte RGB image data");
}
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
@@ -108,7 +110,10 @@ public class AutoSplitPdfController {
@Operation(
summary = "Auto split PDF pages into separate documents",
description =
"This endpoint accepts a PDF file, scans each page for a specific QR code, and splits the document at the QR code boundaries. The output is a zip file containing each separate PDF document. Input:PDF Output:ZIP-PDF Type:SISO")
"This endpoint accepts a PDF file, scans each page for a specific QR code, and"
+ " splits the document at the QR code boundaries. The output is a zip file"
+ " containing each separate PDF document. Input:PDF Output:ZIP-PDF"
+ " Type:SISO")
public ResponseEntity<byte[]> autoSplitPdf(@ModelAttribute AutoSplitPdfRequest request)
throws IOException {
MultipartFile file = request.getFileInput();

View File

@@ -63,8 +63,7 @@ public class CompressController {
if (res != null && res.getXObjectNames() != null) {
for (COSName name : res.getXObjectNames()) {
PDXObject xobj = res.getXObject(name);
if (xobj instanceof PDImageXObject) {
PDImageXObject image = (PDImageXObject) xobj;
if (xobj instanceof PDImageXObject image) {
BufferedImage bufferedImage = image.getImage();
int newWidth = (int) (bufferedImage.getWidth() * scaleFactor);
@@ -119,7 +118,8 @@ public class CompressController {
@Operation(
summary = "Optimize PDF file",
description =
"This endpoint accepts a PDF file and optimizes it based on the provided parameters. Input:PDF Output:PDF Type:SISO")
"This endpoint accepts a PDF file and optimizes it based on the provided"
+ " parameters. Input:PDF Output:PDF Type:SISO")
public ResponseEntity<byte[]> optimizePdf(@ModelAttribute OptimizePdfRequest request)
throws Exception {
MultipartFile inputFile = request.getFileInput();
@@ -221,7 +221,8 @@ public class CompressController {
// Check if optimized file is larger than the original
if (pdfBytes.length > inputFileSize) {
log.warn(
"Optimized file is larger than the original. Returning the original file instead.");
"Optimized file is larger than the original. Returning the original file"
+ " instead.");
finalFile = tempInputFile;
}

View File

@@ -118,9 +118,8 @@ public class PipelineProcessor {
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("fileInput", file);
for (Entry<String, Object> entry : parameters.entrySet()) {
if (entry.getValue() instanceof List) {
List<?> list = (List<?>) entry.getValue();
for (Object item : list) {
if (entry.getValue() instanceof List<?> entryList) {
for (Object item : entryList) {
body.add(entry.getKey(), item);
}
} else {
@@ -139,7 +138,7 @@ public class PipelineProcessor {
log.info("Skipping file due to filtering {}", operation);
continue;
}
if (!response.getStatusCode().equals(HttpStatus.OK)) {
if (!HttpStatus.OK.equals(response.getStatusCode())) {
logPrintStream.println("Error: " + response.getBody());
hasErrors = true;
continue;
@@ -180,9 +179,8 @@ public class PipelineProcessor {
body.add("fileInput", file);
}
for (Entry<String, Object> entry : parameters.entrySet()) {
if (entry.getValue() instanceof List) {
List<?> list = (List<?>) entry.getValue();
for (Object item : list) {
if (entry.getValue() instanceof List<?> entryList) {
for (Object item : entryList) {
body.add(entry.getKey(), item);
}
} else {
@@ -191,7 +189,7 @@ public class PipelineProcessor {
}
ResponseEntity<byte[]> response = sendWebRequest(url, body);
// Handle the response
if (response.getStatusCode().equals(HttpStatus.OK)) {
if (HttpStatus.OK.equals(response.getStatusCode())) {
processOutputFiles(operation, response, newOutputFiles);
} else {
// Log error if the response status is not OK

View File

@@ -129,9 +129,9 @@ public class CertSignController {
@Operation(
summary = "Sign PDF with a Digital Certificate",
description =
"This endpoint accepts a PDF file, a digital certificate and related information to sign"
+ " the PDF. It then returns the digitally signed PDF file. Input:PDF Output:PDF"
+ " Type:SISO")
"This endpoint accepts a PDF file, a digital certificate and related"
+ " information to sign the PDF. It then returns the digitally signed PDF"
+ " file. Input:PDF Output:PDF Type:SISO")
public ResponseEntity<byte[]> signPDFWithCert(@ModelAttribute SignPDFWithCertRequest request)
throws Exception {
MultipartFile pdf = request.getFileInput();
@@ -201,17 +201,14 @@ public class CertSignController {
Object pemObject = pemParser.readObject();
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
PrivateKeyInfo pkInfo;
if (pemObject instanceof PKCS8EncryptedPrivateKeyInfo) {
if (pemObject instanceof PKCS8EncryptedPrivateKeyInfo pkcs8EncryptedPrivateKeyInfo) {
InputDecryptorProvider decProv =
new JceOpenSSLPKCS8DecryptorProviderBuilder().build(password.toCharArray());
pkInfo = ((PKCS8EncryptedPrivateKeyInfo) pemObject).decryptPrivateKeyInfo(decProv);
} else if (pemObject instanceof PEMEncryptedKeyPair) {
pkInfo = pkcs8EncryptedPrivateKeyInfo.decryptPrivateKeyInfo(decProv);
} else if (pemObject instanceof PEMEncryptedKeyPair pemEncryptedKeyPair) {
PEMDecryptorProvider decProv =
new JcePEMDecryptorProviderBuilder().build(password.toCharArray());
pkInfo =
((PEMEncryptedKeyPair) pemObject)
.decryptKeyPair(decProv)
.getPrivateKeyInfo();
pkInfo = pemEncryptedKeyPair.decryptKeyPair(decProv).getPrivateKeyInfo();
} else {
pkInfo = ((PEMKeyPair) pemObject).getPrivateKeyInfo();
}

View File

@@ -214,10 +214,7 @@ public class GetInfoOnPDF {
ArrayNode attachmentsArray = objectMapper.createArrayNode();
for (PDPage page : pdfBoxDoc.getPages()) {
for (PDAnnotation annotation : page.getAnnotations()) {
if (annotation instanceof PDAnnotationFileAttachment) {
PDAnnotationFileAttachment fileAttachmentAnnotation =
(PDAnnotationFileAttachment) annotation;
if (annotation instanceof PDAnnotationFileAttachment fileAttachmentAnnotation) {
ObjectNode attachmentNode = objectMapper.createObjectNode();
attachmentNode.put("Name", fileAttachmentAnnotation.getAttachmentName());
attachmentNode.put("Description", fileAttachmentAnnotation.getContents());
@@ -437,9 +434,7 @@ public class GetInfoOnPDF {
for (COSName name : resources.getXObjectNames()) {
PDXObject xObject = resources.getXObject(name);
if (xObject instanceof PDImageXObject) {
PDImageXObject image = (PDImageXObject) xObject;
if (xObject instanceof PDImageXObject image) {
ObjectNode imageNode = objectMapper.createObjectNode();
imageNode.put("Width", image.getWidth());
imageNode.put("Height", image.getHeight());
@@ -462,10 +457,8 @@ public class GetInfoOnPDF {
Set<String> uniqueURIs = new HashSet<>(); // To store unique URIs
for (PDAnnotation annotation : annotations) {
if (annotation instanceof PDAnnotationLink) {
PDAnnotationLink linkAnnotation = (PDAnnotationLink) annotation;
if (linkAnnotation.getAction() instanceof PDActionURI) {
PDActionURI uriAction = (PDActionURI) linkAnnotation.getAction();
if (annotation instanceof PDAnnotationLink linkAnnotation) {
if (linkAnnotation.getAction() instanceof PDActionURI uriAction) {
String uri = uriAction.getURI();
uniqueURIs.add(uri); // Add to set to ensure uniqueness
}
@@ -541,8 +534,7 @@ public class GetInfoOnPDF {
Iterable<COSName> colorSpaceNames = resources.getColorSpaceNames();
for (COSName name : colorSpaceNames) {
PDColorSpace colorSpace = resources.getColorSpace(name);
if (colorSpace instanceof PDICCBased) {
PDICCBased iccBased = (PDICCBased) colorSpace;
if (colorSpace instanceof PDICCBased iccBased) {
PDStream iccData = iccBased.getPDStream();
byte[] iccBytes = iccData.toByteArray();
@@ -698,12 +690,10 @@ public class GetInfoOnPDF {
ArrayNode elementsArray = objectMapper.createArrayNode();
if (nodes != null) {
for (Object obj : nodes) {
if (obj instanceof PDStructureNode) {
PDStructureNode node = (PDStructureNode) obj;
if (obj instanceof PDStructureNode node) {
ObjectNode elementNode = objectMapper.createObjectNode();
if (node instanceof PDStructureElement) {
PDStructureElement structureElement = (PDStructureElement) node;
if (node instanceof PDStructureElement structureElement) {
elementNode.put("Type", structureElement.getStructureType());
elementNode.put("Content", getContent(structureElement));
@@ -724,8 +714,7 @@ public class GetInfoOnPDF {
StringBuilder contentBuilder = new StringBuilder();
for (Object item : structureElement.getKids()) {
if (item instanceof COSString) {
COSString cosString = (COSString) item;
if (item instanceof COSString cosString) {
contentBuilder.append(cosString.getString());
} else if (item instanceof PDStructureElement) {
// For simplicity, we're handling only COSString and PDStructureElement here

View File

@@ -44,7 +44,8 @@ public class SanitizeController {
@Operation(
summary = "Sanitize a PDF file",
description =
"This endpoint processes a PDF file and removes specific elements based on the provided options. Input:PDF Output:PDF Type:SISO")
"This endpoint processes a PDF file and removes specific elements based on the"
+ " provided options. Input:PDF Output:PDF Type:SISO")
public ResponseEntity<byte[]> sanitizePDF(@ModelAttribute SanitizePdfRequest request)
throws IOException {
MultipartFile inputFile = request.getFileInput();
@@ -103,8 +104,7 @@ public class SanitizeController {
for (PDPage page : document.getPages()) {
for (PDAnnotation annotation : page.getAnnotations()) {
if (annotation instanceof PDAnnotationWidget) {
PDAnnotationWidget widget = (PDAnnotationWidget) annotation;
if (annotation instanceof PDAnnotationWidget widget) {
PDAction action = widget.getAction();
if (action instanceof PDActionJavaScript) {
widget.setAction(null);
@@ -157,12 +157,12 @@ public class SanitizeController {
private void sanitizeLinks(PDDocument document) throws IOException {
for (PDPage page : document.getPages()) {
for (PDAnnotation annotation : page.getAnnotations()) {
if (annotation != null && annotation instanceof PDAnnotationLink) {
PDAction action = ((PDAnnotationLink) annotation).getAction();
if (annotation != null && annotation instanceof PDAnnotationLink linkAnnotation) {
PDAction action = linkAnnotation.getAction();
if (action != null
&& (action instanceof PDActionLaunch
|| action instanceof PDActionURI)) {
((PDAnnotationLink) annotation).setAction(null);
linkAnnotation.setAction(null);
}
}
}