diff --git a/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java b/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java index d9004668d7..7939fea76e 100644 --- a/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java +++ b/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java @@ -24,9 +24,9 @@ import java.util.UUID; // custom ConfigSource, and java.nio / ClassLoader#getResourceAsStream for resources). import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.PropertySource; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; +import stirling.software.common.model.io.ClassPathResource; +import stirling.software.common.model.io.FileSystemResource; +import stirling.software.common.model.io.Resource; import org.springframework.core.io.support.EncodedResource; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/app/common/src/main/java/stirling/software/common/model/io/ClassPathResource.java b/app/common/src/main/java/stirling/software/common/model/io/ClassPathResource.java new file mode 100644 index 0000000000..3984e2e618 --- /dev/null +++ b/app/common/src/main/java/stirling/software/common/model/io/ClassPathResource.java @@ -0,0 +1,64 @@ +package stirling.software.common.model.io; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +/** Classpath-backed {@link Resource} (migration shim for Spring's {@code ClassPathResource}). */ +public class ClassPathResource implements Resource { + + private final String path; + private final ClassLoader classLoader; + + public ClassPathResource(String path) { + this(path, ClassPathResource.class.getClassLoader()); + } + + public ClassPathResource(String path, ClassLoader classLoader) { + this.path = path.startsWith("/") ? path.substring(1) : path; + this.classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader(); + } + + @Override + public InputStream getInputStream() throws IOException { + InputStream is = classLoader.getResourceAsStream(path); + if (is == null) { + throw new IOException("class path resource [" + path + "] cannot be opened"); + } + return is; + } + + @Override + public boolean exists() { + return classLoader.getResource(path) != null; + } + + @Override + public String getFilename() { + int sep = path.lastIndexOf('/'); + return sep != -1 ? path.substring(sep + 1) : path; + } + + @Override + public long contentLength() throws IOException { + try (InputStream is = getInputStream()) { + long count = 0; + byte[] buf = new byte[8192]; + int read; + while ((read = is.read(buf)) != -1) { + count += read; + } + return count; + } + } + + @Override + public File getFile() throws IOException { + URL url = classLoader.getResource(path); + if (url == null || !"file".equals(url.getProtocol())) { + throw new IOException("class path resource [" + path + "] is not a filesystem file"); + } + return new File(url.getFile()); + } +} diff --git a/app/common/src/main/java/stirling/software/common/model/io/FileSystemResource.java b/app/common/src/main/java/stirling/software/common/model/io/FileSystemResource.java new file mode 100644 index 0000000000..19335d2267 --- /dev/null +++ b/app/common/src/main/java/stirling/software/common/model/io/FileSystemResource.java @@ -0,0 +1,56 @@ +package stirling.software.common.model.io; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; + +/** File-backed {@link Resource} (migration shim for Spring's {@code FileSystemResource}). */ +public class FileSystemResource implements Resource { + + private final Path path; + + public FileSystemResource(Path path) { + this.path = path; + } + + public FileSystemResource(File file) { + this.path = file.toPath(); + } + + public FileSystemResource(String path) { + this.path = Path.of(path); + } + + @Override + public InputStream getInputStream() throws IOException { + return Files.newInputStream(path); + } + + @Override + public boolean exists() { + return Files.exists(path); + } + + @Override + public String getFilename() { + Path name = path.getFileName(); + return name == null ? null : name.toString(); + } + + @Override + public long contentLength() throws IOException { + return Files.size(path); + } + + @Override + public boolean isFile() { + return true; + } + + @Override + public File getFile() { + return path.toFile(); + } +} diff --git a/app/common/src/main/java/stirling/software/common/model/io/InputStreamResource.java b/app/common/src/main/java/stirling/software/common/model/io/InputStreamResource.java new file mode 100644 index 0000000000..da1ab6ceb8 --- /dev/null +++ b/app/common/src/main/java/stirling/software/common/model/io/InputStreamResource.java @@ -0,0 +1,50 @@ +package stirling.software.common.model.io; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +/** + * Stream-backed {@link Resource} (migration shim for Spring's {@code InputStreamResource}). As with + * Spring, the stream can only be read once. + */ +public class InputStreamResource implements Resource { + + private final InputStream inputStream; + private final String filename; + + public InputStreamResource(InputStream inputStream) { + this(inputStream, null); + } + + public InputStreamResource(InputStream inputStream, String filename) { + this.inputStream = inputStream; + this.filename = filename; + } + + @Override + public InputStream getInputStream() { + return inputStream; + } + + @Override + public boolean exists() { + return true; + } + + @Override + public String getFilename() { + return filename; + } + + @Override + public long contentLength() throws IOException { + // Spring's InputStreamResource also cannot report length without consuming the stream. + return -1; + } + + @Override + public File getFile() throws IOException { + throw new IOException("InputStreamResource is not backed by a file"); + } +} diff --git a/app/common/src/main/java/stirling/software/common/model/io/Resource.java b/app/common/src/main/java/stirling/software/common/model/io/Resource.java new file mode 100644 index 0000000000..9394d9c7b8 --- /dev/null +++ b/app/common/src/main/java/stirling/software/common/model/io/Resource.java @@ -0,0 +1,40 @@ +package stirling.software.common.model.io; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +/** + * Migration compatibility shim for Spring's {@code org.springframework.core.io.Resource}. + * + *

Quarkus/Jakarta has no single {@code Resource} abstraction. Rather than rewrite the many + * public method signatures across the codebase that accept or return {@code Resource}, this + * interface mirrors the subset of Spring's API the codebase actually uses + * ({@code getInputStream/exists/getFile/getFilename/contentLength/isFile}) together with the + * {@link FileSystemResource}, {@link InputStreamResource} and {@link ClassPathResource} + * implementations. Converting a file is then just an import swap. + * + *

TODO: Migration required - longer term, prefer {@code java.nio.file.Path} / {@code InputStream} + * directly at the boundaries and retire this shim. + */ +public interface Resource { + + InputStream getInputStream() throws IOException; + + boolean exists(); + + String getFilename(); + + long contentLength() throws IOException; + + /** Whether this resource is backed by a real file in the filesystem. */ + default boolean isFile() { + return false; + } + + /** + * @return the underlying file. + * @throws IOException if the resource is not file-backed. + */ + File getFile() throws IOException; +} diff --git a/app/common/src/main/java/stirling/software/common/service/FileStorage.java b/app/common/src/main/java/stirling/software/common/service/FileStorage.java index d5d96c39d3..93e53a1885 100644 --- a/app/common/src/main/java/stirling/software/common/service/FileStorage.java +++ b/app/common/src/main/java/stirling/software/common/service/FileStorage.java @@ -14,7 +14,7 @@ import jakarta.enterprise.context.ApplicationScoped; // TODO: Migration required - org.springframework.core.io.Resource is used in public method // signatures (storeFile, storeFromResource) and for behavior (isFile()/getFile()/getInputStream()). // No drop-in JAX-RS/Jakarta equivalent; converting would ripple into callers. Keeping the type. -import org.springframework.core.io.Resource; +import stirling.software.common.model.io.Resource; // TODO: Migration required - org.springframework.web.multipart.MultipartFile is used in public // method signatures (storeFile, retrieveFile). No servlet/JAX-RS drop-in for utility method // params; changing it would ripple widely into callers. Keeping the type. diff --git a/app/common/src/main/java/stirling/software/common/service/InternalApiClient.java b/app/common/src/main/java/stirling/software/common/service/InternalApiClient.java index 2902430dae..f6c3acfba1 100644 --- a/app/common/src/main/java/stirling/software/common/service/InternalApiClient.java +++ b/app/common/src/main/java/stirling/software/common/service/InternalApiClient.java @@ -16,8 +16,8 @@ import java.util.regex.Pattern; // non-trivial and would ripple to callers (PipelineProcessor, AiWorkflowService) that pass // MultiValueMap bodies and consume ResponseEntity. These Spring imports are // intentionally retained until that cross-file migration is scheduled. -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; +import stirling.software.common.model.io.FileSystemResource; +import stirling.software.common.model.io.Resource; import org.springframework.http.*; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.util.MultiValueMap; diff --git a/app/common/src/main/java/stirling/software/common/service/JobExecutorService.java b/app/common/src/main/java/stirling/software/common/service/JobExecutorService.java index 52cccfa0d9..4a2e168ee5 100644 --- a/app/common/src/main/java/stirling/software/common/service/JobExecutorService.java +++ b/app/common/src/main/java/stirling/software/common/service/JobExecutorService.java @@ -17,7 +17,7 @@ import java.util.function.Supplier; // because they are consumed via ResponseEntity#getHeaders()/getBody() and built // via ResponseEntity builders. These imports are intentionally retained until the // callers are migrated as a unit. -import org.springframework.core.io.Resource; +import stirling.software.common.model.io.Resource; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; diff --git a/app/common/src/main/java/stirling/software/common/util/GeneralUtils.java b/app/common/src/main/java/stirling/software/common/util/GeneralUtils.java index a8dc3d87e2..39b6d07c31 100644 --- a/app/common/src/main/java/stirling/software/common/util/GeneralUtils.java +++ b/app/common/src/main/java/stirling/software/common/util/GeneralUtils.java @@ -21,7 +21,7 @@ import java.util.regex.Pattern; // resource API. Resource/ResourceLoader/ResourcePatternUtils remain in getResourcesFromLocationPattern // because that method's public signature and the Spring resource-pattern resolver are used by // callers; converting it requires a filesystem/classpath glob rewrite that ripples to callers. -import org.springframework.core.io.Resource; +import stirling.software.common.model.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.ResourcePatternUtils; diff --git a/app/common/src/main/java/stirling/software/common/util/PDFToFile.java b/app/common/src/main/java/stirling/software/common/util/PDFToFile.java index 2226372f59..35cdd176e9 100644 --- a/app/common/src/main/java/stirling/software/common/util/PDFToFile.java +++ b/app/common/src/main/java/stirling/software/common/util/PDFToFile.java @@ -27,7 +27,7 @@ import org.apache.commons.io.IOUtils; // org.springframework.http.MediaType -> jakarta.ws.rs.core.MediaType, // HttpStatus.BAD_REQUEST -> Response.Status.BAD_REQUEST, // MultipartFile -> byte[]/InputStream or a JAX-RS multipart type. -import org.springframework.core.io.Resource; +import stirling.software.common.model.io.Resource; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; diff --git a/app/common/src/main/java/stirling/software/common/util/WebResponseUtils.java b/app/common/src/main/java/stirling/software/common/util/WebResponseUtils.java index c6395a0213..711e737eab 100644 --- a/app/common/src/main/java/stirling/software/common/util/WebResponseUtils.java +++ b/app/common/src/main/java/stirling/software/common/util/WebResponseUtils.java @@ -11,27 +11,12 @@ import java.nio.file.Path; import org.apache.pdfbox.pdmodel.PDDocument; -// TODO: Migration required - org.springframework.core.io.Resource/FileSystemResource have no -// JAX-RS drop-in. The file-backed responses below (pdfFileToWebResponse / zipFileToWebResponse / -// fileToWebResponse and the ManagedTempFileResource inner class) rely on Spring's -// ResourceHttpMessageConverter calling Resource#getInputStream() once and closing it after writing -// the body, which is what triggers TempFile deletion. Under Quarkus/JAX-RS the equivalent is to -// return a StreamingOutput (or InputStream) and delete the TempFile after the stream is fully -// written. The Spring Resource imports are retained until those methods are reworked, because -// removing them would require changing the public ResponseEntity signatures and the -// converter-driven lifecycle they depend on. -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; -import org.springframework.http.ResponseEntity; -// TODO: Migration required - org.springframework.web.multipart.MultipartFile has no servlet/JAX-RS -// drop-in for a utility method parameter. Converting multiPartFileToWebResponse to accept -// byte[]/InputStream would ripple through every caller, so the Spring type and its import are kept -// here intentionally. import stirling.software.common.model.MultipartFile; import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.StreamingOutput; import io.github.pixee.security.Filenames; @@ -91,16 +76,15 @@ public class WebResponseUtils { } /** - * Save a {@link PDDocument} to a managed temp file and return it as a file-backed {@code - * ResponseEntity}. + * Save a {@link PDDocument} to a managed temp file and return it as a streamed web response. * - *

