You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2023/06/11 15:14:27 UTC

[commons-fileupload] 02/02: Use a file item builder

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-fileupload.git

commit 16f56322539eebcccf16e19faac7cd756b5a7f4b
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Jun 11 11:14:21 2023 -0400

    Use a file item builder
---
 .../commons/fileupload2/AbstractFileUpload.java    |  11 +-
 .../commons/fileupload2/FileItemFactory.java       | 122 +++++++++++++++++++--
 .../commons/fileupload2/FileItemIteratorImpl.java  |  10 +-
 .../apache/commons/fileupload2/FileItemStream.java |  10 +-
 .../commons/fileupload2/disk/DiskFileItem.java     |  98 +++++------------
 .../fileupload2/disk/DiskFileItemFactory.java      |  29 +----
 .../disk/DiskFileItemSerializeTest.java            |  14 ++-
 7 files changed, 179 insertions(+), 115 deletions(-)

diff --git a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/AbstractFileUpload.java b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/AbstractFileUpload.java
index 9909d3f..bd5f566 100644
--- a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/AbstractFileUpload.java
+++ b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/AbstractFileUpload.java
@@ -420,8 +420,15 @@ public abstract class AbstractFileUpload {
                 final FileItemStream fileItemStream = iter.next();
                 // Don't use getName() here to prevent an InvalidFileNameException.
                 final String fileName = fileItemStream.getName();
-                final FileItem fileItem = fileItemFactory.createFileItem(fileItemStream.getFieldName(), fileItemStream.getContentType(),
-                        fileItemStream.isFormField(), fileName, fileItemStream.getHeaders());
+                // @formatter:off
+                final FileItem fileItem = fileItemFactory.fileItemBuilder()
+                    .setFieldName(fileItemStream.getFieldName())
+                    .setContentType(fileItemStream.getContentType())
+                    .setFormField(fileItemStream.isFormField())
+                    .setFileName(fileName)
+                    .setFileItemHeaders(fileItemStream.getHeaders())
+                    .get();
+                // @formatter:on
                 itemList.add(fileItem);
                 try (InputStream inputStream = fileItemStream.getInputStream();
                         OutputStream outputStream = fileItem.getOutputStream()) {
diff --git a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/FileItemFactory.java b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/FileItemFactory.java
index 43d8775..ebb130d 100644
--- a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/FileItemFactory.java
+++ b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/FileItemFactory.java
@@ -16,6 +16,12 @@
  */
 package org.apache.commons.fileupload2;
 
+import org.apache.commons.fileupload2.disk.DiskFileItem;
+import org.apache.commons.fileupload2.disk.DiskFileItemFactory;
+import org.apache.commons.io.FileCleaningTracker;
+import org.apache.commons.io.build.AbstractStreamBuilder;
+import org.apache.commons.io.file.PathUtils;
+
 /**
  * Creates {@link FileItem} instances.
  * <p>
@@ -25,15 +31,115 @@ package org.apache.commons.fileupload2;
 public interface FileItemFactory {
 
     /**
-     * Creates a new {@link FileItem} instance from the supplied parameters and any local factory configuration.
+     * Builds a new {@link DiskFileItem} instance.
+     * <p>
+     * For example:
+     * </p>
+     *
+     * <pre>{@code
+     * DiskFileItem diskFileItem = DiskFileItem.builder().get();
+     * }
+     * </pre>
      *
-     * @param fieldName       The name of the form field.
-     * @param contentType     The content type of the form field.
-     * @param isFormField     {@code true} if this is a plain form field; {@code false} otherwise.
-     * @param fileName        The name of the uploaded file, if any, as supplied by the browser or other client.
-     * @param fileItemHeaders The file item headers.
-     * @return The newly created file item.
+     * @param <T> the type of instances to build.
+     * @param <B> the type of builder subclass.
      */
-    FileItem createFileItem(String fieldName, String contentType, boolean isFormField, String fileName, FileItemHeaders fileItemHeaders);
+    abstract class FileItemBuilder<T extends FileItem, B extends FileItemBuilder<T, B>> extends AbstractStreamBuilder<T, B> {
+
+        /**
+         * Field name.
+         */
+        private String fieldName;
+
+        /**
+         * Content type.
+         */
+        private String contentType;
+
+        /**
+         * Is this a form field.
+         */
+        private boolean isFormField;
+
+        /**
+         * File name.
+         */
+        private String fileName;
+
+        /**
+         * File item headers.
+         */
+        private FileItemHeaders fileItemHeaders;
+
+        /**
+         * The instance of {@link FileCleaningTracker}, which is responsible for deleting temporary files.
+         * <p>
+         * May be null, if tracking files is not required.
+         * </p>
+         */
+        private FileCleaningTracker fileCleaningTracker;
+
+        public FileItemBuilder() {
+            setBufferSize(DiskFileItemFactory.DEFAULT_THRESHOLD);
+            setPath(PathUtils.getTempDirectory());
+        }
+
+        public String getContentType() {
+            return contentType;
+        }
+
+        public String getFieldName() {
+            return fieldName;
+        }
+
+        public FileCleaningTracker getFileCleaningTracker() {
+            return fileCleaningTracker;
+        }
+
+        public FileItemHeaders getFileItemHeaders() {
+            return fileItemHeaders;
+        }
+
+        public String getFileName() {
+            return fileName;
+        }
+
+        public boolean isFormField() {
+            return isFormField;
+        }
+
+        public B setContentType(final String contentType) {
+            this.contentType = contentType;
+            return asThis();
+        }
+
+        public B setFieldName(final String fieldName) {
+            this.fieldName = fieldName;
+            return asThis();
+        }
+
+        public B setFileCleaningTracker(final FileCleaningTracker fileCleaningTracker) {
+            this.fileCleaningTracker = fileCleaningTracker;
+            return asThis();
+        }
+
+        public B setFileItemHeaders(final FileItemHeaders fileItemHeaders) {
+            this.fileItemHeaders = fileItemHeaders;
+            return asThis();
+        }
+
+        public B setFileName(final String fileName) {
+            this.fileName = fileName;
+            return asThis();
+        }
+
+        public B setFormField(final boolean isFormField) {
+            this.isFormField = isFormField;
+            return asThis();
+        }
+
+    }
+
+    <T extends FileItem, B extends FileItemBuilder<T, B>> FileItemBuilder<T, B> fileItemBuilder();
 
 }
diff --git a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/FileItemIteratorImpl.java b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/FileItemIteratorImpl.java
index 25d987e..503c56d 100644
--- a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/FileItemIteratorImpl.java
+++ b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/FileItemIteratorImpl.java
@@ -196,7 +196,15 @@ class FileItemIteratorImpl implements FileItemIterator {
         final List<FileItem> items = new ArrayList<>();
         while (hasNext()) {
             final FileItemStream fis = next();
-            items.add(fileUploadBase.getFileItemFactory().createFileItem(fis.getFieldName(), fis.getContentType(), fis.isFormField(), fis.getName(), null));
+            // @formatter:off
+            final FileItem fileItem = fileUploadBase.getFileItemFactory().fileItemBuilder()
+                    .setFieldName(fis.getFieldName())
+                    .setContentType(fis.getContentType())
+                    .setFormField(fis.isFormField())
+                    .setFileName(fis.getName())
+                    .get();
+            // @formatter:on
+            items.add(fileItem);
         }
         return items;
     }
diff --git a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/FileItemStream.java b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/FileItemStream.java
index 9f460a9..62b3442 100644
--- a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/FileItemStream.java
+++ b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/FileItemStream.java
@@ -41,6 +41,11 @@ public interface FileItemStream extends FileItemHeadersSupport {
      */
     class ItemSkippedException extends FileUploadException {
 
+        /**
+         * The exceptions serial version UID, which is being used when serializing an exception instance.
+         */
+        private static final long serialVersionUID = 2;
+
         /**
          * Constructs an instance with a given detail message.
          *
@@ -50,11 +55,6 @@ public interface FileItemStream extends FileItemHeadersSupport {
             super(message);
         }
 
-        /**
-         * The exceptions serial version UID, which is being used when serializing an exception instance.
-         */
-        private static final long serialVersionUID = 2;
-
     }
 
     /**
diff --git a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/disk/DiskFileItem.java b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/disk/DiskFileItem.java
index 4443541..6600877 100644
--- a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/disk/DiskFileItem.java
+++ b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/disk/DiskFileItem.java
@@ -36,12 +36,13 @@ import java.util.UUID;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.commons.fileupload2.FileItem;
+import org.apache.commons.fileupload2.FileItemFactory.FileItemBuilder;
 import org.apache.commons.fileupload2.FileItemHeaders;
 import org.apache.commons.fileupload2.FileUploadException;
 import org.apache.commons.fileupload2.ParameterParser;
 import org.apache.commons.io.Charsets;
+import org.apache.commons.io.FileCleaningTracker;
 import org.apache.commons.io.build.AbstractOrigin;
-import org.apache.commons.io.build.AbstractStreamBuilder;
 import org.apache.commons.io.file.PathUtils;
 import org.apache.commons.io.function.Uncheck;
 import org.apache.commons.io.output.DeferredFileOutputStream;
@@ -73,37 +74,11 @@ public final class DiskFileItem implements FileItem {
      * </p>
      *
      * <pre>{@code
-     * DiskFileItem diskFileItem = DiskFileItem.builder()
-     *    .get();
+     * DiskFileItem diskFileItem = DiskFileItem.builder().get();
      * }
      * </pre>
      */
-    public static class Builder extends AbstractStreamBuilder<DiskFileItem, Builder> {
-
-        /**
-         * Field name.
-         */
-        private String fieldName;
-
-        /**
-         * Content type.
-         */
-        private String contentType;
-
-        /**
-         * Is this a form field.
-         */
-        private boolean isFormField;
-
-        /**
-         * File name.
-         */
-        private String fileName;
-
-        /**
-         * File item headers.
-         */
-        private FileItemHeaders fileItemHeaders;
+    public static class Builder extends FileItemBuilder<DiskFileItem, Builder> {
 
         public Builder() {
             setBufferSize(DiskFileItemFactory.DEFAULT_THRESHOLD);
@@ -128,32 +103,13 @@ public final class DiskFileItem implements FileItem {
          */
         @Override
         public DiskFileItem get() {
-            return new DiskFileItem(fieldName, contentType, isFormField, fileName, getBufferSize(), getPath(), fileItemHeaders, getCharset());
-        }
-
-        public Builder setContentType(final String contentType) {
-            this.contentType = contentType;
-            return this;
-        }
-
-        public Builder setFieldName(final String fieldName) {
-            this.fieldName = fieldName;
-            return this;
-        }
-
-        public Builder setFileItemHeaders(final FileItemHeaders fileItemHeaders) {
-            this.fileItemHeaders = fileItemHeaders;
-            return this;
-        }
-
-        public Builder setFileName(final String fileName) {
-            this.fileName = fileName;
-            return this;
-        }
-
-        public Builder setFormField(final boolean isFormField) {
-            this.isFormField = isFormField;
-            return this;
+            final DiskFileItem diskFileItem = new DiskFileItem(getFieldName(), getContentType(), isFormField(), getFileName(), getBufferSize(), getPath(),
+                    getFileItemHeaders(), getCharset());
+            final FileCleaningTracker tracker = getFileCleaningTracker();
+            if (tracker != null) {
+                tracker.track(diskFileItem.getTempFile().toFile(), diskFileItem);
+            }
+            return diskFileItem;
         }
 
     }
@@ -297,14 +253,14 @@ public final class DiskFileItem implements FileItem {
     /**
      * Constructs a new {@code DiskFileItem} instance.
      *
-     * @param fieldName   The name of the form field.
-     * @param contentType The content type passed by the browser or {@code null} if not specified.
-     * @param isFormField Whether or not this item is a plain form field, as opposed to a file upload.
-     * @param fileName    The original file name in the user's file system, or {@code null} if not specified.
-     * @param threshold   The threshold, in bytes, below which items will be retained in memory and above which they will be stored as a file.
-     * @param repository  The data repository, which is the directory in which files will be created, should the item size exceed the threshold.
+     * @param fieldName       The name of the form field.
+     * @param contentType     The content type passed by the browser or {@code null} if not specified.
+     * @param isFormField     Whether or not this item is a plain form field, as opposed to a file upload.
+     * @param fileName        The original file name in the user's file system, or {@code null} if not specified.
+     * @param threshold       The threshold, in bytes, below which items will be retained in memory and above which they will be stored as a file.
+     * @param repository      The data repository, which is the directory in which files will be created, should the item size exceed the threshold.
      * @param fileItemHeaders The file item headers.
-     * @param defaultCharset The default Charset.
+     * @param defaultCharset  The default Charset.
      */
     private DiskFileItem(final String fieldName, final String contentType, final boolean isFormField, final String fileName, final int threshold,
             final Path repository, final FileItemHeaders fileItemHeaders, final Charset defaultCharset) {
@@ -369,22 +325,22 @@ public final class DiskFileItem implements FileItem {
     }
 
     /**
-     * Gets the content type passed by the agent or {@code null} if not defined.
+     * Gets the default charset for use when no explicit charset parameter is provided by the sender.
      *
-     * @return The content type passed by the agent or {@code null} if not defined.
+     * @return the default charset
      */
-    @Override
-    public String getContentType() {
-        return contentType;
+    public Charset getCharsetDefault() {
+        return charsetDefault;
     }
 
     /**
-     * Gets the default charset for use when no explicit charset parameter is provided by the sender.
+     * Gets the content type passed by the agent or {@code null} if not defined.
      *
-     * @return the default charset
+     * @return The content type passed by the agent or {@code null} if not defined.
      */
-    public Charset getCharsetDefault() {
-        return charsetDefault;
+    @Override
+    public String getContentType() {
+        return contentType;
     }
 
     /**
diff --git a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/disk/DiskFileItemFactory.java b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/disk/DiskFileItemFactory.java
index a7ce5df..19f1fc1 100644
--- a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/disk/DiskFileItemFactory.java
+++ b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/disk/DiskFileItemFactory.java
@@ -21,7 +21,6 @@ import java.nio.file.Path;
 
 import org.apache.commons.fileupload2.FileItem;
 import org.apache.commons.fileupload2.FileItemFactory;
-import org.apache.commons.fileupload2.FileItemHeaders;
 import org.apache.commons.io.FileCleaningTracker;
 import org.apache.commons.io.build.AbstractOrigin;
 import org.apache.commons.io.build.AbstractStreamBuilder;
@@ -172,35 +171,15 @@ public final class DiskFileItemFactory implements FileItemFactory {
         this.fileCleaningTracker = fileCleaningTracker;
     }
 
-    /**
-     * Creates a new {@link DiskFileItem} instance from the supplied parameters and the local factory configuration.
-     *
-     * @param fieldName   The name of the form field.
-     * @param contentType The content type of the form field.
-     * @param isFormField {@code true} if this is a plain form field; {@code false} otherwise.
-     * @param fileName    The name of the uploaded file, if any, as supplied by the browser or other client.
-     * @return The newly created file item.
-     */
     @Override
-    public FileItem createFileItem(final String fieldName, final String contentType, final boolean isFormField, final String fileName,
-            final FileItemHeaders fileItemHeaders) {
+    public DiskFileItem.Builder fileItemBuilder() {
         // @formatter:off
-        final DiskFileItem result = DiskFileItem.builder()
+        return DiskFileItem.builder()
                 .setBufferSize(threshold)
-                .setContentType(contentType)
                 .setCharset(charsetDefault)
-                .setFieldName(fieldName)
-                .setFileItemHeaders(fileItemHeaders)
-                .setFileName(fileName)
-                .setFormField(isFormField)
-                .setPath(repository)
-                .get();
+                .setFileCleaningTracker(fileCleaningTracker)
+                .setPath(repository);
         // @formatter:on
-        final FileCleaningTracker tracker = getFileCleaningTracker();
-        if (tracker != null) {
-            tracker.track(result.getTempFile().toFile(), result);
-        }
-        return result;
     }
 
     /**
diff --git a/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/disk/DiskFileItemSerializeTest.java b/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/disk/DiskFileItemSerializeTest.java
index 0ccf5e2..19b8bff 100644
--- a/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/disk/DiskFileItemSerializeTest.java
+++ b/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/disk/DiskFileItemSerializeTest.java
@@ -103,7 +103,15 @@ public class DiskFileItemSerializeTest {
         final FileItemFactory factory = DiskFileItemFactory.builder().setBufferSize(THRESHOLD).setPath(repository).get();
         final String textFieldName = "textField";
 
-        final FileItem item = factory.createFileItem(textFieldName, TEXT_CONTENT_TYPE, true, "My File Name", null);
+        // @formatter:off
+        final FileItem item = factory.fileItemBuilder()
+                .setFieldName(textFieldName)
+                .setContentType(TEXT_CONTENT_TYPE)
+                .setFormField(true)
+                .setFileName("My File Name")
+                .get();
+        // @formatter:on
+
         try (OutputStream os = item.getOutputStream()) {
             os.write(contentBytes);
         }
@@ -111,14 +119,14 @@ public class DiskFileItemSerializeTest {
     }
 
     /**
-     * Do deserialization.
+     * Deserializes.
      */
     private Object deserialize(final ByteArrayOutputStream baos) {
         return SerializationUtils.deserialize(baos.toByteArray());
     }
 
     /**
-     * Do serialization.
+     * Serializes.
      */
     private ByteArrayOutputStream serialize(final Object target) throws IOException {
         try (final ByteArrayOutputStream baos = new ByteArrayOutputStream();