You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hop.apache.org by mc...@apache.org on 2026/03/27 11:59:51 UTC

(hop) branch main updated: issue #1930 (XML cleanup Set Field Value to a Constant) (#6870)

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

mcasters 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 b3499b6593 issue #1930 (XML cleanup Set Field Value to a Constant) (#6870)
b3499b6593 is described below

commit b3499b6593bd1bfec9e6fca580eb196044bdec2a
Author: Matt Casters <ma...@gmail.com>
AuthorDate: Fri Mar 27 12:59:47 2026 +0100

    issue #1930 (XML cleanup Set Field Value to a Constant) (#6870)
---
 .../mdi/0046-set-constant-values-validate.hpl      | 270 +++++++++++++++++++++
 integration-tests/mdi/0046-set-constant-values.hpl | 268 ++++++++++++++++++++
 .../mdi/0046-set-contant-values-template.hpl       |  65 +++++
 .../datasets/golden-set-constant-values-fields.csv |   4 +
 .../mdi/datasets/golden-set-constant-values.csv    |   2 +
 .../mdi/files/set-constant-values.xml              |  41 ++++
 .../mdi/main-0046-set-constant-values.hwf          | 113 +++++++++
 .../dataset/golden-set-constant-values-fields.json |  40 +++
 .../dataset/golden-set-constant-values.json        |  16 ++
 .../0046-set-constant-values-validate UNIT.json    |  56 +++++
 .../setvalueconstant/SetValueConstant.java         |  28 +--
 .../setvalueconstant/SetValueConstantDialog.java   | 118 ++++-----
 .../setvalueconstant/SetValueConstantMeta.java     | 184 +++++---------
 .../SetValueConstantMetaInjectionTest.java         |  44 ----
 .../setvalueconstant/SetValueConstantMetaTest.java | 117 ++-------
 .../setvalueconstant/SetValueConstantTest.java     |   1 -
 .../src/test/resources/set-constant-values.xml     |  41 ++++
 17 files changed, 1055 insertions(+), 353 deletions(-)

diff --git a/integration-tests/mdi/0046-set-constant-values-validate.hpl b/integration-tests/mdi/0046-set-constant-values-validate.hpl
new file mode 100644
index 0000000000..114f2a69ff
--- /dev/null
+++ b/integration-tests/mdi/0046-set-constant-values-validate.hpl
@@ -0,0 +1,270 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<pipeline>
+  <info>
+    <name>0046-set-constant-values-validate</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description/>
+    <extended_description/>
+    <pipeline_version/>
+    <pipeline_type>Normal</pipeline_type>
+    <parameters>
+    </parameters>
+    <capture_transform_performance>N</capture_transform_performance>
+    <transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    <transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <created_user>-</created_user>
+    <created_date>2026/03/25 13:00:53.820</created_date>
+    <modified_user>-</modified_user>
+    <modified_date>2026/03/25 13:00:53.820</modified_date>
+  </info>
+  <notepads>
+  </notepads>
+  <order>
+    <hop>
+      <from>/tmp/set-constant-values.hpl fields</from>
+      <to>validate fields</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>/tmp/set-constant-values.hpl</from>
+      <to>validate</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <transform>
+    <name>/tmp/set-constant-values.hpl fields</name>
+    <type>getXMLData</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <IsAFile>N</IsAFile>
+    <IsIgnoreEmptyFile>N</IsIgnoreEmptyFile>
+    <IsInFields>N</IsInFields>
+    <XmlField/>
+    <addresultfile>N</addresultfile>
+    <doNotFailIfNoFile>Y</doNotFailIfNoFile>
+    <encoding>UTF-8</encoding>
+    <extensionFieldName/>
+    <fields>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>name</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>name</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>value</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>value</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>mask</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>mask</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>set_empty_string</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>Boolean</type>
+        <xPath>set_empty_string</xPath>
+      </field>
+    </fields>
+    <file>
+      <exclude_filemask/>
+      <file_required>N</file_required>
+      <filemask/>
+      <include_subfolders>N</include_subfolders>
+      <name>${java.io.tmpdir}/set-constant-values.hpl</name>
+    </file>
+    <hiddenFieldName/>
+    <ignorecomments>N</ignorecomments>
+    <include>N</include>
+    <include_field/>
+    <lastModificationTimeFieldName/>
+    <limit>0</limit>
+    <loopxpath>/pipeline/transform/fields/field</loopxpath>
+    <namespaceaware>N</namespaceaware>
+    <pathFieldName/>
+    <prunePath/>
+    <readurl>N</readurl>
+    <rootUriNameFieldName/>
+    <rownum>N</rownum>
+    <rownum_field/>
+    <shortFileFieldName/>
+    <sizeFieldName/>
+    <uriNameFieldName/>
+    <usetoken>N</usetoken>
+    <validating>N</validating>
+    <attributes/>
+    <GUI>
+      <xloc>112</xloc>
+      <yloc>160</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>/tmp/set-constant-values.hpl</name>
+    <type>getXMLData</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <IsAFile>N</IsAFile>
+    <IsIgnoreEmptyFile>N</IsIgnoreEmptyFile>
+    <IsInFields>N</IsInFields>
+    <XmlField/>
+    <addresultfile>N</addresultfile>
+    <doNotFailIfNoFile>Y</doNotFailIfNoFile>
+    <encoding>UTF-8</encoding>
+    <extensionFieldName/>
+    <fields>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>usevar</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>Boolean</type>
+        <xPath>usevar</xPath>
+      </field>
+    </fields>
+    <file>
+      <exclude_filemask/>
+      <file_required>N</file_required>
+      <filemask/>
+      <include_subfolders>N</include_subfolders>
+      <name>${java.io.tmpdir}/set-constant-values.hpl</name>
+    </file>
+    <hiddenFieldName/>
+    <ignorecomments>N</ignorecomments>
+    <include>N</include>
+    <include_field/>
+    <lastModificationTimeFieldName/>
+    <limit>0</limit>
+    <loopxpath>/pipeline/transform</loopxpath>
+    <namespaceaware>N</namespaceaware>
+    <pathFieldName/>
+    <prunePath/>
+    <readurl>N</readurl>
+    <rootUriNameFieldName/>
+    <rownum>N</rownum>
+    <rownum_field/>
+    <shortFileFieldName/>
+    <sizeFieldName/>
+    <uriNameFieldName/>
+    <usetoken>N</usetoken>
+    <validating>N</validating>
+    <attributes/>
+    <GUI>
+      <xloc>112</xloc>
+      <yloc>80</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>validate fields</name>
+    <type>Dummy</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+    <GUI>
+      <xloc>320</xloc>
+      <yloc>160</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>validate</name>
+    <type>Dummy</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+    <GUI>
+      <xloc>320</xloc>
+      <yloc>80</yloc>
+    </GUI>
+  </transform>
+  <transform_error_handling>
+  </transform_error_handling>
+  <attributes/>
+</pipeline>
diff --git a/integration-tests/mdi/0046-set-constant-values.hpl b/integration-tests/mdi/0046-set-constant-values.hpl
new file mode 100644
index 0000000000..f10da81623
--- /dev/null
+++ b/integration-tests/mdi/0046-set-constant-values.hpl
@@ -0,0 +1,268 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<pipeline>
+  <info>
+    <name>0046-set-constant-values</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description/>
+    <extended_description/>
+    <pipeline_version/>
+    <pipeline_type>Normal</pipeline_type>
+    <parameters>
+    </parameters>
+    <capture_transform_performance>N</capture_transform_performance>
+    <transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    <transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <created_user>-</created_user>
+    <created_date>2026/03/25 12:52:28.576</created_date>
+    <modified_user>-</modified_user>
+    <modified_date>2026/03/25 12:52:28.576</modified_date>
+  </info>
+  <notepads>
+  </notepads>
+  <order>
+    <hop>
+      <from>use-variables</from>
+      <to>0046-set-contant-values-template.hpl</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Get data from XML</from>
+      <to>0046-set-contant-values-template.hpl</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <transform>
+    <name>0046-set-contant-values-template.hpl</name>
+    <type>MetaInject</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <allow_empty_stream_on_execution>N</allow_empty_stream_on_execution>
+    <create_parent_folder>Y</create_parent_folder>
+    <filename>${PROJECT_HOME}/0046-set-contant-values-template.hpl</filename>
+    <mappings>
+      <mapping>
+        <source_field>use-variables</source_field>
+        <source_transform>use-variables</source_transform>
+        <target_attribute_key>USE_VARIABLE</target_attribute_key>
+        <target_detail>N</target_detail>
+        <target_transform_name>Set field value to a constant</target_transform_name>
+      </mapping>
+      <mapping>
+        <source_field>mask</source_field>
+        <source_transform>Get data from XML</source_transform>
+        <target_attribute_key>REPLACE_MASK</target_attribute_key>
+        <target_detail>Y</target_detail>
+        <target_transform_name>Set field value to a constant</target_transform_name>
+      </mapping>
+      <mapping>
+        <source_field>name</source_field>
+        <source_transform>Get data from XML</source_transform>
+        <target_attribute_key>FIELD_NAME</target_attribute_key>
+        <target_detail>Y</target_detail>
+        <target_transform_name>Set field value to a constant</target_transform_name>
+      </mapping>
+      <mapping>
+        <source_field>set_empty_string</source_field>
+        <source_transform>Get data from XML</source_transform>
+        <target_attribute_key>EMPTY_STRING</target_attribute_key>
+        <target_detail>Y</target_detail>
+        <target_transform_name>Set field value to a constant</target_transform_name>
+      </mapping>
+      <mapping>
+        <source_field>value</source_field>
+        <source_transform>Get data from XML</source_transform>
+        <target_attribute_key>REPLACE_VALUE</target_attribute_key>
+        <target_detail>Y</target_detail>
+        <target_transform_name>Set field value to a constant</target_transform_name>
+      </mapping>
+    </mappings>
+    <no_execution>Y</no_execution>
+    <run_configuration>local</run_configuration>
+    <source_output_fields>
+</source_output_fields>
+    <source_transform/>
+    <stream_source_transform/>
+    <stream_target_transform/>
+    <target_file>${java.io.tmpdir}/set-constant-values.hpl</target_file>
+    <attributes/>
+    <GUI>
+      <xloc>272</xloc>
+      <yloc>96</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>use-variables</name>
+    <type>DataGrid</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <data>
+      <line>
+        <item>true</item>
+      </line>
+    </data>
+    <fields>
+      <field>
+        <length>-1</length>
+        <precision>-1</precision>
+        <currency/>
+        <set_empty_string>N</set_empty_string>
+        <name>use-variables</name>
+        <format/>
+        <group/>
+        <decimal/>
+        <type>Boolean</type>
+      </field>
+    </fields>
+    <attributes/>
+    <GUI>
+      <xloc>96</xloc>
+      <yloc>96</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>Get data from XML</name>
+    <type>getXMLData</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <IsAFile>N</IsAFile>
+    <IsIgnoreEmptyFile>N</IsIgnoreEmptyFile>
+    <IsInFields>N</IsInFields>
+    <XmlField/>
+    <addresultfile>N</addresultfile>
+    <doNotFailIfNoFile>Y</doNotFailIfNoFile>
+    <encoding>UTF-8</encoding>
+    <extensionFieldName/>
+    <fields>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>mask</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>mask</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>name</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>name</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>set_empty_string</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>set_empty_string</xPath>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <element_type>Node</element_type>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>value</name>
+        <precision>-1</precision>
+        <repeat>N</repeat>
+        <result_type>valueof</result_type>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <xPath>value</xPath>
+      </field>
+    </fields>
+    <file>
+      <exclude_filemask/>
+      <file_required>N</file_required>
+      <filemask/>
+      <include_subfolders>N</include_subfolders>
+      <name>${PROJECT_HOME}/files/set-constant-values.xml</name>
+    </file>
+    <hiddenFieldName/>
+    <ignorecomments>N</ignorecomments>
+    <include>N</include>
+    <include_field/>
+    <lastModificationTimeFieldName/>
+    <limit>0</limit>
+    <loopxpath>/transform/fields/field</loopxpath>
+    <namespaceaware>N</namespaceaware>
+    <pathFieldName/>
+    <prunePath/>
+    <readurl>N</readurl>
+    <rootUriNameFieldName/>
+    <rownum>N</rownum>
+    <rownum_field/>
+    <shortFileFieldName/>
+    <sizeFieldName/>
+    <uriNameFieldName/>
+    <usetoken>N</usetoken>
+    <validating>N</validating>
+    <attributes/>
+    <GUI>
+      <xloc>96</xloc>
+      <yloc>192</yloc>
+    </GUI>
+  </transform>
+  <transform_error_handling>
+  </transform_error_handling>
+  <attributes/>
+</pipeline>
diff --git a/integration-tests/mdi/0046-set-contant-values-template.hpl b/integration-tests/mdi/0046-set-contant-values-template.hpl
new file mode 100644
index 0000000000..2f7217d3a3
--- /dev/null
+++ b/integration-tests/mdi/0046-set-contant-values-template.hpl
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<pipeline>
+  <info>
+    <name>0046-set-contant-values-template</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description/>
+    <extended_description/>
+    <pipeline_version/>
+    <pipeline_type>Normal</pipeline_type>
+    <parameters>
+    </parameters>
+    <capture_transform_performance>N</capture_transform_performance>
+    <transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    <transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <created_user>-</created_user>
+    <created_date>2026/03/25 12:52:02.368</created_date>
+    <modified_user>-</modified_user>
+    <modified_date>2026/03/25 12:52:02.368</modified_date>
+  </info>
+  <notepads>
+  </notepads>
+  <order>
+  </order>
+  <transform>
+    <name>Set field value to a constant</name>
+    <type>SetValueConstant</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <fields>
+</fields>
+    <usevar>N</usevar>
+    <attributes/>
+    <GUI>
+      <xloc>192</xloc>
+      <yloc>96</yloc>
+    </GUI>
+  </transform>
+  <transform_error_handling>
+  </transform_error_handling>
+  <attributes/>
+</pipeline>
diff --git a/integration-tests/mdi/datasets/golden-set-constant-values-fields.csv b/integration-tests/mdi/datasets/golden-set-constant-values-fields.csv
new file mode 100644
index 0000000000..68918568de
--- /dev/null
+++ b/integration-tests/mdi/datasets/golden-set-constant-values-fields.csv
@@ -0,0 +1,4 @@
+name,value,mask,set_empty_string
+f1,const1,,N
+f2,2026/03/25,yyyy/MM/dd,N
+f3,,,Y
diff --git a/integration-tests/mdi/datasets/golden-set-constant-values.csv b/integration-tests/mdi/datasets/golden-set-constant-values.csv
new file mode 100644
index 0000000000..7dd23f0766
--- /dev/null
+++ b/integration-tests/mdi/datasets/golden-set-constant-values.csv
@@ -0,0 +1,2 @@
+usevar
+Y
diff --git a/integration-tests/mdi/files/set-constant-values.xml b/integration-tests/mdi/files/set-constant-values.xml
new file mode 100644
index 0000000000..02d4a01156
--- /dev/null
+++ b/integration-tests/mdi/files/set-constant-values.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~       http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<transform>
+    <fields>
+        <field>
+            <mask/>
+            <name>f1</name>
+            <set_empty_string>N</set_empty_string>
+            <value>const1</value>
+        </field>
+        <field>
+            <mask>yyyy/MM/dd</mask>
+            <name>f2</name>
+            <set_empty_string>N</set_empty_string>
+            <value>2026/03/25</value>
+        </field>
+        <field>
+            <mask/>
+            <name>f3</name>
+            <set_empty_string>Y</set_empty_string>
+            <value/>
+        </field>
+    </fields>
+    <usevar>Y</usevar>
+</transform>
diff --git a/integration-tests/mdi/main-0046-set-constant-values.hwf b/integration-tests/mdi/main-0046-set-constant-values.hwf
new file mode 100644
index 0000000000..98cf3dc629
--- /dev/null
+++ b/integration-tests/mdi/main-0046-set-constant-values.hwf
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<workflow>
+  <name>main-0046-set-constant-values</name>
+  <name_sync_with_filename>Y</name_sync_with_filename>
+  <description/>
+  <extended_description/>
+  <workflow_version/>
+  <created_user>-</created_user>
+  <created_date>2026/03/25 12:51:28.914</created_date>
+  <modified_user>-</modified_user>
+  <modified_date>2026/03/25 12:51:28.914</modified_date>
+  <parameters>
+    </parameters>
+  <actions>
+    <action>
+      <name>Start</name>
+      <description/>
+      <type>SPECIAL</type>
+      <attributes/>
+      <DayOfMonth>1</DayOfMonth>
+      <doNotWaitOnFirstExecution>N</doNotWaitOnFirstExecution>
+      <hour>12</hour>
+      <intervalMinutes>60</intervalMinutes>
+      <intervalSeconds>0</intervalSeconds>
+      <minutes>0</minutes>
+      <repeat>N</repeat>
+      <schedulerType>0</schedulerType>
+      <weekDay>1</weekDay>
+      <parallel>N</parallel>
+      <xloc>96</xloc>
+      <yloc>80</yloc>
+      <attributes_hac/>
+    </action>
+    <action>
+      <name>0046-set-constant-values</name>
+      <description/>
+      <type>PIPELINE</type>
+      <attributes/>
+      <add_date>N</add_date>
+      <add_time>N</add_time>
+      <clear_files>N</clear_files>
+      <clear_rows>N</clear_rows>
+      <create_parent_folder>N</create_parent_folder>
+      <exec_per_row>N</exec_per_row>
+      <filename>${PROJECT_HOME}/0046-set-constant-values.hpl</filename>
+      <loglevel>Basic</loglevel>
+      <parameters>
+        <pass_all_parameters>Y</pass_all_parameters>
+      </parameters>
+      <params_from_previous>N</params_from_previous>
+      <run_configuration>local</run_configuration>
+      <set_append_logfile>N</set_append_logfile>
+      <set_logfile>N</set_logfile>
+      <wait_until_finished>Y</wait_until_finished>
+      <parallel>N</parallel>
+      <xloc>240</xloc>
+      <yloc>80</yloc>
+      <attributes_hac/>
+    </action>
+    <action>
+      <name>0046-set-constant-values-validate UNIT</name>
+      <description/>
+      <type>RunPipelineTests</type>
+      <attributes/>
+      <test_names>
+        <test_name>
+          <name>0046-set-constant-values-validate UNIT</name>
+        </test_name>
+      </test_names>
+      <parallel>N</parallel>
+      <xloc>432</xloc>
+      <yloc>80</yloc>
+      <attributes_hac/>
+    </action>
+  </actions>
+  <hops>
+    <hop>
+      <from>Start</from>
+      <to>0046-set-constant-values</to>
+      <enabled>Y</enabled>
+      <evaluation>Y</evaluation>
+      <unconditional>Y</unconditional>
+    </hop>
+    <hop>
+      <from>0046-set-constant-values</from>
+      <to>0046-set-constant-values-validate UNIT</to>
+      <enabled>Y</enabled>
+      <evaluation>Y</evaluation>
+      <unconditional>N</unconditional>
+    </hop>
+  </hops>
+  <notepads>
+  </notepads>
+  <attributes/>
+</workflow>
diff --git a/integration-tests/mdi/metadata/dataset/golden-set-constant-values-fields.json b/integration-tests/mdi/metadata/dataset/golden-set-constant-values-fields.json
new file mode 100644
index 0000000000..22a3dd474f
--- /dev/null
+++ b/integration-tests/mdi/metadata/dataset/golden-set-constant-values-fields.json
@@ -0,0 +1,40 @@
+{
+  "base_filename": "golden-set-constant-values-fields.csv",
+  "name": "golden-set-constant-values-fields",
+  "description": "",
+  "dataset_fields": [
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "name",
+      "field_format": ""
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "value",
+      "field_format": ""
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "mask",
+      "field_format": ""
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 4,
+      "field_precision": -1,
+      "field_name": "set_empty_string",
+      "field_format": ""
+    }
+  ],
+  "folder_name": ""
+}
\ No newline at end of file
diff --git a/integration-tests/mdi/metadata/dataset/golden-set-constant-values.json b/integration-tests/mdi/metadata/dataset/golden-set-constant-values.json
new file mode 100644
index 0000000000..55bb4d0d6b
--- /dev/null
+++ b/integration-tests/mdi/metadata/dataset/golden-set-constant-values.json
@@ -0,0 +1,16 @@
+{
+  "base_filename": "golden-set-constant-values.csv",
+  "name": "golden-set-constant-values",
+  "description": "",
+  "dataset_fields": [
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 4,
+      "field_precision": -1,
+      "field_name": "usevar",
+      "field_format": ""
+    }
+  ],
+  "folder_name": ""
+}
\ No newline at end of file
diff --git a/integration-tests/mdi/metadata/unit-test/0046-set-constant-values-validate UNIT.json b/integration-tests/mdi/metadata/unit-test/0046-set-constant-values-validate UNIT.json
new file mode 100644
index 0000000000..278ead0859
--- /dev/null
+++ b/integration-tests/mdi/metadata/unit-test/0046-set-constant-values-validate UNIT.json	
@@ -0,0 +1,56 @@
+{
+  "database_replacements": [],
+  "autoOpening": true,
+  "description": "",
+  "persist_filename": "",
+  "test_type": "UNIT_TEST",
+  "variableValues": [],
+  "basePath": "${HOP_UNIT_TESTS_FOLDER}",
+  "golden_data_sets": [
+    {
+      "field_mappings": [
+        {
+          "transform_field": "usevar",
+          "data_set_field": "usevar"
+        }
+      ],
+      "field_order": [
+        "usevar"
+      ],
+      "data_set_name": "golden-set-constant-values",
+      "transform_name": "validate"
+    },
+    {
+      "field_mappings": [
+        {
+          "transform_field": "name",
+          "data_set_field": "name"
+        },
+        {
+          "transform_field": "value",
+          "data_set_field": "value"
+        },
+        {
+          "transform_field": "mask",
+          "data_set_field": "mask"
+        },
+        {
+          "transform_field": "set_empty_string",
+          "data_set_field": "set_empty_string"
+        }
+      ],
+      "field_order": [
+        "name",
+        "value",
+        "mask",
+        "set_empty_string"
+      ],
+      "data_set_name": "golden-set-constant-values-fields",
+      "transform_name": "validate fields"
+    }
+  ],
+  "input_data_sets": [],
+  "name": "0046-set-constant-values-validate UNIT",
+  "trans_test_tweaks": [],
+  "pipeline_filename": "./0046-set-constant-values-validate.hpl"
+}
\ No newline at end of file
diff --git a/plugins/transforms/setvalueconstant/src/main/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstant.java b/plugins/transforms/setvalueconstant/src/main/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstant.java
index 70cf491bd4..3d5b35ba7e 100644
--- a/plugins/transforms/setvalueconstant/src/main/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstant.java
+++ b/plugins/transforms/setvalueconstant/src/main/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstant.java
@@ -30,7 +30,6 @@ import org.apache.hop.pipeline.transform.TransformMeta;
 
 /** Replace Field value by a constant value. */
 public class SetValueConstant extends BaseTransform<SetValueConstantMeta, SetValueConstantData> {
-
   private static final Class<?> PKG = SetValueConstantMeta.class;
 
   public SetValueConstant(
@@ -45,7 +44,6 @@ public class SetValueConstant extends BaseTransform<SetValueConstantMeta, SetVal
 
   @Override
   public boolean processRow() throws HopException {
-
     Object[] r = getRow(); // get row, set busy!
     if (r == null) { // no more input to be expected...
 
@@ -84,27 +82,26 @@ public class SetValueConstant extends BaseTransform<SetValueConstantMeta, SetVal
             }
           }
 
-          data.getFieldnrs()[i] =
-              data.getOutputRowMeta().indexOfValue(meta.getField(i).getFieldName());
+          data.getFieldnrs()[i] = data.getOutputRowMeta().indexOfValue(check.getFieldName());
 
           if (data.getFieldnrs()[i] < 0) {
             logError(
                 BaseMessages.getString(
-                    PKG, "SetValueConstant.Log.CanNotFindField", meta.getField(i).getFieldName()));
+                    PKG, "SetValueConstant.Log.CanNotFindField", check.getFieldName()));
             throw new HopException(
                 BaseMessages.getString(
-                    PKG, "SetValueConstant.Log.CanNotFindField", meta.getField(i).getFieldName()));
+                    PKG, "SetValueConstant.Log.CanNotFindField", check.getFieldName()));
           }
 
-          if (meta.getField(i).isEmptyString()) {
+          if (check.isEmptyString()) {
             // Just set empty string
             data.getRealReplaceByValues()[i] = StringUtil.EMPTY_STRING;
           } else {
             // set specified value
-            if (meta.isUseVars()) {
-              data.getRealReplaceByValues()[i] = resolve(meta.getField(i).getReplaceValue());
+            if (meta.isUsingVariables()) {
+              data.getRealReplaceByValues()[i] = resolve(check.getReplaceValue());
             } else {
-              data.getRealReplaceByValues()[i] = meta.getField(i).getReplaceValue();
+              data.getRealReplaceByValues()[i] = check.getReplaceValue();
             }
           }
         }
@@ -138,13 +135,14 @@ public class SetValueConstant extends BaseTransform<SetValueConstantMeta, SetVal
   private void updateField(Object[] r) throws Exception {
     // Loop through fields
     for (int i = 0; i < data.getFieldnr(); i++) {
+      SetValueConstantMeta.Field field = meta.getFields().get(i);
       // DO CONVERSION OF THE DEFAULT VALUE ...
       // Entered by user
       IValueMeta targetValueMeta = data.getOutputRowMeta().getValueMeta(data.getFieldnrs()[i]);
       IValueMeta sourceValueMeta = data.getConvertRowMeta().getValueMeta(data.getFieldnrs()[i]);
 
-      if (!Utils.isEmpty(meta.getField(i).getReplaceMask())) {
-        sourceValueMeta.setConversionMask(meta.getField(i).getReplaceMask());
+      if (!Utils.isEmpty(field.getReplaceMask())) {
+        sourceValueMeta.setConversionMask(field.getReplaceMask());
       }
 
       sourceValueMeta.setStorageType(IValueMeta.STORAGE_TYPE_NORMAL);
@@ -153,10 +151,4 @@ public class SetValueConstant extends BaseTransform<SetValueConstantMeta, SetVal
       targetValueMeta.setStorageType(IValueMeta.STORAGE_TYPE_NORMAL);
     }
   }
-
-  @Override
-  public boolean init() {
-
-    return super.init();
-  }
 }
diff --git a/plugins/transforms/setvalueconstant/src/main/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantDialog.java b/plugins/transforms/setvalueconstant/src/main/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantDialog.java
index 3576810b78..c8e50f15c7 100644
--- a/plugins/transforms/setvalueconstant/src/main/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantDialog.java
+++ b/plugins/transforms/setvalueconstant/src/main/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantDialog.java
@@ -42,7 +42,6 @@ import org.eclipse.swt.layout.FormData;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.TableItem;
 
 public class SetValueConstantDialog extends BaseTransformDialog {
@@ -56,7 +55,7 @@ public class SetValueConstantDialog extends BaseTransformDialog {
 
   private TableView wFields;
 
-  private ColumnInfo[] colinf;
+  private ColumnInfo[] columnInfos;
 
   private Button wUseVars;
 
@@ -77,7 +76,6 @@ public class SetValueConstantDialog extends BaseTransformDialog {
 
     ModifyListener lsMod = e -> input.setChanged();
     changed = input.hasChanged();
-    ModifyListener oldlsMod = lsMod;
 
     // Use variable?
     Label wlUseVars = new Label(shell, SWT.RIGHT);
@@ -103,47 +101,43 @@ public class SetValueConstantDialog extends BaseTransformDialog {
     PropsUi.setLook(wlFields);
     FormData fdlFields = new FormData();
     fdlFields.left = new FormAttachment(0, 0);
-    fdlFields.top = new FormAttachment(wUseVars, margin);
+    fdlFields.top = new FormAttachment(wlUseVars, margin);
     wlFields.setLayoutData(fdlFields);
 
     int fieldsCols = 4;
-    final int FieldsRows = input.getFields().size();
-    colinf = new ColumnInfo[fieldsCols];
-    colinf[0] =
+    columnInfos = new ColumnInfo[fieldsCols];
+    columnInfos[0] =
         new ColumnInfo(
             BaseMessages.getString(PKG, "SetValueConstantDialog.Fieldname.Column"),
             ColumnInfo.COLUMN_TYPE_CCOMBO,
             new String[] {},
             false);
-    colinf[1] =
+    columnInfos[1] =
         new ColumnInfo(
             BaseMessages.getString(PKG, "SetValueConstantDialog.Value.Column"),
             ColumnInfo.COLUMN_TYPE_TEXT,
             false);
-    colinf[2] =
+    columnInfos[2] =
         new ColumnInfo(
             BaseMessages.getString(PKG, "SetValueConstantDialog.Value.ConversionMask"),
             ColumnInfo.COLUMN_TYPE_CCOMBO,
             Const.getDateFormats());
-    colinf[3] =
+    columnInfos[3] =
         new ColumnInfo(
             BaseMessages.getString(PKG, "SetValueConstantDialog.Value.SetEmptyString"),
             ColumnInfo.COLUMN_TYPE_CCOMBO,
-            new String[] {
-              BaseMessages.getString(PKG, CONST_SYSTEM_COMBO_YES),
-              BaseMessages.getString(PKG, "System.Combo.No")
-            });
+            BaseMessages.getString(PKG, CONST_SYSTEM_COMBO_YES),
+            BaseMessages.getString(PKG, "System.Combo.No"));
 
     wFields =
         new TableView(
             variables,
             shell,
             SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI,
-            colinf,
-            FieldsRows,
-            oldlsMod,
+            columnInfos,
+            input.getFields().size(),
+            lsMod,
             props);
-
     FormData fdFields = new FormData();
     fdFields.left = new FormAttachment(0, 0);
     fdFields.top = new FormAttachment(wlFields, margin);
@@ -154,25 +148,7 @@ public class SetValueConstantDialog extends BaseTransformDialog {
     //
     // Search the fields in the background
     //
-
-    final Runnable runnable =
-        () -> {
-          TransformMeta transformMeta = pipelineMeta.findTransform(transformName);
-          if (transformMeta != null) {
-            try {
-              IRowMeta row = pipelineMeta.getPrevTransformFields(variables, transformMeta);
-
-              // Remember these fields...
-              for (int i = 0; i < row.size(); i++) {
-                inputFields.add(row.getValueMeta(i).getName());
-              }
-              setComboBoxes();
-            } catch (HopException e) {
-              logError(BaseMessages.getString(PKG, "System.Dialog.GetFieldsFailed.Message"));
-            }
-          }
-        };
-    new Thread(runnable).start();
+    new Thread(this::getPreviousFields).start();
 
     getData();
     input.setChanged(changed);
@@ -182,11 +158,28 @@ public class SetValueConstantDialog extends BaseTransformDialog {
     return transformName;
   }
 
+  private void getPreviousFields() {
+    TransformMeta transformMeta = pipelineMeta.findTransform(transformName);
+    if (transformMeta != null) {
+      try {
+        IRowMeta row = pipelineMeta.getPrevTransformFields(variables, transformMeta);
+
+        // Remember these fields...
+        for (int i = 0; i < row.size(); i++) {
+          inputFields.add(row.getValueMeta(i).getName());
+        }
+        setComboBoxes();
+      } catch (HopException e) {
+        logError(BaseMessages.getString(PKG, "System.Dialog.GetFieldsFailed.Message"));
+      }
+    }
+  }
+
   protected void setComboBoxes() {
     // Something was changed in the row.
     //
     String[] fieldNames = ConstUi.sortFieldNames(inputFields);
-    colinf[0].setComboValues(fieldNames);
+    columnInfos[0].setComboValues(fieldNames);
   }
 
   private void get() {
@@ -209,34 +202,20 @@ public class SetValueConstantDialog extends BaseTransformDialog {
 
   /** Copy information from the meta-data input to the dialog fields. */
   public void getData() {
-    wUseVars.setSelection(input.isUseVars());
-    Table table = wFields.table;
-    if (!input.getFields().isEmpty()) {
-      table.removeAll();
-    }
-    for (int i = 0; i < input.getFields().size(); i++) {
-      SetValueConstantMeta.Field field = input.getField(i);
-      TableItem ti = new TableItem(table, SWT.NONE);
-      ti.setText(0, "" + (i + 1));
-      if (field.getFieldName() != null) {
-        ti.setText(1, field.getFieldName());
-      }
-      if (field.getReplaceValue() != null) {
-        ti.setText(2, field.getReplaceValue());
-      }
-      if (field.getReplaceMask() != null) {
-        ti.setText(3, field.getReplaceMask());
-      }
+    wUseVars.setSelection(input.isUsingVariables());
+    wFields.clearAll();
+    for (SetValueConstantMeta.Field field : input.getFields()) {
+      TableItem ti = new TableItem(wFields.table, SWT.NONE);
+      ti.setText(1, Const.NVL(field.getFieldName(), ""));
+      ti.setText(2, Const.NVL(field.getReplaceValue(), ""));
+      ti.setText(3, Const.NVL(field.getReplaceMask(), ""));
       ti.setText(
           4,
           field.isEmptyString()
               ? BaseMessages.getString(PKG, CONST_SYSTEM_COMBO_YES)
               : BaseMessages.getString(PKG, "System.Combo.No"));
     }
-
-    wFields.setRowNums();
-    wFields.removeEmptyRows();
-    wFields.optWidth(true);
+    wFields.optimizeTableView();
   }
 
   private void cancel() {
@@ -251,21 +230,18 @@ public class SetValueConstantDialog extends BaseTransformDialog {
     }
     transformName = wTransformName.getText(); // return value
 
-    input.setUseVars(wUseVars.getSelection());
-    int count = wFields.nrNonEmpty();
-    List<SetValueConstantMeta.Field> fields = new ArrayList<>();
+    input.setUsingVariables(wUseVars.getSelection());
 
-    for (int i = 0; i < count; i++) {
-      TableItem ti = wFields.getNonEmpty(i);
+    input.getFields().clear();
+    for (TableItem item : wFields.getNonEmptyItems()) {
       SetValueConstantMeta.Field field = new SetValueConstantMeta.Field();
-      field.setFieldName(ti.getText(1));
+      field.setFieldName(item.getText(1));
       field.setEmptyString(
-          BaseMessages.getString(PKG, CONST_SYSTEM_COMBO_YES).equalsIgnoreCase(ti.getText(4)));
-      field.setReplaceValue(field.isEmptyString() ? "" : ti.getText(2));
-      field.setReplaceMask(field.isEmptyString() ? "" : ti.getText(3));
-      fields.add(field);
+          BaseMessages.getString(PKG, CONST_SYSTEM_COMBO_YES).equalsIgnoreCase(item.getText(4)));
+      field.setReplaceValue(field.isEmptyString() ? "" : item.getText(2));
+      field.setReplaceMask(field.isEmptyString() ? "" : item.getText(3));
+      input.getFields().add(field);
     }
-    input.setFields(fields);
 
     dispose();
   }
diff --git a/plugins/transforms/setvalueconstant/src/main/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantMeta.java b/plugins/transforms/setvalueconstant/src/main/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantMeta.java
index 1d5273953c..57c874944f 100644
--- a/plugins/transforms/setvalueconstant/src/main/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantMeta.java
+++ b/plugins/transforms/setvalueconstant/src/main/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantMeta.java
@@ -19,28 +19,23 @@ package org.apache.hop.pipeline.transforms.setvalueconstant;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.hop.core.CheckResult;
 import org.apache.hop.core.Const;
 import org.apache.hop.core.ICheckResult;
 import org.apache.hop.core.annotations.Transform;
-import org.apache.hop.core.exception.HopXmlException;
-import org.apache.hop.core.injection.Injection;
-import org.apache.hop.core.injection.InjectionDeep;
-import org.apache.hop.core.injection.InjectionSupported;
 import org.apache.hop.core.row.IRowMeta;
 import org.apache.hop.core.util.Utils;
 import org.apache.hop.core.variables.IVariables;
-import org.apache.hop.core.xml.XmlHandler;
 import org.apache.hop.i18n.BaseMessages;
+import org.apache.hop.metadata.api.HopMetadataProperty;
 import org.apache.hop.metadata.api.IHopMetadataProvider;
 import org.apache.hop.pipeline.PipelineMeta;
 import org.apache.hop.pipeline.transform.BaseTransformMeta;
 import org.apache.hop.pipeline.transform.TransformMeta;
-import org.w3c.dom.Node;
 
-@InjectionSupported(
-    localizationPrefix = "SetValueConstant.Injection.",
-    groups = {"FIELDS", "OPTIONS"})
 @Transform(
     id = "SetValueConstant",
     image = "setvalueconstant.svg",
@@ -49,93 +44,28 @@ import org.w3c.dom.Node;
     categoryDescription = "i18n:org.apache.hop.pipeline.transform:BaseTransform.Category.Transform",
     keywords = "i18n::SetValueConstantMeta.keyword",
     documentationUrl = "/pipeline/transforms/setvalueconstant.html")
+@Getter
+@Setter
 public class SetValueConstantMeta
     extends BaseTransformMeta<SetValueConstant, SetValueConstantData> {
   private static final Class<?> PKG = SetValueConstantMeta.class;
-  public static final String CONST_SPACES = "        ";
 
-  @InjectionDeep private List<Field> fields = new ArrayList<>();
+  @HopMetadataProperty(
+      key = "field",
+      groupKey = "fields",
+      injectionGroupKey = "FIELDS",
+      injectionGroupDescription = "SetValueConstant.Injection.FIELDS")
+  private List<Field> fields;
 
-  public Field getField(int i) {
-    return fields.get(i);
-  }
-
-  public List<Field> getFields() {
-    return fields;
-  }
-
-  public void setFields(List<Field> fields) {
-    this.fields = fields;
-  }
-
-  @Injection(name = "USE_VARIABLE", group = "OPTIONS")
-  private boolean usevar;
+  @HopMetadataProperty(
+      key = "usevar",
+      injectionKey = "USE_VARIABLE",
+      injectionKeyDescription = "SetValueConstant.Injection.USE_VARIABLE")
+  private boolean usingVariables;
 
   public SetValueConstantMeta() {
-    super(); // allocate BaseTransformMeta
-  }
-
-  @Override
-  public void loadXml(Node transformNode, IHopMetadataProvider metadataProvider)
-      throws HopXmlException {
-    readData(transformNode, metadataProvider);
-  }
-
-  public void setUseVars(boolean usevar) {
-    this.usevar = usevar;
-  }
-
-  public boolean isUseVars() {
-    return usevar;
-  }
-
-  private void readData(Node transformNode, IHopMetadataProvider metadataProvider)
-      throws HopXmlException {
-    try {
-      usevar = "Y".equalsIgnoreCase(XmlHandler.getTagValue(transformNode, "usevar"));
-      Node fields = XmlHandler.getSubNode(transformNode, "fields");
-      int nrFields = XmlHandler.countNodes(fields, "field");
-      List<Field> fieldList = new ArrayList<>();
-      for (int i = 0; i < nrFields; i++) {
-        Node fnode = XmlHandler.getSubNodeByNr(fields, "field", i);
-        Field field = new Field();
-        field.setFieldName(XmlHandler.getTagValue(fnode, "name"));
-        field.setReplaceValue(XmlHandler.getTagValue(fnode, "value"));
-        field.setReplaceMask(XmlHandler.getTagValue(fnode, "mask"));
-        String emptyString = XmlHandler.getTagValue(fnode, "set_empty_string");
-        field.setEmptyString(!Utils.isEmpty(emptyString) && "Y".equalsIgnoreCase(emptyString));
-        fieldList.add(field);
-      }
-      setFields(fieldList);
-    } catch (Exception e) {
-      throw new HopXmlException(
-          "It was not possible to load the metadata for this transform from XML", e);
-    }
-  }
-
-  @Override
-  public String getXml() {
-    StringBuilder retval = new StringBuilder();
-    retval.append("   " + XmlHandler.addTagValue("usevar", usevar));
-    retval.append("    <fields>" + Const.CR);
-    fields.forEach(
-        field -> {
-          retval.append("      <field>" + Const.CR);
-          retval.append(CONST_SPACES + XmlHandler.addTagValue("name", field.getFieldName()));
-          retval.append(CONST_SPACES + XmlHandler.addTagValue("value", field.getReplaceValue()));
-          retval.append(CONST_SPACES + XmlHandler.addTagValue("mask", field.getReplaceMask()));
-          retval.append(
-              CONST_SPACES + XmlHandler.addTagValue("set_empty_string", field.isEmptyString()));
-          retval.append("        </field>" + Const.CR);
-        });
-    retval.append("      </fields>" + Const.CR);
-
-    return retval.toString();
-  }
-
-  @Override
-  public void setDefault() {
-    usevar = false;
+    super();
+    this.fields = new ArrayList<>();
   }
 
   @Override
@@ -226,58 +156,58 @@ public class SetValueConstantMeta
     return true;
   }
 
+  @Getter
+  @Setter
   public static class Field {
-
-    @Injection(name = "FIELD_NAME", group = "FIELDS")
+    @HopMetadataProperty(
+        key = "name",
+        injectionKey = "FIELD_NAME",
+        injectionKeyDescription = "SetValueConstant.Injection.FIELD_NAME")
     private String fieldName;
 
-    @Injection(name = "REPLACE_VALUE", group = "FIELDS")
+    @HopMetadataProperty(
+        key = "value",
+        injectionKey = "REPLACE_VALUE",
+        injectionKeyDescription = "SetValueConstant.Injection.REPLACE_VALUE")
     private String replaceValue;
 
-    @Injection(name = "REPLACE_MASK", group = "FIELDS")
+    @HopMetadataProperty(
+        key = "mask",
+        injectionKey = "REPLACE_MASK",
+        injectionKeyDescription = "SetValueConstant.Injection.REPLACE_MASK")
     private String replaceMask;
 
-    @Injection(name = "EMPTY_STRING", group = "FIELDS")
-    private boolean setEmptyString;
+    @HopMetadataProperty(
+        key = "set_empty_string",
+        injectionKey = "EMPTY_STRING",
+        injectionKeyDescription = "SetValueConstant.Injection.EMPTY_STRING")
+    private boolean emptyString;
 
-    public String getFieldName() {
-      return fieldName;
-    }
+    public Field() {}
 
-    public void setFieldName(String fieldName) {
-      this.fieldName = fieldName;
+    public Field(Field f) {
+      this();
+      this.fieldName = f.fieldName;
+      this.replaceValue = f.replaceValue;
+      this.replaceMask = f.replaceMask;
+      this.emptyString = f.emptyString;
     }
 
-    public String getReplaceValue() {
-      return replaceValue;
-    }
-
-    public void setReplaceValue(String replaceValue) {
-      this.replaceValue = replaceValue;
-    }
-
-    public String getReplaceMask() {
-      return replaceMask;
-    }
-
-    public void setReplaceMask(String replaceMask) {
-      this.replaceMask = replaceMask;
-    }
-
-    public boolean isEmptyString() {
-      return setEmptyString;
-    }
-
-    public void setEmptyString(boolean setEmptyString) {
-      this.setEmptyString = setEmptyString;
+    @Override
+    public boolean equals(Object o) {
+      if (o == null || getClass() != o.getClass()) {
+        return false;
+      }
+      Field field = (Field) o;
+      return emptyString == field.emptyString
+          && Objects.equals(fieldName, field.fieldName)
+          && Objects.equals(replaceValue, field.replaceValue)
+          && Objects.equals(replaceMask, field.replaceMask);
     }
 
     @Override
-    public boolean equals(Object obj) {
-      return fieldName.equals(((Field) obj).getFieldName())
-          && replaceValue.equals(((Field) obj).getReplaceValue())
-          && replaceMask.equals(((Field) obj).getReplaceMask())
-          && setEmptyString == ((Field) obj).isEmptyString();
+    public int hashCode() {
+      return Objects.hash(fieldName, replaceValue, replaceMask, emptyString);
     }
   }
 }
diff --git a/plugins/transforms/setvalueconstant/src/test/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantMetaInjectionTest.java b/plugins/transforms/setvalueconstant/src/test/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantMetaInjectionTest.java
deleted file mode 100644
index 3304787388..0000000000
--- a/plugins/transforms/setvalueconstant/src/test/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantMetaInjectionTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.hop.pipeline.transforms.setvalueconstant;
-
-import org.apache.hop.core.injection.BaseMetadataInjectionTestJunit5;
-import org.apache.hop.junit.rules.RestoreHopEngineEnvironmentExtension;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-class SetValueConstantMetaInjectionTest
-    extends BaseMetadataInjectionTestJunit5<SetValueConstantMeta> {
-  @RegisterExtension
-  static RestoreHopEngineEnvironmentExtension env = new RestoreHopEngineEnvironmentExtension();
-
-  @BeforeEach
-  void setup() throws Exception {
-    setup(new SetValueConstantMeta());
-  }
-
-  @Test
-  void test() throws Exception {
-    check("FIELD_NAME", () -> meta.getField(0).getFieldName());
-    check("REPLACE_VALUE", () -> meta.getField(0).getReplaceValue());
-    check("REPLACE_MASK", () -> meta.getField(0).getReplaceMask());
-    check("EMPTY_STRING", () -> meta.getField(0).isEmptyString());
-    check("USE_VARIABLE", () -> meta.isUseVars());
-  }
-}
diff --git a/plugins/transforms/setvalueconstant/src/test/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantMetaTest.java b/plugins/transforms/setvalueconstant/src/test/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantMetaTest.java
index fac9d21e66..ca270905a7 100644
--- a/plugins/transforms/setvalueconstant/src/test/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantMetaTest.java
+++ b/plugins/transforms/setvalueconstant/src/test/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantMetaTest.java
@@ -16,100 +16,33 @@
  */
 package org.apache.hop.pipeline.transforms.setvalueconstant;
 
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.UUID;
-import org.apache.hop.core.HopEnvironment;
-import org.apache.hop.core.exception.HopException;
-import org.apache.hop.core.plugins.PluginRegistry;
-import org.apache.hop.junit.rules.RestoreHopEngineEnvironmentExtension;
-import org.apache.hop.pipeline.transform.ITransformMeta;
-import org.apache.hop.pipeline.transforms.loadsave.LoadSaveTester;
-import org.apache.hop.pipeline.transforms.loadsave.initializer.IInitializer;
-import org.apache.hop.pipeline.transforms.loadsave.validator.IFieldLoadSaveValidator;
-import org.apache.hop.pipeline.transforms.loadsave.validator.ListLoadSaveValidator;
-import org.junit.jupiter.api.BeforeEach;
+import org.apache.commons.lang.StringUtils;
+import org.apache.hop.pipeline.transform.TransformSerializationTestUtil;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-class SetValueConstantMetaTest implements IInitializer<ITransformMeta> {
-  @RegisterExtension
-  static RestoreHopEngineEnvironmentExtension env = new RestoreHopEngineEnvironmentExtension();
-
-  LoadSaveTester loadSaveTester;
-  Class<SetValueConstantMeta> testMetaClass = SetValueConstantMeta.class;
-
-  @BeforeEach
-  void setUpLoadSave() throws Exception {
-    HopEnvironment.init();
-    PluginRegistry.init();
-    List<String> attributes = Arrays.asList("fields", "usevar");
-
-    Map<String, String> getterMap =
-        new HashMap<>() {
-          {
-            put("fields", "getFields");
-            put("usevar", "isUseVars");
-          }
-        };
-    Map<String, String> setterMap =
-        new HashMap<>() {
-          {
-            put("fields", "setFields");
-            put("usevar", "setUseVars");
-          }
-        };
-
-    Map<String, IFieldLoadSaveValidator<?>> attrValidatorMap = new HashMap<>();
-    attrValidatorMap.put(
-        "fields", new ListLoadSaveValidator<>(new SetValueConstantMetaFieldLoadSaveValidator(), 5));
-    Map<String, IFieldLoadSaveValidator<?>> typeValidatorMap = new HashMap<>();
-
-    loadSaveTester =
-        new LoadSaveTester(
-            testMetaClass,
-            attributes,
-            getterMap,
-            setterMap,
-            attrValidatorMap,
-            typeValidatorMap,
-            this);
-  }
-
-  @Override
-  public void modify(ITransformMeta someMeta) {
-    // Do nothing
-  }
 
+class SetValueConstantMetaTest {
   @Test
-  void testSerialization() throws HopException {
-    loadSaveTester.testSerialization();
-  }
-
-  public class SetValueConstantMetaFieldLoadSaveValidator
-      implements IFieldLoadSaveValidator<SetValueConstantMeta.Field> {
-    final Random rand = new Random();
-
-    @Override
-    public SetValueConstantMeta.Field getTestObject() {
-      SetValueConstantMeta.Field field = new SetValueConstantMeta.Field();
-      field.setReplaceMask(UUID.randomUUID().toString());
-      field.setReplaceValue(UUID.randomUUID().toString());
-      field.setEmptyString(rand.nextBoolean());
-      field.setFieldName(UUID.randomUUID().toString());
-      return field;
-    }
-
-    @Override
-    public boolean validateTestObject(SetValueConstantMeta.Field testObject, Object actual) {
-      if (!(actual instanceof SetValueConstantMeta.Field)) {
-        return false;
-      }
-      SetValueConstantMeta.Field actualInput = (SetValueConstantMeta.Field) actual;
-      return (actualInput.equals(testObject));
-    }
+  void testSerializationRoundTrip() throws Exception {
+    SetValueConstantMeta meta =
+        TransformSerializationTestUtil.testSerialization(
+            "/set-constant-values.xml", SetValueConstantMeta.class);
+
+    Assertions.assertTrue(meta.isUsingVariables());
+    Assertions.assertEquals(3, meta.getFields().size());
+    SetValueConstantMeta.Field f = meta.getFields().getFirst();
+    Assertions.assertEquals("f1", f.getFieldName());
+    Assertions.assertEquals("const1", f.getReplaceValue());
+    Assertions.assertFalse(f.isEmptyString());
+    f = meta.getFields().get(1);
+    Assertions.assertEquals("f2", f.getFieldName());
+    Assertions.assertEquals("2026/03/25", f.getReplaceValue());
+    Assertions.assertEquals("yyyy/MM/dd", f.getReplaceMask());
+    Assertions.assertFalse(f.isEmptyString());
+    f = meta.getFields().getLast();
+    Assertions.assertEquals("f3", f.getFieldName());
+    Assertions.assertTrue(StringUtils.isEmpty(f.getReplaceValue()));
+    Assertions.assertTrue(StringUtils.isEmpty(f.getReplaceMask()));
+    Assertions.assertTrue(f.isEmptyString());
   }
 }
diff --git a/plugins/transforms/setvalueconstant/src/test/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantTest.java b/plugins/transforms/setvalueconstant/src/test/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantTest.java
index 8a788a18e4..05a86a35e7 100644
--- a/plugins/transforms/setvalueconstant/src/test/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantTest.java
+++ b/plugins/transforms/setvalueconstant/src/test/java/org/apache/hop/pipeline/transforms/setvalueconstant/SetValueConstantTest.java
@@ -79,7 +79,6 @@ class SetValueConstantTest {
     field.setReplaceValue("Replace Value");
 
     doReturn(Collections.singletonList(field)).when(smh.iTransformMeta).getFields();
-    doReturn(field).when(smh.iTransformMeta).getField(0);
     doReturn(rowMeta).when(smh.iTransformData).getConvertRowMeta();
     doReturn(rowMeta).when(smh.iTransformData).getOutputRowMeta();
     doReturn(1).when(smh.iTransformData).getFieldnr();
diff --git a/plugins/transforms/setvalueconstant/src/test/resources/set-constant-values.xml b/plugins/transforms/setvalueconstant/src/test/resources/set-constant-values.xml
new file mode 100644
index 0000000000..02d4a01156
--- /dev/null
+++ b/plugins/transforms/setvalueconstant/src/test/resources/set-constant-values.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~       http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<transform>
+    <fields>
+        <field>
+            <mask/>
+            <name>f1</name>
+            <set_empty_string>N</set_empty_string>
+            <value>const1</value>
+        </field>
+        <field>
+            <mask>yyyy/MM/dd</mask>
+            <name>f2</name>
+            <set_empty_string>N</set_empty_string>
+            <value>2026/03/25</value>
+        </field>
+        <field>
+            <mask/>
+            <name>f3</name>
+            <set_empty_string>Y</set_empty_string>
+            <value/>
+        </field>
+    </fields>
+    <usevar>Y</usevar>
+</transform>