The returned {@link Resource} owns the supplied {@link TempFile} — the file is deleted - * when Spring closes the response {@link InputStream} after writing the body. This is a - * synchronous equivalent of the previous {@code StreamingResponseBody} pattern and avoids the - * async-dispatch hazards (response-committed races, filter incompatibility, silent write - * failures) that {@code StreamingResponseBody} introduced. + *

MIGRATION (Spring -> JAX-RS): previously returned {@code ResponseEntity} backed + * by a {@code ManagedTempFileResource}, relying on Spring's {@code ResourceHttpMessageConverter} + * to call {@code Resource#getInputStream()} and close it after writing (the hook that deleted + * the {@link TempFile}). The JAX-RS equivalent is a {@link StreamingOutput} that copies the file + * to the response and deletes the temp file in a {@code finally} block once writing completes. */ - public static ResponseEntity pdfDocToWebResponse( + public static Response pdfDocToWebResponse( PDDocument document, String docName, TempFileManager tempFileManager) throws IOException { TempFile tempFile = tempFileManager.createManagedTempFile(".pdf"); @@ -113,71 +97,63 @@ public class WebResponseUtils { return pdfFileToWebResponse(tempFile, docName); } - /** - * Convert a {@link TempFile} holding a PDF into a web response. - * - *

The temp file is deleted when Spring closes the response body stream. - * - * @param outputTempFile The temporary file to be sent as a response. - * @param docName The name of the document. - * @return A ResponseEntity whose body streams the file, deleting it on close. - */ - public static ResponseEntity pdfFileToWebResponse( - TempFile outputTempFile, String docName) throws IOException { + /** Convert a {@link TempFile} holding a PDF into a streamed web response (deletes on close). */ + public static Response pdfFileToWebResponse(TempFile outputTempFile, String docName) + throws IOException { return fileToWebResponse(outputTempFile, docName, APPLICATION_PDF); } - /** - * Convert a {@link TempFile} holding a ZIP archive into a web response. - * - *

The temp file is deleted when Spring closes the response body stream. - * - * @param outputTempFile The temporary file to be sent as a response. - * @param docName The name of the document. - * @return A ResponseEntity whose body streams the file, deleting it on close. - */ - public static ResponseEntity zipFileToWebResponse( - TempFile outputTempFile, String docName) throws IOException { + /** Convert a {@link TempFile} holding a ZIP into a streamed web response (deletes on close). */ + public static Response zipFileToWebResponse(TempFile outputTempFile, String docName) + throws IOException { return fileToWebResponse( outputTempFile, docName, MediaType.valueOf(MediaType.APPLICATION_OCTET_STREAM)); } /** - * Convert a {@link TempFile} into a web response with an explicit media type. + * Convert a {@link TempFile} into a streamed web response with an explicit media type. * - *

The returned {@link ResponseEntity} carries a {@link ManagedTempFileResource} as its body. - * Spring's {@code ResourceHttpMessageConverter} calls {@link Resource#getInputStream()} once - * and closes the returned stream after writing — at which point the underlying {@link TempFile} - * is deleted. Everything runs synchronously on the request thread, so write failures propagate - * through normal Spring error handling and are logged, rather than silently truncating the - * response. - * - * @param outputTempFile The temporary file to be sent as a response. - * @param docName The name of the document. - * @param mediaType The content type to set on the response. - * @return A ResponseEntity whose body streams the file, deleting it on close. + *

The body is a {@link StreamingOutput} that copies the temp file to the client and deletes + * the backing {@link TempFile} once the transfer completes (or fails). This replaces the former + * Spring {@code ResponseEntity} + {@code ResourceHttpMessageConverter} lifecycle. + * I/O errors during the copy are logged and propagated. */ - // TODO: Migration required - ResponseEntity + FileSystemResource depend on Spring's - // ResourceHttpMessageConverter to invoke Resource#getInputStream() and close it after writing, - // which is the hook that deletes the backing TempFile. There is no faithful JAX-RS drop-in for - // that lifecycle; rework to return jakarta.ws.rs.core.Response carrying a StreamingOutput that - // deletes the TempFile after writing. Left intact to preserve behaviour and the public - // signature until callers can be migrated together. - public static ResponseEntity fileToWebResponse( + public static Response fileToWebResponse( TempFile outputTempFile, String docName, MediaType mediaType) throws IOException { try { Path path = outputTempFile.getFile().toPath().normalize(); long len = Files.size(path); - org.springframework.http.HttpHeaders headers = - new org.springframework.http.HttpHeaders(); - headers.setContentType( - org.springframework.http.MediaType.parseMediaType(mediaType.toString())); - headers.setContentLength(len); - headers.setContentDispositionFormData("attachment", encodeAttachmentName(docName)); - Resource body = new ManagedTempFileResource(outputTempFile); - return new ResponseEntity<>(body, headers, org.springframework.http.HttpStatus.OK); + StreamingOutput body = + output -> { + try (InputStream in = Files.newInputStream(path)) { + in.transferTo(output); + } catch (IOException e) { + log.error( + "Failed to stream temp response body {} to client", + outputTempFile.getAbsolutePath(), + e); + throw e; + } finally { + try { + outputTempFile.close(); + } catch (Exception closeEx) { + log.warn( + "Failed to clean up temp file {} after streaming response", + outputTempFile.getAbsolutePath(), + closeEx); + } + } + }; + + return Response.ok(body) + .type(mediaType) + .header(HttpHeaders.CONTENT_LENGTH, len) + .header( + "Content-Disposition", + "attachment; filename=\"" + encodeAttachmentName(docName) + "\"") + .build(); } catch (IOException | RuntimeException e) { try { outputTempFile.close(); @@ -195,110 +171,8 @@ public class WebResponseUtils { .replaceAll("%20"); } - /** - * {@link Resource} backed by a {@link TempFile}. The underlying temp file is deleted when the - * response {@code InputStream} is closed — i.e. after Spring has finished writing the body. Any - * {@link IOException} during the copy is logged via {@link ClosingInputStream} and propagates - * through Spring's normal error path. Since response headers are committed before the body - * transfer begins, a mid-body failure manifests as a server-side log entry plus an aborted - * connection rather than a silently-truncated success — which is the behaviour this class was - * added to restore. - * - *

Single-use contract: {@link #getInputStream()} is intended to be called once by - * Spring's {@code ResourceHttpMessageConverter} on the normal write path. After the returned - * stream is closed the backing temp file is deleted, so subsequent {@code getInputStream()} - * calls will either see a deleted file (tests that mock {@link TempFile#close()} are an - * exception) or fail at read time. Callers that need to re-read the body must copy it first. - */ - // TODO: Migration required - extends Spring's FileSystemResource and is consumed by Spring's - // ResourceHttpMessageConverter; no JAX-RS equivalent. Kept intact pending the Response + - // StreamingOutput rework described on fileToWebResponse. - public static final class ManagedTempFileResource extends FileSystemResource { - - private final TempFile tempFile; - - public ManagedTempFileResource(TempFile tempFile) { - super(tempFile.getFile()); - this.tempFile = tempFile; - } - - @Override - public InputStream getInputStream() throws IOException { - InputStream source; - try { - source = super.getInputStream(); - } catch (IOException e) { - // Opening the input stream already failed; make sure we don't leak the temp file. - try { - tempFile.close(); - } catch (Exception closeEx) { - e.addSuppressed(closeEx); - } - throw e; - } - return new ClosingInputStream(source, tempFile); - } - } - - /** - * Stream wrapper that deletes its backing {@link TempFile} on close. Logs — but does not - * swallow — any IOException that happens while reading the body, so upstream handlers can - * surface the failure to the client. - */ - private static final class ClosingInputStream extends FilterInputStream { - - private final TempFile tempFile; - private boolean closed; - - ClosingInputStream(InputStream delegate, TempFile tempFile) { - super(delegate); - this.tempFile = tempFile; - } - - @Override - public int read() throws IOException { - try { - return super.read(); - } catch (IOException e) { - log.error( - "Failed to read temp response body {} while streaming to client", - tempFile.getAbsolutePath(), - e); - throw e; - } - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - try { - return super.read(b, off, len); - } catch (IOException e) { - log.error( - "Failed to read temp response body {} while streaming to client", - tempFile.getAbsolutePath(), - e); - throw e; - } - } - - @Override - public void close() throws IOException { - if (closed) { - return; - } - closed = true; - try { - super.close(); - } finally { - try { - tempFile.close(); - } catch (Exception closeEx) { - log.warn( - "Failed to clean up temp file {} after streaming response", - tempFile.getAbsolutePath(), - closeEx); - } - } - } - } + // REMOVED (Spring -> JAX-RS): ManagedTempFileResource (extended Spring FileSystemResource) and + // ClosingInputStream. Their job - delete the TempFile after the response body is written - is now + // done inline by the StreamingOutput's finally block in fileToWebResponse, which is the idiomatic + // JAX-RS lifecycle and removes the dependency on Spring's ResourceHttpMessageConverter. } diff --git a/app/common/src/main/java/stirling/software/common/util/ZipExtractionUtils.java b/app/common/src/main/java/stirling/software/common/util/ZipExtractionUtils.java index 8aa721ec74..32ec630bda 100644 --- a/app/common/src/main/java/stirling/software/common/util/ZipExtractionUtils.java +++ b/app/common/src/main/java/stirling/software/common/util/ZipExtractionUtils.java @@ -16,8 +16,8 @@ import java.util.zip.ZipInputStream; // (PipelineProcessor, AiWorkflowService). Replacing them with InputStream/java.nio would ripple // across callers that this single-file migration is not permitted to edit. Keeping the Spring core // io abstraction until callers are migrated together. -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; +import stirling.software.common.model.io.FileSystemResource; +import stirling.software.common.model.io.Resource; import io.github.pixee.security.ZipSecurity; diff --git a/app/common/src/main/java/stirling/software/common/util/misc/ColorSpaceConversionStrategy.java b/app/common/src/main/java/stirling/software/common/util/misc/ColorSpaceConversionStrategy.java index ddcdbbf75a..d58a0dacfe 100644 --- a/app/common/src/main/java/stirling/software/common/util/misc/ColorSpaceConversionStrategy.java +++ b/app/common/src/main/java/stirling/software/common/util/misc/ColorSpaceConversionStrategy.java @@ -11,7 +11,7 @@ import java.util.List; // because the abstract superclass ReplaceAndInvertColorStrategy.replace() declares this return // type. Migrating it (e.g. to java.io.InputStream) would change the public API of the parent // class and all sibling strategies/callers, which is out of scope for this single-file migration. -import org.springframework.core.io.InputStreamResource; +import stirling.software.common.model.io.InputStreamResource; // TODO: Migration required - org.springframework.web.multipart.MultipartFile is retained because // the superclass ctor ReplaceAndInvertColorStrategy(MultipartFile, ReplaceAndInvert) requires it. // No JAX-RS drop-in exists for this constructor param without rippling changes to the parent and diff --git a/app/common/src/main/java/stirling/software/common/util/misc/CustomColorReplaceStrategy.java b/app/common/src/main/java/stirling/software/common/util/misc/CustomColorReplaceStrategy.java index f1122a069d..31cd913e09 100644 --- a/app/common/src/main/java/stirling/software/common/util/misc/CustomColorReplaceStrategy.java +++ b/app/common/src/main/java/stirling/software/common/util/misc/CustomColorReplaceStrategy.java @@ -23,7 +23,7 @@ import org.apache.pdfbox.text.TextPosition; // replace() method declared in the parent ReplaceAndInvertColorStrategy (not in scope for // this migration). Changing it here would break the @Override and ripple to all callers, so // the Spring type is retained until the parent and its callers are migrated together. -import org.springframework.core.io.InputStreamResource; +import stirling.software.common.model.io.InputStreamResource; // TODO: Migration required - MultipartFile is the constructor parameter type that must match // the parent ReplaceAndInvertColorStrategy(MultipartFile, ReplaceAndInvert) constructor (not in // scope for this migration). There is no JAX-RS drop-in for this widely used public signature; diff --git a/app/common/src/main/java/stirling/software/common/util/misc/InvertFullColorStrategy.java b/app/common/src/main/java/stirling/software/common/util/misc/InvertFullColorStrategy.java index aa1e17b8a7..03d1be1223 100644 --- a/app/common/src/main/java/stirling/software/common/util/misc/InvertFullColorStrategy.java +++ b/app/common/src/main/java/stirling/software/common/util/misc/InvertFullColorStrategy.java @@ -21,7 +21,7 @@ import org.apache.pdfbox.rendering.PDFRenderer; // drop-in here. The abstract parent ReplaceAndInvertColorStrategy.replace() returns // InputStreamResource and editing that signature would ripple to all subclasses and callers; per // task rules, only this file may change, so the type is kept until the parent is migrated. -import org.springframework.core.io.InputStreamResource; +import stirling.software.common.model.io.InputStreamResource; // TODO: Migration required - org.springframework.web.multipart.MultipartFile has no JAX-RS drop-in // for these constructor params. The parent class ReplaceAndInvertColorStrategy declares the same // MultipartFile constructor parameter; changing the public signature here would diverge from the diff --git a/app/common/src/main/java/stirling/software/common/util/misc/ReplaceAndInvertColorStrategy.java b/app/common/src/main/java/stirling/software/common/util/misc/ReplaceAndInvertColorStrategy.java index 865ddb3d4e..feeb8831a5 100644 --- a/app/common/src/main/java/stirling/software/common/util/misc/ReplaceAndInvertColorStrategy.java +++ b/app/common/src/main/java/stirling/software/common/util/misc/ReplaceAndInvertColorStrategy.java @@ -6,7 +6,7 @@ import java.io.IOException; // type of the public abstract replace() method, implemented by subclasses and consumed by // callers. Replacing it (e.g. with InputStream/StreamingOutput) would ripple across the // strategy subclasses and their callers, so it is kept until they are migrated together. -import org.springframework.core.io.InputStreamResource; +import stirling.software.common.model.io.InputStreamResource; // TODO: Migration required - org.springframework.web.multipart.MultipartFile is required by // the inherited PDFFile.setFileInput(MultipartFile) (PDFFile keeps this type for the same // reason); changing this constructor parameter would ripple to callers and the API binding