This is an automated email from the ASF dual-hosted git repository.
bamaer pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git
The following commit(s) were added to refs/heads/main by this push:
new 9ca1f343fb Issue #4303 : Add a Do not right-pad fields option to Text
File Output (#8690)
9ca1f343fb is described below
commit 9ca1f343fbd97be6c5531dabfa931844e71a6dba
Author: Matt Casters <[email protected]>
AuthorDate: Fri Oct 2 06:44:43 2026 +0200
Issue #4303 : Add a Do not right-pad fields option to Text File Output
(#8690)
* Issue #4303 : Add a Do not right-pad fields option to Text File Output
* Issue #4303 : Keep padding when Right pad fields is selected
* Issue #4303 : Keep historical text-file padding unless the user opts out
A new transform left Do not right-pad fields checked, so it stopped padding
short values. Saved pipelines and a new transform now keep the padding Hop
already applies. Checking the option stops that padding, and Right pad fields
still pads when it is selected.
---
.../pages/pipeline/transforms/textfileoutput.adoc | 13 ++-
.../transforms/textfileoutput/TextFileOutput.java | 7 +-
.../textfileoutput/TextFileOutputDialog.java | 48 ++++++++-
.../textfileoutput/TextFileOutputMeta.java | 35 ++++++-
.../messages/messages_en_US.properties | 4 +
.../textfileoutput/TextFileOutputMetaTest.java | 111 ++++++++++++++++++++-
.../textfileoutput/TextFileOutputTest.java | 48 +++++++++
7 files changed, 254 insertions(+), 12 deletions(-)
diff --git
a/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/textfileoutput.adoc
b/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/textfileoutput.adoc
index 45f66ce161..b645e92f45 100644
---
a/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/textfileoutput.adoc
+++
b/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/textfileoutput.adoc
@@ -28,6 +28,9 @@ The Text File Output transform is used to export data to text
file format.
This is commonly used to generate Comma Separated Values (CSV files) that can
be read by spreadsheet applications.
It is also possible to generate fixed width files by setting lengths on the
fields in the fields tab.
+Short values are padded out to those lengths. Existing pipelines keep that
output, and a new transform does too.
+Check *Do not right-pad fields* to write the value as it is. Values longer
than the field length are still shortened.
+*Right pad fields* always pads, including when *Do not right-pad fields* is
checked, and disables that option while it is selected.
Output is buffered. Open files are flushed on an interval so slow-arriving
rows show up without waiting for that buffer to fill. The interval is
xref:variables.adoc[HOP_FILE_OUTPUT_MAX_STREAM_LIFE], in milliseconds. The
default is 5 seconds. A value of 0 uses that default. Set a positive number of
milliseconds to change the interval. A negative value, for example -1, disables
the interval flush.
@@ -99,7 +102,15 @@ To use Unicode specify UTF-8 or UTF-16.
|Compression|Allows you to compress the file and specify the type of
compression, either .zip or .gzip, to use when compressing the output.
Note: Only one file is placed in a single compressed archive.
-|Right pad fields|Add spaces to the end of the fields (or remove characters at
the end) until they have the length specific on the Fields tab.
+|Right pad fields|Add spaces to the end of the fields until they have the
length specified on the Fields tab.
+This always pads.
+While it is selected, Do not right-pad fields is disabled.
+|Do not right-pad fields|Do not add spaces to the end of fields to reach the
length on the Fields tab.
+Values that are longer than that length are still shortened.
+This option is disabled while Right pad fields is selected.
+Right pad fields still pads in that case.
+Existing pipelines and new transforms leave this unchecked, so they keep
padding.
+Check it when those trailing spaces are not wanted.
|Fast data dump (no formatting)|Improves the performance when dumping large
amounts of data to a text file by not including any formatting information.
Field formats are ignored, so a Boolean is written as `true` or `false`.
|Split every ... rows|Specify a number of rows to split the file into chunks
of that many rows.
diff --git
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutput.java
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutput.java
index 002f981aac..f9e616ecaf 100644
---
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutput.java
+++
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutput.java
@@ -598,7 +598,9 @@ public class TextFileOutput extends
BaseTransform<TextFileOutputMeta, TextFileOu
e);
}
}
- if (length > string.length()) {
+ // Saved transforms and a new transform pad, as before. Do not right-pad
fields opts out,
+ // unless Right pad fields is selected.
+ if (length > string.length() &&
meta.getFileSettings().isPaddingFields()) {
// we need to pad this
// not all encoding use single characters, so we need to cope
@@ -674,6 +676,9 @@ public class TextFileOutput extends
BaseTransform<TextFileOutputMeta, TextFileOu
boolean writeEnclosures = false;
if (v.isString()) {
+ // Quoting stays tied to the Right pad fields checkbox.
isPaddingFields() is also true
+ // for saved transforms that never selected that checkbox, and using
it here would drop
+ // enclosures from existing files.
if (meta.isEnclosureForced() && !meta.getFileSettings().isPadded()) {
writeEnclosures = true;
} else if (!meta.isEnclosureFixDisabled()
diff --git
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputDialog.java
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputDialog.java
index 2e0a2ef428..baba50fa32 100644
---
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputDialog.java
+++
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputDialog.java
@@ -129,6 +129,9 @@ public class TextFileOutputDialog extends
BaseTransformDialog {
private Button wPad;
+ private Label wlDoNotPadFields;
+ private Button wDoNotPadFields;
+
private Button wFastDump;
private Label wlSplitEvery;
@@ -867,6 +870,7 @@ public class TextFileOutputDialog extends
BaseTransformDialog {
Label wlPad = new Label(wContentComp, SWT.RIGHT);
wlPad.setText(BaseMessages.getString(PKG,
"TextFileOutputDialog.Pad.Label"));
+ wlPad.setToolTipText(BaseMessages.getString(PKG,
"TextFileOutputDialog.Pad.Tooltip"));
PropsUi.setLook(wlPad);
FormData fdlPad = new FormData();
fdlPad.left = new FormAttachment(0, 0);
@@ -874,6 +878,7 @@ public class TextFileOutputDialog extends
BaseTransformDialog {
fdlPad.right = new FormAttachment(middle, -margin);
wlPad.setLayoutData(fdlPad);
wPad = new Button(wContentComp, SWT.CHECK);
+ wPad.setToolTipText(BaseMessages.getString(PKG,
"TextFileOutputDialog.Pad.Tooltip"));
PropsUi.setLook(wPad);
FormData fdPad = new FormData();
fdPad.left = new FormAttachment(middle, 0);
@@ -881,6 +886,35 @@ public class TextFileOutputDialog extends
BaseTransformDialog {
fdPad.right = new FormAttachment(100, 0);
wPad.setLayoutData(fdPad);
wPad.addSelectionListener(
+ new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ input.setChanged();
+ enableDoNotPadFields();
+ }
+ });
+
+ wlDoNotPadFields = new Label(wContentComp, SWT.RIGHT);
+ wlDoNotPadFields.setText(
+ BaseMessages.getString(PKG,
"TextFileOutputDialog.DoNotPadFields.Label"));
+ wlDoNotPadFields.setToolTipText(
+ BaseMessages.getString(PKG,
"TextFileOutputDialog.DoNotPadFields.Tooltip"));
+ PropsUi.setLook(wlDoNotPadFields);
+ FormData fdlDoNotPadFields = new FormData();
+ fdlDoNotPadFields.left = new FormAttachment(0, 0);
+ fdlDoNotPadFields.top = new FormAttachment(wPad, margin);
+ fdlDoNotPadFields.right = new FormAttachment(middle, -margin);
+ wlDoNotPadFields.setLayoutData(fdlDoNotPadFields);
+ wDoNotPadFields = new Button(wContentComp, SWT.CHECK);
+ wDoNotPadFields.setToolTipText(
+ BaseMessages.getString(PKG,
"TextFileOutputDialog.DoNotPadFields.Tooltip"));
+ PropsUi.setLook(wDoNotPadFields);
+ FormData fdDoNotPadFields = new FormData();
+ fdDoNotPadFields.left = new FormAttachment(middle, 0);
+ fdDoNotPadFields.top = new FormAttachment(wlDoNotPadFields, 0, SWT.CENTER);
+ fdDoNotPadFields.right = new FormAttachment(100, 0);
+ wDoNotPadFields.setLayoutData(fdDoNotPadFields);
+ wDoNotPadFields.addSelectionListener(
new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
@@ -893,7 +927,7 @@ public class TextFileOutputDialog extends
BaseTransformDialog {
PropsUi.setLook(wlFastDump);
FormData fdlFastDump = new FormData();
fdlFastDump.left = new FormAttachment(0, 0);
- fdlFastDump.top = new FormAttachment(wPad, margin);
+ fdlFastDump.top = new FormAttachment(wDoNotPadFields, margin);
fdlFastDump.right = new FormAttachment(middle, -margin);
wlFastDump.setLayoutData(fdlFastDump);
wFastDump = new Button(wContentComp, SWT.CHECK);
@@ -1197,6 +1231,7 @@ public class TextFileOutputDialog extends
BaseTransformDialog {
getData();
activeFileNameField();
+ enableDoNotPadFields();
enableParentFolder();
input.setChanged(changed);
focusTransformName();
@@ -1436,6 +1471,7 @@ public class TextFileOutputDialog extends
BaseTransformDialog {
wAddTransformNr.setSelection(input.getFileSettings().isTransformNrInFilename());
wAddPartnr.setSelection(input.getFileSettings().isPartNrInFilename());
wPad.setSelection(input.getFileSettings().isPadded());
+ wDoNotPadFields.setSelection(input.getFileSettings().isDoNotPadFields());
wFastDump.setSelection(input.getFileSettings().isFastDump());
wAddToResult.setSelection(input.getFileSettings().isAddToResultFiles());
@@ -1508,6 +1544,7 @@ public class TextFileOutputDialog extends
BaseTransformDialog {
tfoi.getFileSettings().setDateTimeFormat(wDateTimeFormat.getText());
tfoi.getFileSettings().setSpecifyingFormat(wSpecifyFormat.getSelection());
tfoi.getFileSettings().setPadded(wPad.getSelection());
+ tfoi.getFileSettings().setDoNotPadFields(wDoNotPadFields.getSelection());
tfoi.getFileSettings().setAddToResultFiles(wAddToResult.getSelection());
tfoi.getFileSettings().setFastDump(wFastDump.getSelection());
@@ -1637,4 +1674,13 @@ public class TextFileOutputDialog extends
BaseTransformDialog {
protected void enableParentFolder() {
// it is enabled always in this implementation
}
+
+ /**
+ * Right pad fields always pads, so the skip-padding option does not apply
while it is selected.
+ */
+ private void enableDoNotPadFields() {
+ boolean rightPad = wPad.getSelection();
+ wlDoNotPadFields.setEnabled(!rightPad);
+ wDoNotPadFields.setEnabled(!rightPad);
+ }
}
diff --git
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputMeta.java
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputMeta.java
index e90b3a9838..29a855691b 100644
---
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputMeta.java
+++
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputMeta.java
@@ -160,6 +160,18 @@ public class TextFileOutputMeta extends
BaseTransformMeta<TextFileOutput, TextFi
injectionKeyDescription = "TextFileOutput.Injection.RIGHT_PAD_FIELDS")
private boolean padded;
+ /**
+ * Skip padding fields with spaces up to their length. Absent from saved
transforms and
+ * unchecked on a new one, so both keep the historical padding. Right pad
fields still pads when
+ * this is checked.
+ */
+ @HopMetadataProperty(
+ key = "do_not_right_pad",
+ defaultBoolean = false,
+ injectionKey = "DO_NOT_RIGHT_PAD_FIELDS",
+ injectionKeyDescription =
"TextFileOutput.Injection.DO_NOT_RIGHT_PAD_FIELDS")
+ private boolean doNotPadFields;
+
/** Flag: Fast dump data without field formatting */
@HopMetadataProperty(
key = "fast_dump",
@@ -187,6 +199,9 @@ public class TextFileOutputMeta extends
BaseTransformMeta<TextFileOutput, TextFi
dateInFilename = false;
timeInFilename = false;
padded = false;
+ // Checked only when the user opts out. A new transform and a saved one
both leave this
+ // off, so they keep the padding Hop has always applied.
+ doNotPadFields = false;
fastDump = false;
addToResultFiles = true;
fileAppended = false;
@@ -203,12 +218,25 @@ public class TextFileOutputMeta extends
BaseTransformMeta<TextFileOutput, TextFi
this.fileAppended = f.fileAppended;
this.fileName = f.fileName;
this.padded = f.padded;
+ this.doNotPadFields = f.doNotPadFields;
this.partNrInFilename = f.partNrInFilename;
this.specifyingFormat = f.specifyingFormat;
this.splitEveryRows = f.splitEveryRows;
this.timeInFilename = f.timeInFilename;
this.transformNrInFilename = f.transformNrInFilename;
}
+
+ /**
+ * Short values are padded out to the field length.
+ *
+ * <p>Saved transforms omit Do not right-pad fields, and a new transform
leaves it unchecked.
+ * Both keep the padding Hop has always applied, whether or not Right pad
fields was selected.
+ * Checking Do not right-pad fields stops that padding, unless Right pad
fields is also
+ * selected. Right pad fields always pads.
+ */
+ public boolean isPaddingFields() {
+ return padded || !doNotPadFields;
+ }
}
/** The file compression: None, Zip or Gzip */
@@ -451,16 +479,15 @@ public class TextFileOutputMeta extends
BaseTransformMeta<TextFileOutput, TextFi
v.setDecimalSymbol(field.getDecimalSymbol());
v.setGroupingSymbol(field.getGroupingSymbol());
v.setCurrencySymbol(field.getCurrencySymbol());
- v.setOutputPaddingEnabled(getFileSettings().isPadded());
v.setTrimType(field.getTrimType());
v.setRoundingType(field.getRoundingType());
if (!Utils.isEmpty(getEncoding())) {
v.setStringEncoding(getEncoding());
}
- // enable output padding by default to be compatible with v2.5.x
- //
- v.setOutputPaddingEnabled(true);
+ // v2.5 compatibility: pad unless the user checked Do not right-pad
fields and did not
+ // select Right pad fields. Saved transforms and a new transform take
the pad path.
+ v.setOutputPaddingEnabled(getFileSettings().isPaddingFields());
}
}
}
diff --git
a/plugins/transforms/textfile/src/main/resources/org/apache/hop/pipeline/transforms/textfileoutput/messages/messages_en_US.properties
b/plugins/transforms/textfile/src/main/resources/org/apache/hop/pipeline/transforms/textfileoutput/messages/messages_en_US.properties
index 0011fc949b..6c6f8641c5 100644
---
a/plugins/transforms/textfile/src/main/resources/org/apache/hop/pipeline/transforms/textfileoutput/messages/messages_en_US.properties
+++
b/plugins/transforms/textfile/src/main/resources/org/apache/hop/pipeline/transforms/textfileoutput/messages/messages_en_US.properties
@@ -58,6 +58,7 @@ TextFileOutput.Injection.OUTPUT_TRIM=Field trim type (none,
left, both, right)
TextFileOutput.Injection.OUTPUT_TYPE=Field type
TextFileOutput.Injection.OUTPUT_ROUNDING=Rounding type
TextFileOutput.Injection.RIGHT_PAD_FIELDS=Right pad fields? (Y/N)
+TextFileOutput.Injection.DO_NOT_RIGHT_PAD_FIELDS=Do not right-pad fields? (Y/N)
TextFileOutput.Injection.RUN_AS_COMMAND=Enable this option to treat the
filename as a command and write data into the output stream created by it.
TextFileOutput.Injection.SEPARATOR=The separator
TextFileOutput.Injection.SPECIFY_DATE_FORMAT=Specify date time format for
filename? (Y/N)
@@ -120,6 +121,9 @@ TextFileOutputDialog.NameColumn.Column=Name
TextFileOutputDialog.NoFilesFound.DialogMessage=No files found\! Please check
the filename/directory and options.
TextFileOutputDialog.NullColumn.Column=Null
TextFileOutputDialog.Pad.Label=Right pad fields
+TextFileOutputDialog.Pad.Tooltip=Add spaces to the end of fields until they
reach the length on the Fields tab. This always pads, and disables Do not
right-pad fields while it is selected.
+TextFileOutputDialog.DoNotPadFields.Label=Do not right-pad fields
+TextFileOutputDialog.DoNotPadFields.Tooltip=Do not add spaces to the end of
fields to reach the length on the Fields tab. Values longer than that length
are still shortened. This option is disabled while Right pad fields is
selected, and Right pad fields still pads. Existing pipelines and new
transforms leave this unchecked and keep padding. Check it to stop that padding.
TextFileOutputDialog.PrecisionColumn.Column=Precision
TextFileOutputDialog.SchemaDefinition.Label=Schema definition
TextFileOutputDialog.SchemaDefinition.Tooltip=Select the schema definition you
want to apply to incoming/outgoing rows
diff --git
a/plugins/transforms/textfile/src/test/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputMetaTest.java
b/plugins/transforms/textfile/src/test/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputMetaTest.java
index dfc4868be2..8469f806e6 100644
---
a/plugins/transforms/textfile/src/test/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputMetaTest.java
+++
b/plugins/transforms/textfile/src/test/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputMetaTest.java
@@ -20,6 +20,7 @@ package org.apache.hop.pipeline.transforms.textfileoutput;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.nio.file.Files;
@@ -37,7 +38,9 @@ import org.apache.hop.core.Const;
import org.apache.hop.core.HopEnvironment;
import org.apache.hop.core.exception.HopException;
import org.apache.hop.core.row.IValueMeta;
+import org.apache.hop.core.row.RowMeta;
import org.apache.hop.core.row.value.ValueMetaFactory;
+import org.apache.hop.core.row.value.ValueMetaString;
import org.apache.hop.core.variables.IVariables;
import org.apache.hop.core.variables.Variables;
import org.apache.hop.core.xml.XmlHandler;
@@ -177,16 +180,95 @@ class TextFileOutputMetaTest {
}
@Test
- void testLoadSave() throws Exception {
- Path path =
-
Paths.get(Objects.requireNonNull(getClass().getResource("/text-file-output.xml")).toURI());
- String xml = Files.readString(path);
+ void newTransformKeepsLegacyPaddingUntilTheOptionIsChecked() throws
Exception {
TextFileOutputMeta meta = new TextFileOutputMeta();
+ assertFalse(meta.getFileSettings().isDoNotPadFields());
+ assertFalse(meta.getFileSettings().isPadded());
+ assertTrue(meta.getFileSettings().isPaddingFields());
+
+ String xml =
+ XmlHandler.openTag(TransformMeta.XML_TAG)
+ + XmlMetadataUtil.serializeObjectToXml(meta)
+ + XmlHandler.closeTag(TransformMeta.XML_TAG);
+ assertFalse(xml.contains("<do_not_right_pad>Y</do_not_right_pad>"));
+
+ TextFileOutputMeta copy = new TextFileOutputMeta();
XmlMetadataUtil.deSerializeFromXml(
XmlHandler.loadXmlString(xml, TransformMeta.XML_TAG),
TextFileOutputMeta.class,
- meta,
+ copy,
new MemoryMetadataProvider());
+ assertFalse(copy.getFileSettings().isDoNotPadFields());
+ assertTrue(copy.getFileSettings().isPaddingFields());
+ }
+
+ @Test
+ void savedTransformWithoutTheFlagStillEnablesOutputPadding() throws
Exception {
+ TextFileOutputMeta meta = loadFixture();
+ assertFalse(meta.getFileSettings().isPadded());
+ assertTrue(meta.getFileSettings().isPaddingFields());
+
+ TextFileOutputMeta cloned = (TextFileOutputMeta) meta.clone();
+ assertNotSame(meta.getFileSettings(), cloned.getFileSettings());
+ assertFalse(cloned.getFileSettings().isDoNotPadFields());
+ assertTrue(cloned.getFileSettings().isPaddingFields());
+
+ RowMeta row = new RowMeta();
+ row.addValueMeta(new ValueMetaString("f1"));
+ row.addValueMeta(new ValueMetaString("f2"));
+ meta.getFields(row, "out", null, null, new Variables(), new
MemoryMetadataProvider());
+ assertTrue(row.getValueMeta(0).isOutputPaddingEnabled());
+ assertEquals(100, row.getValueMeta(0).getLength());
+ assertTrue(row.getValueMeta(1).isOutputPaddingEnabled());
+ assertEquals(7, row.getValueMeta(1).getLength());
+ }
+
+ @Test
+ void outputPaddingFollowsDoNotRightPadFields() throws Exception {
+ TextFileOutputMeta meta = new TextFileOutputMeta();
+ TextFileField field = new TextFileField();
+ field.setName("name");
+ field.setType(IValueMeta.TYPE_STRING);
+ field.setLength(10);
+ meta.getOutputFields().add(field);
+
+ meta.getFileSettings().setDoNotPadFields(false);
+ RowMeta legacy = new RowMeta();
+ legacy.addValueMeta(new ValueMetaString("name"));
+ meta.getFields(legacy, "out", null, null, new Variables(), new
MemoryMetadataProvider());
+ assertTrue(legacy.getValueMeta(0).isOutputPaddingEnabled());
+ assertEquals(10, legacy.getValueMeta(0).getLength());
+
+ meta.getFileSettings().setDoNotPadFields(true);
+ meta.getFileSettings().setPadded(false);
+ RowMeta noPad = new RowMeta();
+ noPad.addValueMeta(new ValueMetaString("name"));
+ meta.getFields(noPad, "out", null, null, new Variables(), new
MemoryMetadataProvider());
+ assertFalse(noPad.getValueMeta(0).isOutputPaddingEnabled());
+ }
+
+ @Test
+ void rightPadFieldsPadsWhenDoNotRightPadIsAlsoSelected() throws Exception {
+ TextFileOutputMeta meta = new TextFileOutputMeta();
+ TextFileField field = new TextFileField();
+ field.setName("name");
+ field.setType(IValueMeta.TYPE_STRING);
+ field.setLength(10);
+ meta.getOutputFields().add(field);
+ meta.getFileSettings().setDoNotPadFields(true);
+ meta.getFileSettings().setPadded(true);
+
+ assertTrue(meta.getFileSettings().isPaddingFields());
+
+ RowMeta row = new RowMeta();
+ row.addValueMeta(new ValueMetaString("name"));
+ meta.getFields(row, "out", null, null, new Variables(), new
MemoryMetadataProvider());
+ assertTrue(row.getValueMeta(0).isOutputPaddingEnabled());
+ }
+
+ @Test
+ void testLoadSave() throws Exception {
+ TextFileOutputMeta meta = loadFixture();
validate(meta);
@@ -205,6 +287,22 @@ class TextFileOutputMetaTest {
validate(metaCopy);
}
+ private static TextFileOutputMeta loadFixture() throws Exception {
+ Path path =
+ Paths.get(
+ Objects.requireNonNull(
+
TextFileOutputMetaTest.class.getResource("/text-file-output.xml"))
+ .toURI());
+ String xml = Files.readString(path);
+ TextFileOutputMeta meta = new TextFileOutputMeta();
+ XmlMetadataUtil.deSerializeFromXml(
+ XmlHandler.loadXmlString(xml, TransformMeta.XML_TAG),
+ TextFileOutputMeta.class,
+ meta,
+ new MemoryMetadataProvider());
+ return meta;
+ }
+
private static void validate(TextFileOutputMeta meta) {
assertEquals("schemaDefinition", meta.getSchemaDefinition());
assertTrue(meta.isIgnoreFields());
@@ -235,6 +333,9 @@ class TextFileOutputMetaTest {
assertTrue(StringUtils.isEmpty(meta.getFileSettings().getDateTimeFormat()));
assertTrue(meta.getFileSettings().isAddToResultFiles());
assertFalse(meta.getFileSettings().isPadded());
+ // The fixture predates the option. Right pad fields is off, and padding
still stays on.
+ assertFalse(meta.getFileSettings().isDoNotPadFields());
+ assertTrue(meta.getFileSettings().isPaddingFields());
assertTrue(meta.getFileSettings().isFastDump());
assertEquals("0", meta.getFileSettings().getSplitEveryRows());
diff --git
a/plugins/transforms/textfile/src/test/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputTest.java
b/plugins/transforms/textfile/src/test/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputTest.java
index cff519cc11..737232387d 100644
---
a/plugins/transforms/textfile/src/test/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputTest.java
+++
b/plugins/transforms/textfile/src/test/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputTest.java
@@ -829,6 +829,54 @@ class TextFileOutputTest {
return IOUtils.toString(file.getContent().getInputStream(),
StandardCharsets.UTF_8);
}
+ @Test
+ void doNotRightPadFieldsSkipsTrailingSpaces() throws Exception {
+ assertEquals("abc ", writeStringField("abc", 10, false, false));
+ assertEquals("abc ", writeStringField("abc", 10, false, true));
+ assertEquals("abc", writeStringField("abc", 10, true, false));
+ // Right pad fields wins when both options are selected.
+ assertEquals("abc ", writeStringField("abc", 10, true, true));
+ assertEquals("abcdefghij", writeStringField("abcdefghijklmnop", 10, false,
false));
+ assertEquals("abcdefghij", writeStringField("abcdefghijklmnop", 10, true,
true));
+ }
+
+ private String writeStringField(String value, int length, boolean doNotPad,
boolean rightPad)
+ throws Exception {
+ TextFileOutputMeta meta = new TextFileOutputMeta();
+ meta.setEncoding(Const.UTF_8);
+ meta.setSeparator("");
+ meta.setEnclosure("");
+ meta.setEnclosureForced(false);
+ meta.setEnclosureFixDisabled(true);
+ meta.getFileSettings().setDoNotPadFields(doNotPad);
+ meta.getFileSettings().setPadded(rightPad);
+
+ TextFileOutputData data = new TextFileOutputData();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ data.writer = baos;
+ data.binarySeparator = new byte[0];
+ data.binaryEnclosure = new byte[0];
+ data.binaryNewline = "\n".getBytes(StandardCharsets.UTF_8);
+
+ ValueMetaString valueMeta = new ValueMetaString("name");
+ valueMeta.setLength(length);
+ RowMeta rowMeta = new RowMeta();
+ rowMeta.addValueMeta(valueMeta);
+
+ TextFileOutput transform =
+ new TextFileOutput(
+ transformMockHelper.transformMeta,
+ meta,
+ data,
+ 0,
+ transformMockHelper.pipelineMeta,
+ transformMockHelper.pipeline);
+ transform.writeRow(rowMeta, new Object[] {value});
+ String written = baos.toString(StandardCharsets.UTF_8);
+ assertTrue(written.endsWith("\n"), written);
+ return written.substring(0, written.length() - 1);
+ }
+
@Test
void testFastDumpDisableStreamEncodeTest() throws Exception {