diff --git a/spring-integration-zip/src/main/java/org/springframework/integration/zip/transformer/AbstractZipTransformer.java b/spring-integration-zip/src/main/java/org/springframework/integration/zip/transformer/AbstractZipTransformer.java
index 58639af1e9..948aa58ba6 100644
--- a/spring-integration-zip/src/main/java/org/springframework/integration/zip/transformer/AbstractZipTransformer.java
+++ b/spring-integration-zip/src/main/java/org/springframework/integration/zip/transformer/AbstractZipTransformer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2023 the original author or authors.
+ * Copyright 2015-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,8 +19,6 @@ package org.springframework.integration.zip.transformer;
import java.io.File;
import java.nio.charset.Charset;
-import org.springframework.integration.file.DefaultFileNameGenerator;
-import org.springframework.integration.file.FileNameGenerator;
import org.springframework.integration.transformer.AbstractTransformer;
import org.springframework.messaging.Message;
import org.springframework.util.Assert;
@@ -37,8 +35,6 @@ public abstract class AbstractZipTransformer extends AbstractTransformer {
protected Charset charset = Charset.defaultCharset();
- protected FileNameGenerator fileNameGenerator;
-
protected ZipResultType zipResultType = ZipResultType.FILE;
protected File workDirectory =
@@ -91,11 +87,6 @@ public abstract class AbstractZipTransformer extends AbstractTransformer {
logger.info(() -> "Creating work directory: " + this.workDirectory);
Assert.isTrue(this.workDirectory.mkdirs(), () -> "Can't create the 'workDirectory': " + this.workDirectory);
}
- DefaultFileNameGenerator defaultFileNameGenerator = new DefaultFileNameGenerator();
- defaultFileNameGenerator.setBeanFactory(getBeanFactory());
- defaultFileNameGenerator.setConversionService(getConversionService());
- this.fileNameGenerator = defaultFileNameGenerator;
-
}
/**
diff --git a/spring-integration-zip/src/main/java/org/springframework/integration/zip/transformer/ZipTransformer.java b/spring-integration-zip/src/main/java/org/springframework/integration/zip/transformer/ZipTransformer.java
index 056e831b30..fe8d68c32b 100644
--- a/spring-integration-zip/src/main/java/org/springframework/integration/zip/transformer/ZipTransformer.java
+++ b/spring-integration-zip/src/main/java/org/springframework/integration/zip/transformer/ZipTransformer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2023 the original author or authors.
+ * Copyright 2015-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,10 +29,13 @@ import org.zeroturnaround.zip.ByteSource;
import org.zeroturnaround.zip.FileSource;
import org.zeroturnaround.zip.ZipEntrySource;
+import org.springframework.integration.file.DefaultFileNameGenerator;
import org.springframework.integration.file.FileHeaders;
+import org.springframework.integration.file.FileNameGenerator;
import org.springframework.integration.transformer.Transformer;
import org.springframework.integration.zip.ZipHeaders;
import org.springframework.messaging.Message;
+import org.springframework.messaging.MessageHeaders;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
@@ -43,9 +46,6 @@ import org.springframework.util.StringUtils;
*
* See also:
*
- * If you want to generate Zip files larger than {@code 4GB}, you must use Java 7:
- *
- * See also:
*
* @author Gunnar Hillert
* @author Artem Bilan
@@ -56,9 +56,11 @@ public class ZipTransformer extends AbstractZipTransformer {
private static final String ZIP_EXTENSION = ".zip";
- private volatile int compressionLevel = Deflater.DEFAULT_COMPRESSION;
+ private int compressionLevel = Deflater.DEFAULT_COMPRESSION;
- private volatile boolean useFileAttributes = true;
+ private boolean useFileAttributes = true;
+
+ private FileNameGenerator fileNameGenerator;
/**
* Set the compression level. Default is {@link Deflater#DEFAULT_COMPRESSION}.
@@ -77,6 +79,31 @@ public class ZipTransformer extends AbstractZipTransformer {
this.useFileAttributes = useFileAttributes;
}
+ /**
+ * Set a {@link FileNameGenerator} for zip file base name: the {@code .zip} extension is added to this name.
+ * Unless it already comes with {@code .zip} extension.
+ * Defaults to the {@link org.springframework.integration.file.DefaultFileNameGenerator}.
+ * The result of this generator is also used for zip entry(ies) if {@link ZipHeaders#ZIP_ENTRY_FILE_NAME}
+ * header is not provided in the request message.
+ * @param fileNameGenerator the {@link FileNameGenerator} to use.
+ * @since 6.4
+ */
+ public void setFileNameGenerator(FileNameGenerator fileNameGenerator) {
+ Assert.notNull(fileNameGenerator, "'fileNameGenerator' must not be null");
+ this.fileNameGenerator = fileNameGenerator;
+ }
+
+ @Override
+ protected void onInit() {
+ super.onInit();
+ if (this.fileNameGenerator == null) {
+ DefaultFileNameGenerator defaultFileNameGenerator = new DefaultFileNameGenerator();
+ defaultFileNameGenerator.setBeanFactory(getBeanFactory());
+ defaultFileNameGenerator.setConversionService(getConversionService());
+ this.fileNameGenerator = defaultFileNameGenerator;
+ }
+ }
+
/**
* The payload may encompass the following types:
*
@@ -91,39 +118,19 @@ public class ZipTransformer extends AbstractZipTransformer {
@Override
protected Object doZipTransform(Message> message) {
Object payload = message.getPayload();
- Object zippedData;
+ MessageHeaders messageHeaders = message.getHeaders();
+
String baseFileName = this.fileNameGenerator.generateFileName(message);
+ String zipFileName = baseFileName.endsWith(ZIP_EXTENSION) ? baseFileName : baseFileName + ZIP_EXTENSION;
- String zipEntryName;
- String zipFileName;
-
- if (message.getHeaders().containsKey(ZipHeaders.ZIP_ENTRY_FILE_NAME)) {
- zipEntryName = (String) message.getHeaders().get(ZipHeaders.ZIP_ENTRY_FILE_NAME);
- }
- else {
- zipEntryName = baseFileName;
- }
-
- if (message.getHeaders().containsKey(FileHeaders.FILENAME)) {
- zipFileName = (String) message.getHeaders().get(FileHeaders.FILENAME);
- }
- else {
- zipFileName = baseFileName + ZIP_EXTENSION;
- }
-
- Date lastModifiedDate;
-
- if (message.getHeaders().containsKey(ZipHeaders.ZIP_ENTRY_LAST_MODIFIED_DATE)) {
- lastModifiedDate = message.getHeaders().get(ZipHeaders.ZIP_ENTRY_LAST_MODIFIED_DATE, Date.class);
- }
- else {
- lastModifiedDate = new Date();
- }
+ String zipEntryName = (String) messageHeaders.getOrDefault(ZipHeaders.ZIP_ENTRY_FILE_NAME, baseFileName);
+ Date lastModifiedDate = (Date) messageHeaders.getOrDefault(ZipHeaders.ZIP_ENTRY_LAST_MODIFIED_DATE, new Date());
List entries = createZipEntries(payload, zipEntryName, lastModifiedDate);
byte[] zippedBytes = SpringZipUtils.pack(entries, this.compressionLevel);
+ Object zippedData;
if (ZipResultType.FILE.equals(this.zipResultType)) {
final File zippedFile = new File(this.workDirectory, zipFileName);
try {
@@ -145,7 +152,7 @@ public class ZipTransformer extends AbstractZipTransformer {
return getMessageBuilderFactory()
.withPayload(zippedData)
- .copyHeaders(message.getHeaders())
+ .copyHeaders(messageHeaders)
.setHeader(FileHeaders.FILENAME, zipFileName)
.build();
}
diff --git a/spring-integration-zip/src/test/java/org/springframework/integration/zip/config/xml/UnZipTransformerParserTests.java b/spring-integration-zip/src/test/java/org/springframework/integration/zip/config/xml/UnZipTransformerParserTests.java
index 2a0dc0e331..4264d408c5 100644
--- a/spring-integration-zip/src/test/java/org/springframework/integration/zip/config/xml/UnZipTransformerParserTests.java
+++ b/spring-integration-zip/src/test/java/org/springframework/integration/zip/config/xml/UnZipTransformerParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2023 the original author or authors.
+ * Copyright 2015-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,8 +25,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.integration.channel.AbstractMessageChannel;
import org.springframework.integration.endpoint.EventDrivenConsumer;
-import org.springframework.integration.file.DefaultFileNameGenerator;
-import org.springframework.integration.file.FileNameGenerator;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.integration.transformer.MessageTransformingHandler;
import org.springframework.integration.zip.transformer.UnZipTransformer;
@@ -64,21 +62,18 @@ public class UnZipTransformerParserTests {
final UnZipTransformer unZipTransformer = TestUtils.getPropertyValue(handler, "transformer", UnZipTransformer.class);
final Charset charset = TestUtils.getPropertyValue(unZipTransformer, "charset", Charset.class);
- final FileNameGenerator fileNameGenerator = TestUtils.getPropertyValue(unZipTransformer, "fileNameGenerator", FileNameGenerator.class);
final ZipResultType zipResultType = TestUtils.getPropertyValue(unZipTransformer, "zipResultType", ZipResultType.class);
final File workDirectory = TestUtils.getPropertyValue(unZipTransformer, "workDirectory", File.class);
final Boolean deleteFiles = TestUtils.getPropertyValue(unZipTransformer, "deleteFiles", Boolean.class);
final Boolean expectSingleResult = TestUtils.getPropertyValue(unZipTransformer, "expectSingleResult", Boolean.class);
assertThat(charset).isNotNull();
- assertThat(fileNameGenerator).isNotNull();
assertThat(zipResultType).isNotNull();
assertThat(workDirectory).isNotNull();
assertThat(deleteFiles).isNotNull();
assertThat(expectSingleResult).isNotNull();
assertThat(charset).isEqualTo(Charset.defaultCharset());
- assertThat(fileNameGenerator).isInstanceOf(DefaultFileNameGenerator.class);
assertThat(zipResultType).isEqualTo(ZipResultType.FILE);
assertThat(workDirectory)
.isEqualTo(new File(System.getProperty("java.io.tmpdir") + File.separator + "ziptransformer"));
@@ -102,21 +97,18 @@ public class UnZipTransformerParserTests {
final UnZipTransformer unZipTransformer = TestUtils.getPropertyValue(handler, "transformer", UnZipTransformer.class);
final Charset charset = TestUtils.getPropertyValue(unZipTransformer, "charset", Charset.class);
- final FileNameGenerator fileNameGenerator = TestUtils.getPropertyValue(unZipTransformer, "fileNameGenerator", FileNameGenerator.class);
final ZipResultType zipResultType = TestUtils.getPropertyValue(unZipTransformer, "zipResultType", ZipResultType.class);
final File workDirectory = TestUtils.getPropertyValue(unZipTransformer, "workDirectory", File.class);
final Boolean deleteFiles = TestUtils.getPropertyValue(unZipTransformer, "deleteFiles", Boolean.class);
final Boolean expectSingleResult = TestUtils.getPropertyValue(unZipTransformer, "expectSingleResult", Boolean.class);
assertThat(charset).isNotNull();
- assertThat(fileNameGenerator).isNotNull();
assertThat(zipResultType).isNotNull();
assertThat(workDirectory).isNotNull();
assertThat(deleteFiles).isNotNull();
assertThat(expectSingleResult).isNotNull();
assertThat(charset).isEqualTo(Charset.defaultCharset());
- assertThat(fileNameGenerator).isInstanceOf(DefaultFileNameGenerator.class);
assertThat(zipResultType).isEqualTo(ZipResultType.FILE);
assertThat(workDirectory)
.isEqualTo(new File(System.getProperty("java.io.tmpdir") + File.separator + "ziptransformer"));
diff --git a/src/reference/antora/modules/ROOT/pages/whats-new.adoc b/src/reference/antora/modules/ROOT/pages/whats-new.adoc
index c286857483..b5e22303c8 100644
--- a/src/reference/antora/modules/ROOT/pages/whats-new.adoc
+++ b/src/reference/antora/modules/ROOT/pages/whats-new.adoc
@@ -78,3 +78,9 @@ See xref:sftp/session-factory.adoc[SFTP Session Factory] for more information.
Multiple instances of `MqttPahoMessageDrivenChannelAdapter` and `Mqttv5PahoMessageDrivenChannelAdapter` can now be added at runtime using corresponding `ClientManager` through `IntegrationFlowContext`
Also a `MqttMessageNotDeliveredEvent` event has been introduced to emit when action callback reacts to the delivery failure.
See xref:mqtt.adoc[MQTT Support] for more information.
+
+[[x6.4-zip-support-changes]]
+=== Zip Support Changes
+
+The `ZipTransformer` now exposes a `fileNameGenerator` property to customize a target zip file (and optional zip entry) name generation.
+See xref:zip.adoc[Zip Support] for more information.
diff --git a/src/reference/antora/modules/ROOT/pages/zip.adoc b/src/reference/antora/modules/ROOT/pages/zip.adoc
index d7ebf3e864..9d99f06a69 100644
--- a/src/reference/antora/modules/ROOT/pages/zip.adoc
+++ b/src/reference/antora/modules/ROOT/pages/zip.adoc
@@ -69,6 +69,14 @@ The `ZipTransformer` can be customized by setting several properties:
Default is `Deflater#DEFAULT_COMPRESSION`.
* `useFileAttributes` - specifies whether the name of the file shall be used for the zip entry.
+* `fileNameGenerator` - uses to generate an original file name based on the request message.
+Defaults to `DefaultFileNameGenerator`.
+The `.zip` extension is added into this name for the target zip file name.
+Unless it is already present as a result of this generator.
+
+In addition, a `ZipHeaders.ZIP_ENTRY_FILE_NAME` and `ZipHeaders.ZIP_ENTRY_LAST_MODIFIED_DATE` can be supplied for the name of zip entry and its `lastmodified` attribute.
+If not provided, the entry name is exact result of the `fileNameGenerator` and `lastmodified` falls back to the current date and time.
+If the payload of request message is an `Iterable`, then this entry name is modified with an index starting `1`.
For example to zip a simple `test.txt` file into a `test.txt.zip`, only this configuration is enough: