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

hansva pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-hop.git


The following commit(s) were added to refs/heads/master by this push:
     new e768f2f  HOP-3122 - Migrate Update transform to use 
HopMetadataProperty for MDI and metadata generation HOP-3109 - Unable to set 
connection name by using a variable on Update transform
     new add6d5f  Merge pull request #1037 from sramazzina/UPDATE-TR-CHANGES
e768f2f is described below

commit e768f2faf04d415eca016a56f2634252e8b81da8
Author: sergio.ramazzina <[email protected]>
AuthorDate: Fri Sep 3 17:54:06 2021 +0200

    HOP-3122 - Migrate Update transform to use HopMetadataProperty for MDI and 
metadata generation
    HOP-3109 - Unable to set connection name by using a variable on Update 
transform
---
 .../hop/pipeline/transforms/update/Update.java     | 149 ++++---
 .../hop/pipeline/transforms/update/UpdateData.java |   1 +
 .../pipeline/transforms/update/UpdateDialog.java   | 105 ++---
 .../pipeline/transforms/update/UpdateField.java    |  75 ++++
 .../pipeline/transforms/update/UpdateKeyField.java | 109 +++++
 .../transforms/update/UpdateLookupField.java       | 110 +++++
 .../hop/pipeline/transforms/update/UpdateMeta.java | 479 +++++++--------------
 .../update/messages/messages_en_US.properties      |  35 +-
 ..._en_US.properties => messages_it_IT.properties} |  69 +--
 .../transforms/update/UpdateMetaInjectionTest.java |  17 -
 .../pipeline/transforms/update/UpdateMetaTest.java | 292 +++++++++----
 .../dialog/messages/messages_en_US.properties      |   2 +-
 12 files changed, 851 insertions(+), 592 deletions(-)

diff --git 
a/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/Update.java
 
b/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/Update.java
index 89dc2b8..d1d559e 100644
--- 
a/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/Update.java
+++ 
b/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/Update.java
@@ -24,9 +24,9 @@ import org.apache.hop.core.database.DatabaseMeta;
 import org.apache.hop.core.exception.HopDatabaseException;
 import org.apache.hop.core.exception.HopException;
 import org.apache.hop.core.exception.HopTransformException;
+import org.apache.hop.core.row.RowMeta;
 import org.apache.hop.core.row.IRowMeta;
 import org.apache.hop.core.row.IValueMeta;
-import org.apache.hop.core.row.RowMeta;
 import org.apache.hop.core.util.Utils;
 import org.apache.hop.i18n.BaseMessages;
 import org.apache.hop.pipeline.Pipeline;
@@ -185,7 +185,7 @@ public class Update extends BaseTransform<UpdateMeta, 
UpdateData>
                   + data.lookupParameterRowMeta.getString(lookupRow));
         }
         data.db.setValues(data.updateParameterRowMeta, updateRow, 
data.prepStatementUpdate);
-        data.db.insertRow(data.prepStatementUpdate, meta.useBatchUpdate(), 
true);
+        data.db.insertRow(data.prepStatementUpdate, meta.isUseBatchUpdate(), 
true);
         incrementLinesUpdated();
       } else {
         incrementLinesSkipped();
@@ -200,7 +200,6 @@ public class Update extends BaseTransform<UpdateMeta, 
UpdateData>
     return outputRow;
   }
 
-  @Override
   public boolean processRow() throws HopException {
 
     boolean sendToErrorRow = false;
@@ -222,7 +221,7 @@ public class Update extends BaseTransform<UpdateMeta, 
UpdateData>
 
       data.schemaTable =
           meta.getDatabaseMeta()
-              .getQuotedSchemaTableCombination(this, meta.getSchemaName(), 
meta.getTableName());
+              .getQuotedSchemaTableCombination(this, 
meta.getLookupField().getSchemaName(), meta.getLookupField().getTableName());
 
       // lookup the values!
       if (log.isDetailed()) {
@@ -230,44 +229,45 @@ public class Update extends BaseTransform<UpdateMeta, 
UpdateData>
             BaseMessages.getString(PKG, "Update.Log.CheckingRow") + 
getInputRowMeta().getString(r));
       }
 
-      ArrayList<Integer> keynrs = new ArrayList<>(meta.getKeyStream().length);
-      ArrayList<Integer> keynrs2 = new ArrayList<>(meta.getKeyStream().length);
+      ArrayList<Integer> keynrs = new 
ArrayList<>(meta.getLookupField().getLookupKeys().size());
+      ArrayList<Integer> keynrs2 = new 
ArrayList<>(meta.getLookupField().getLookupKeys().size());
 
-      for (int i = 0; i < meta.getKeyStream().length; i++) {
-        int keynr = getInputRowMeta().indexOfValue(meta.getKeyStream()[i]);
+      for (int i = 0; i < meta.getLookupField().getLookupKeys().size(); i++) {
+        UpdateKeyField keyItem = meta.getLookupField().getLookupKeys().get(i);
+        int keynr = getInputRowMeta().indexOfValue(keyItem.getKeyStream());
 
         if (keynr < 0
             && // couldn't find field!
-            !"IS NULL".equalsIgnoreCase(meta.getKeyCondition()[i])
+            !"IS NULL".equalsIgnoreCase(keyItem.getKeyCondition())
             && // No field needed!
-            !"IS NOT NULL".equalsIgnoreCase(meta.getKeyCondition()[i]) // No 
field needed!
+            !"IS NOT NULL".equalsIgnoreCase(keyItem.getKeyCondition()) // No 
field needed!
         ) {
           throw new HopTransformException(
               BaseMessages.getString(
-                  PKG, "Update.Exception.FieldRequired", 
meta.getKeyStream()[i]));
+                  PKG, "Update.Exception.FieldRequired", 
keyItem.getKeyStream()));
         }
         keynrs.add(keynr);
 
         // this operator needs two bindings
-        if ("= ~NULL".equalsIgnoreCase(meta.getKeyCondition()[i])) {
+        if ("= ~NULL".equalsIgnoreCase(keyItem.getKeyCondition())) {
           keynrs.add(keynr);
           keynrs2.add(-1);
         }
 
-        int keynr2 = getInputRowMeta().indexOfValue(meta.getKeyStream2()[i]);
+        int keynr2 = getInputRowMeta().indexOfValue(keyItem.getKeyStream2());
         if (keynr2 < 0
             && // couldn't find field!
-            "BETWEEN".equalsIgnoreCase(meta.getKeyCondition()[i]) // 2 fields 
needed!
+            "BETWEEN".equalsIgnoreCase(keyItem.getKeyCondition()) // 2 fields 
needed!
         ) {
           throw new HopTransformException(
               BaseMessages.getString(
-                  PKG, "Update.Exception.FieldRequired", 
meta.getKeyStream2()[i]));
+                  PKG, "Update.Exception.FieldRequired", 
keyItem.getKeyStream2()));
         }
         keynrs2.add(keynr2);
 
         if (log.isDebug()) {
           logDebug(
-              BaseMessages.getString(PKG, "Update.Log.FieldHasDataNumbers", 
meta.getKeyStream()[i])
+              BaseMessages.getString(PKG, "Update.Log.FieldHasDataNumbers", 
keyItem.getKeyStream())
                   + ""
                   + keynrs.get(keynrs.size() - 1));
         }
@@ -278,19 +278,20 @@ public class Update extends BaseTransform<UpdateMeta, 
UpdateData>
 
       // ICache the position of the compare fields in Row row
       //
-      data.valuenrs = new int[meta.getUpdateLookup().length];
-      for (int i = 0; i < meta.getUpdateLookup().length; i++) {
-        data.valuenrs[i] = 
getInputRowMeta().indexOfValue(meta.getUpdateStream()[i]);
+      data.valuenrs = new int[meta.getLookupField().getUpdateFields().size()];
+      for (int i = 0; i < meta.getLookupField().getUpdateFields().size(); i++) 
{
+        UpdateField fieldItem = meta.getLookupField().getUpdateFields().get(i);
+        data.valuenrs[i] = 
getInputRowMeta().indexOfValue(fieldItem.getUpdateStream());
         if (data.valuenrs[i] < 0) { // couldn't find field!
 
           throw new HopTransformException(
               BaseMessages.getString(
-                  PKG, "Update.Exception.FieldRequired", 
meta.getUpdateStream()[i]));
+                  PKG, "Update.Exception.FieldRequired", 
fieldItem.getUpdateStream()));
         }
         if (log.isDebug()) {
           logDebug(
               BaseMessages.getString(
-                      PKG, "Update.Log.FieldHasDataNumbers", 
meta.getUpdateStream()[i])
+                      PKG, "Update.Log.FieldHasDataNumbers", 
fieldItem.getUpdateStream())
                   + ""
                   + data.valuenrs[i]);
         }
@@ -299,22 +300,23 @@ public class Update extends BaseTransform<UpdateMeta, 
UpdateData>
         // We skip lookup
         // but we need fields for update
         data.lookupParameterRowMeta = new RowMeta();
-        for (int i = 0; i < meta.getKeyLookup().length; i++) {
-          if ("BETWEEN".equalsIgnoreCase(meta.getKeyCondition()[i])) {
+        for (int i = 0; i < meta.getLookupField().getLookupKeys().size(); i++) 
{
+          UpdateKeyField keyItem = 
meta.getLookupField().getLookupKeys().get(i);
+          if ("BETWEEN".equalsIgnoreCase(keyItem.getKeyCondition())) {
             data.lookupParameterRowMeta.addValueMeta(
-                getInputRowMeta().searchValueMeta(meta.getKeyStream()[i]));
+                getInputRowMeta().searchValueMeta(keyItem.getKeyStream()));
             data.lookupParameterRowMeta.addValueMeta(
-                getInputRowMeta().searchValueMeta(meta.getKeyStream2()[i]));
+                getInputRowMeta().searchValueMeta(keyItem.getKeyStream2()));
           } else {
-            if ("= ~NULL".equalsIgnoreCase(meta.getKeyCondition()[i])) {
+            if ("= ~NULL".equalsIgnoreCase(keyItem.getKeyCondition())) {
               data.lookupParameterRowMeta.addValueMeta(
-                  getInputRowMeta().searchValueMeta(meta.getKeyStream()[i]));
+                  getInputRowMeta().searchValueMeta(keyItem.getKeyStream()));
               data.lookupParameterRowMeta.addValueMeta(
-                  
getInputRowMeta().searchValueMeta(meta.getKeyStream()[i]).clone());
-            } else if (!"IS NULL".equalsIgnoreCase(meta.getKeyCondition()[i])
-                && !"IS NOT NULL".equalsIgnoreCase(meta.getKeyCondition()[i])) 
{
+                  
getInputRowMeta().searchValueMeta(keyItem.getKeyStream()).clone());
+            } else if (!"IS NULL".equalsIgnoreCase(keyItem.getKeyCondition())
+                && !"IS NOT NULL".equalsIgnoreCase(keyItem.getKeyCondition())) 
{
               data.lookupParameterRowMeta.addValueMeta(
-                  getInputRowMeta().searchValueMeta(meta.getKeyStream()[i]));
+                  getInputRowMeta().searchValueMeta(keyItem.getKeyStream()));
             }
           }
         }
@@ -364,33 +366,36 @@ public class Update extends BaseTransform<UpdateMeta, 
UpdateData>
 
     String sql = "SELECT ";
 
-    for (int i = 0; i < meta.getUpdateLookup().length; i++) {
+    for (int i = 0; i < meta.getLookupField().getUpdateFields().size(); i++) {
+      UpdateField fieldItem = meta.getLookupField().getUpdateFields().get(i);
+
       if (i != 0) {
         sql += ", ";
       }
-      sql += databaseMeta.quoteField(meta.getUpdateLookup()[i]);
-      
data.lookupReturnRowMeta.addValueMeta(rowMeta.searchValueMeta(meta.getUpdateStream()[i]));
+      sql += databaseMeta.quoteField(fieldItem.getUpdateLookup());
+      
data.lookupReturnRowMeta.addValueMeta(rowMeta.searchValueMeta(fieldItem.getUpdateStream()));
     }
 
     sql += " FROM " + data.schemaTable + " WHERE ";
 
-    for (int i = 0; i < meta.getKeyLookup().length; i++) {
+    for (int i = 0; i < meta.getLookupField().getLookupKeys().size(); i++) {
+      UpdateKeyField keyItem = meta.getLookupField().getLookupKeys().get(i);
       if (i != 0) {
         sql += " AND ";
       }
 
       sql += " ( ( ";
 
-      sql += databaseMeta.quoteField(meta.getKeyLookup()[i]);
-      if ("BETWEEN".equalsIgnoreCase(meta.getKeyCondition()[i])) {
+      sql += databaseMeta.quoteField(keyItem.getKeyLookup());
+      if ("BETWEEN".equalsIgnoreCase(keyItem.getKeyCondition())) {
         sql += " BETWEEN ? AND ? ";
-        
data.lookupParameterRowMeta.addValueMeta(rowMeta.searchValueMeta(meta.getKeyStream()[i]));
-        
data.lookupParameterRowMeta.addValueMeta(rowMeta.searchValueMeta(meta.getKeyStream2()[i]));
+        
data.lookupParameterRowMeta.addValueMeta(rowMeta.searchValueMeta(keyItem.getKeyStream()));
+        
data.lookupParameterRowMeta.addValueMeta(rowMeta.searchValueMeta(keyItem.getKeyStream2()));
       } else {
-        if ("IS NULL".equalsIgnoreCase(meta.getKeyCondition()[i])
-            || "IS NOT NULL".equalsIgnoreCase(meta.getKeyCondition()[i])) {
-          sql += " " + meta.getKeyCondition()[i] + " ";
-        } else if ("= ~NULL".equalsIgnoreCase(meta.getKeyCondition()[i])) {
+        if ("IS NULL".equalsIgnoreCase(keyItem.getKeyCondition())
+            || "IS NOT NULL".equalsIgnoreCase(keyItem.getKeyCondition())) {
+          sql += " " + keyItem.getKeyCondition() + " ";
+        } else if ("= ~NULL".equalsIgnoreCase(keyItem.getKeyCondition())) {
 
           sql += " IS NULL AND ";
 
@@ -400,16 +405,16 @@ public class Update extends BaseTransform<UpdateMeta, 
UpdateData>
             sql += "? IS NULL";
           }
           // null check
-          
data.lookupParameterRowMeta.addValueMeta(rowMeta.searchValueMeta(meta.getKeyStream()[i]));
-          sql += " ) OR ( " + databaseMeta.quoteField(meta.getKeyLookup()[i]) 
+ " = ?";
+          
data.lookupParameterRowMeta.addValueMeta(rowMeta.searchValueMeta(keyItem.getKeyStream()));
+          sql += " ) OR ( " + databaseMeta.quoteField(keyItem.getKeyLookup()) 
+ " = ?";
           // equality check, cloning so auto-rename because of adding same 
fieldname does not cause
           // problems
           data.lookupParameterRowMeta.addValueMeta(
-              rowMeta.searchValueMeta(meta.getKeyStream()[i]).clone());
+              rowMeta.searchValueMeta(keyItem.getKeyStream()).clone());
 
         } else {
-          sql += " " + meta.getKeyCondition()[i] + " ? ";
-          
data.lookupParameterRowMeta.addValueMeta(rowMeta.searchValueMeta(meta.getKeyStream()[i]));
+          sql += " " + keyItem.getKeyCondition() + " ? ";
+          
data.lookupParameterRowMeta.addValueMeta(rowMeta.searchValueMeta(keyItem.getKeyStream()));
         }
       }
       sql += " ) ) ";
@@ -435,31 +440,37 @@ public class Update extends BaseTransform<UpdateMeta, 
UpdateData>
     String sql = "UPDATE " + data.schemaTable + Const.CR;
     sql += "SET ";
 
-    for (int i = 0; i < meta.getUpdateLookup().length; i++) {
+    for (int i = 0; i < meta.getLookupField().getUpdateFields().size(); i++) {
+
+      UpdateField fieldItem = meta.getLookupField().getUpdateFields().get(i);
+
       if (i != 0) {
         sql += ",   ";
       }
-      sql += databaseMeta.quoteField(meta.getUpdateLookup()[i]);
+      sql += databaseMeta.quoteField(fieldItem.getUpdateLookup());
       sql += " = ?" + Const.CR;
-      
data.updateParameterRowMeta.addValueMeta(rowMeta.searchValueMeta(meta.getUpdateStream()[i]));
+      
data.updateParameterRowMeta.addValueMeta(rowMeta.searchValueMeta(fieldItem.getUpdateStream()));
     }
 
     sql += "WHERE ";
 
-    for (int i = 0; i < meta.getKeyLookup().length; i++) {
+    for (int i = 0; i < meta.getLookupField().getLookupKeys().size(); i++) {
+
+      UpdateKeyField keyItem = meta.getLookupField().getLookupKeys().get(i);
+
       if (i != 0) {
         sql += "AND   ";
       }
       sql += " ( ( ";
-      sql += databaseMeta.quoteField(meta.getKeyLookup()[i]);
-      if ("BETWEEN".equalsIgnoreCase(meta.getKeyCondition()[i])) {
+      sql += databaseMeta.quoteField(keyItem.getKeyLookup());
+      if ("BETWEEN".equalsIgnoreCase(keyItem.getKeyCondition())) {
         sql += " BETWEEN ? AND ? ";
-        
data.updateParameterRowMeta.addValueMeta(rowMeta.searchValueMeta(meta.getKeyStream()[i]));
-        
data.updateParameterRowMeta.addValueMeta(rowMeta.searchValueMeta(meta.getKeyStream2()[i]));
-      } else if ("IS NULL".equalsIgnoreCase(meta.getKeyCondition()[i])
-          || "IS NOT NULL".equalsIgnoreCase(meta.getKeyCondition()[i])) {
-        sql += " " + meta.getKeyCondition()[i] + " ";
-      } else if ("= ~NULL".equalsIgnoreCase(meta.getKeyCondition()[i])) {
+        
data.updateParameterRowMeta.addValueMeta(rowMeta.searchValueMeta(keyItem.getKeyStream()));
+        
data.updateParameterRowMeta.addValueMeta(rowMeta.searchValueMeta(keyItem.getKeyStream2()));
+      } else if ("IS NULL".equalsIgnoreCase(keyItem.getKeyCondition())
+          || "IS NOT NULL".equalsIgnoreCase(keyItem.getKeyCondition())) {
+        sql += " " + keyItem.getKeyCondition() + " ";
+      } else if ("= ~NULL".equalsIgnoreCase(keyItem.getKeyCondition())) {
 
         sql += " IS NULL AND ";
 
@@ -469,16 +480,16 @@ public class Update extends BaseTransform<UpdateMeta, 
UpdateData>
           sql += "? IS NULL";
         }
         // null check
-        
data.updateParameterRowMeta.addValueMeta(rowMeta.searchValueMeta(meta.getKeyStream()[i]));
-        sql += " ) OR ( " + databaseMeta.quoteField(meta.getKeyLookup()[i]) + 
" = ?";
+        
data.updateParameterRowMeta.addValueMeta(rowMeta.searchValueMeta(keyItem.getKeyStream()));
+        sql += " ) OR ( " + databaseMeta.quoteField(keyItem.getKeyLookup()) + 
" = ?";
         // equality check, cloning so auto-rename because of adding same 
fieldname does not cause
         // problems
         data.updateParameterRowMeta.addValueMeta(
-            rowMeta.searchValueMeta(meta.getKeyStream()[i]).clone());
+            rowMeta.searchValueMeta(keyItem.getKeyStream()).clone());
 
       } else {
-        sql += " " + meta.getKeyCondition()[i] + " ? ";
-        
data.updateParameterRowMeta.addValueMeta(rowMeta.searchValueMeta(meta.getKeyStream()[i]));
+        sql += " " + keyItem.getKeyCondition() + " ? ";
+        
data.updateParameterRowMeta.addValueMeta(rowMeta.searchValueMeta(keyItem.getKeyStream()));
       }
       sql += " ) ) ";
     }
@@ -494,14 +505,16 @@ public class Update extends BaseTransform<UpdateMeta, 
UpdateData>
     }
   }
 
-  @Override
   public boolean init() {
 
     if (super.init()) {
-      if (meta.getDatabaseMeta() == null) {
+      if (meta.getConnection() == null) {
         logError(BaseMessages.getString(PKG, "Update.Init.ConnectionMissing", 
getTransformName()));
         return false;
       }
+      
meta.setDatabaseMeta(getPipelineMeta().findDatabase(meta.getConnection(), 
variables));
+
+      // TODO DatabaseMeta
       data.db = new Database(this, this, meta.getDatabaseMeta());
       try {
         data.db.connect();
@@ -541,7 +554,7 @@ public class Update extends BaseTransform<UpdateMeta, 
UpdateData>
         if (!data.db.isAutoCommit()) {
           if (getErrors() == 0) {
             if (dispose) {
-              data.db.emptyAndCommit(data.prepStatementUpdate, 
meta.useBatchUpdate());
+              data.db.emptyAndCommit(data.prepStatementUpdate, 
meta.isUseBatchUpdate());
             } else {
               data.db.commit();
             }
diff --git 
a/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateData.java
 
b/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateData.java
index fd685cd..8ba25dd 100644
--- 
a/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateData.java
+++ 
b/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateData.java
@@ -55,4 +55,5 @@ public class UpdateData extends BaseTransformData implements 
ITransformData {
 
     db = null;
   }
+
 }
diff --git 
a/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateDialog.java
 
b/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateDialog.java
index 59018cd..bb2d68e 100644
--- 
a/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateDialog.java
+++ 
b/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateDialog.java
@@ -99,7 +99,6 @@ public class UpdateDialog extends BaseTransformDialog 
implements ITransformDialo
     inputFields = new HashMap<>();
   }
 
-  @Override
   public String open() {
     Shell parent = getParent();
 
@@ -115,7 +114,6 @@ public class UpdateDialog extends BaseTransformDialog 
implements ITransformDialo
         };
     SelectionListener lsSelection =
         new SelectionAdapter() {
-          @Override
           public void widgetSelected(SelectionEvent e) {
             input.setChanged();
             setTableFieldCombo();
@@ -153,7 +151,8 @@ public class UpdateDialog extends BaseTransformDialog 
implements ITransformDialo
     wTransformName.setLayoutData(fdTransformName);
 
     // Connection line
-    wConnection = addConnectionLine(shell, wTransformName, 
input.getDatabaseMeta(), lsMod);
+    DatabaseMeta dbm = pipelineMeta.findDatabase(input.getConnection(), 
variables);
+    wConnection = addConnectionLine(shell, wTransformName, dbm, lsMod);
     wConnection.addSelectionListener(lsSelection);
 
     // Schema line...
@@ -246,7 +245,6 @@ public class UpdateDialog extends BaseTransformDialog 
implements ITransformDialo
     wBatch.setLayoutData(fdBatch);
     wBatch.addSelectionListener(
         new SelectionAdapter() {
-          @Override
           public void widgetSelected(SelectionEvent arg0) {
             setFlags();
             input.setChanged();
@@ -272,7 +270,6 @@ public class UpdateDialog extends BaseTransformDialog 
implements ITransformDialo
     wSkipLookup.setLayoutData(fdSkipLookup);
     wSkipLookup.addSelectionListener(
         new SelectionAdapter() {
-          @Override
           public void widgetSelected(SelectionEvent e) {
             input.setChanged();
             setActiveIgnoreLookup();
@@ -296,7 +293,6 @@ public class UpdateDialog extends BaseTransformDialog 
implements ITransformDialo
     wErrorIgnored.setLayoutData(fdErrorIgnored);
     wErrorIgnored.addSelectionListener(
         new SelectionAdapter() {
-          @Override
           public void widgetSelected(SelectionEvent e) {
             input.setChanged();
             setFlags();
@@ -328,7 +324,10 @@ public class UpdateDialog extends BaseTransformDialog 
implements ITransformDialo
     wlKey.setLayoutData(fdlKey);
 
     int nrKeyCols = 4;
-    int nrKeyRows = (input.getKeyStream() != null ? 
input.getKeyStream().length : 1);
+    int nrKeyRows =
+        (input.getLookupField().getLookupKeys() != null
+            ? input.getLookupField().getLookupKeys().size()
+            : 1);
 
     ciKey = new ColumnInfo[nrKeyCols];
     ciKey[0] =
@@ -411,7 +410,10 @@ public class UpdateDialog extends BaseTransformDialog 
implements ITransformDialo
     wlReturn.setLayoutData(fdlReturn);
 
     int UpInsCols = 2;
-    int UpInsRows = (input.getUpdateLookup() != null ? 
input.getUpdateLookup().length : 1);
+    int UpInsRows =
+        (input.getLookupField().getUpdateFields() != null
+            ? input.getLookupField().getUpdateFields().size()
+            : 1);
 
     ciReturn = new ColumnInfo[UpInsCols];
     ciReturn[0] =
@@ -484,14 +486,12 @@ public class UpdateDialog extends BaseTransformDialog 
implements ITransformDialo
 
     wbSchema.addSelectionListener(
         new SelectionAdapter() {
-          @Override
           public void widgetSelected(SelectionEvent e) {
             getSchemaNames();
           }
         });
     wbTable.addSelectionListener(
         new SelectionAdapter() {
-          @Override
           public void widgetSelected(SelectionEvent e) {
             getTableName();
           }
@@ -542,7 +542,7 @@ public class UpdateDialog extends BaseTransformDialog 
implements ITransformDialo
     wlIgnoreFlagField.setEnabled(wErrorIgnored.getSelection());
     wIgnoreFlagField.setEnabled(wErrorIgnored.getSelection());
 
-    DatabaseMeta databaseMeta = 
pipelineMeta.findDatabase(wConnection.getText());
+    DatabaseMeta databaseMeta = 
pipelineMeta.findDatabase(wConnection.getText(), variables);
     boolean hasErrorHandling = 
pipelineMeta.findTransform(transformName).isDoingErrorHandling();
 
     // Can't use batch yet when grabbing auto-generated keys...
@@ -570,7 +570,7 @@ public class UpdateDialog extends BaseTransformDialog 
implements ITransformDialo
               colInfo.setComboValues(new String[] {});
             }
             if (!Utils.isEmpty(tableName)) {
-              DatabaseMeta databaseMeta = 
pipelineMeta.findDatabase(connectionName);
+              DatabaseMeta databaseMeta = 
pipelineMeta.findDatabase(connectionName, variables);
               if (databaseMeta != null) {
                 Database db = new Database(loggingObject, variables, 
databaseMeta);
                 try {
@@ -617,51 +617,58 @@ public class UpdateDialog extends BaseTransformDialog 
implements ITransformDialo
     }
 
     wCommit.setText(input.getCommitSizeVar());
-    wBatch.setSelection(input.useBatchUpdate());
+    wBatch.setSelection(input.isUseBatchUpdate());
     wSkipLookup.setSelection(input.isSkipLookup());
     wErrorIgnored.setSelection(input.isErrorIgnored());
     if (input.getIgnoreFlagField() != null) {
       wIgnoreFlagField.setText(input.getIgnoreFlagField());
     }
 
-    if (input.getKeyStream() != null) {
-      for (int i = 0; i < input.getKeyStream().length; i++) {
+    wKey.table.clearAll();
+    if (input.getLookupField().getLookupKeys() != null
+        && input.getLookupField().getLookupKeys().size() > 0) {
+      for (int i = 0; i < input.getLookupField().getLookupKeys().size(); i++) {
+        UpdateKeyField keyField = 
input.getLookupField().getLookupKeys().get(i);
         TableItem item = wKey.table.getItem(i);
-        if (input.getKeyLookup()[i] != null) {
-          item.setText(1, input.getKeyLookup()[i]);
+        if (keyField.getKeyLookup() != null) {
+          item.setText(1, keyField.getKeyLookup());
         }
-        if (input.getKeyCondition()[i] != null) {
-          item.setText(2, input.getKeyCondition()[i]);
+        if (keyField.getKeyCondition() != null) {
+          item.setText(2, keyField.getKeyCondition());
         }
-        if (input.getKeyStream()[i] != null) {
-          item.setText(3, input.getKeyStream()[i]);
+        if (keyField.getKeyStream() != null) {
+          item.setText(3, keyField.getKeyStream());
         }
-        if (input.getKeyStream2()[i] != null) {
-          item.setText(4, input.getKeyStream2()[i]);
+        if (keyField.getKeyStream2() != null) {
+          item.setText(4, keyField.getKeyStream2());
         }
       }
     }
 
-    if (input.getUpdateLookup() != null) {
-      for (int i = 0; i < input.getUpdateLookup().length; i++) {
+    if (input.getLookupField().getUpdateFields() != null
+        && input.getLookupField().getUpdateFields().size() > 0) {
+      wReturn.table.clearAll();
+      for (int i = 0; i < input.getLookupField().getUpdateFields().size(); 
i++) {
+        UpdateField fieldItem = 
input.getLookupField().getUpdateFields().get(i);
         TableItem item = wReturn.table.getItem(i);
-        if (input.getUpdateLookup()[i] != null) {
-          item.setText(1, input.getUpdateLookup()[i]);
+        if (fieldItem.getUpdateLookup() != null) {
+          item.setText(1, fieldItem.getUpdateLookup());
         }
-        if (input.getUpdateStream()[i] != null) {
-          item.setText(2, input.getUpdateStream()[i]);
+        if (fieldItem.getUpdateStream() != null) {
+          item.setText(2, fieldItem.getUpdateStream());
         }
       }
     }
 
-    if (input.getSchemaName() != null) {
-      wSchema.setText(input.getSchemaName());
+    if (input.getLookupField().getSchemaName() != null) {
+      wSchema.setText(input.getLookupField().getSchemaName());
     }
-    if (input.getTableName() != null) {
-      wTable.setText(input.getTableName());
+    if (input.getLookupField().getTableName() != null) {
+      wTable.setText(input.getLookupField().getTableName());
     }
-    if (input.getDatabaseMeta() != null) {
-      wConnection.setText(input.getDatabaseMeta().getName());
+
+    if (input.getConnection() != null) {
+      wConnection.setText(input.getConnection());
     }
 
     wKey.setRowNums();
@@ -686,8 +693,8 @@ public class UpdateDialog extends BaseTransformDialog 
implements ITransformDialo
     int nrkeys = wKey.nrNonEmpty();
     int nrFields = wReturn.nrNonEmpty();
 
-    inf.allocate(nrkeys, nrFields);
-
+    inf.setConnection(wConnection.getText());
+    inf.setDatabaseMeta(pipelineMeta.findDatabase(wConnection.getText(), 
variables));
     inf.setCommitSize(wCommit.getText());
     inf.setUseBatchUpdate(wBatch.getSelection());
     inf.setSkipLookup(wSkipLookup.getSelection());
@@ -695,28 +702,30 @@ public class UpdateDialog extends BaseTransformDialog 
implements ITransformDialo
     if (log.isDebug()) {
       logDebug(BaseMessages.getString(PKG, "UpdateDialog.Log.FoundKeys", 
nrkeys + ""));
     }
+
+    inf.getLookupField().getLookupKeys().clear();
     // CHECKSTYLE:Indentation:OFF
     for (int i = 0; i < nrkeys; i++) {
       TableItem item = wKey.getNonEmpty(i);
-      inf.getKeyLookup()[i] = item.getText(1);
-      inf.getKeyCondition()[i] = item.getText(2);
-      inf.getKeyStream()[i] = item.getText(3);
-      inf.getKeyStream2()[i] = item.getText(4);
+      UpdateKeyField keyItem =
+          new UpdateKeyField(item.getText(3), item.getText(1), 
item.getText(2), item.getText(4));
+
+      inf.getLookupField().getLookupKeys().add(keyItem);
     }
 
     // Table ftable = wReturn.table;
 
     logDebug(BaseMessages.getString(PKG, "UpdateDialog.Log.FoundFields", 
nrFields + ""));
     // CHECKSTYLE:Indentation:OFF
+    inf.getLookupField().getUpdateFields().clear();
     for (int i = 0; i < nrFields; i++) {
       TableItem item = wReturn.getNonEmpty(i);
-      inf.getUpdateLookup()[i] = item.getText(1);
-      inf.getUpdateStream()[i] = item.getText(2);
+      UpdateField fieldItem = new UpdateField(item.getText(1), 
item.getText(2));
+      inf.getLookupField().getUpdateFields().add(fieldItem);
     }
 
-    inf.setSchemaName(wSchema.getText());
-    inf.setTableName(wTable.getText());
-    inf.setDatabaseMeta(pipelineMeta.findDatabase(wConnection.getText()));
+    inf.getLookupField().setSchemaName(wSchema.getText());
+    inf.getLookupField().setTableName(wTable.getText());
 
     inf.setErrorIgnored(wErrorIgnored.getSelection());
     inf.setIgnoreFlagField(wIgnoreFlagField.getText());
@@ -748,7 +757,7 @@ public class UpdateDialog extends BaseTransformDialog 
implements ITransformDialo
     if (StringUtils.isEmpty(connectionName)) {
       return;
     }
-    DatabaseMeta databaseMeta = pipelineMeta.findDatabase(connectionName);
+    DatabaseMeta databaseMeta = pipelineMeta.findDatabase(connectionName, 
variables);
     if (databaseMeta != null) {
       if (log.isDebug()) {
         logDebug(
@@ -858,7 +867,7 @@ public class UpdateDialog extends BaseTransformDialog 
implements ITransformDialo
   }
 
   private void getSchemaNames() {
-    DatabaseMeta databaseMeta = 
pipelineMeta.findDatabase(wConnection.getText());
+    DatabaseMeta databaseMeta = 
pipelineMeta.findDatabase(wConnection.getText(), variables);
     if (databaseMeta != null) {
       Database database = new Database(loggingObject, variables, databaseMeta);
       try {
diff --git 
a/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateField.java
 
b/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateField.java
new file mode 100644
index 0000000..20344ed
--- /dev/null
+++ 
b/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateField.java
@@ -0,0 +1,75 @@
+/*
+ *  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.update;
+
+import org.apache.hop.core.injection.Injection;
+import org.apache.hop.metadata.api.HopMetadataProperty;
+
+import java.util.Objects;
+
+public class UpdateField {
+
+    /** Field value to update after lookup */
+    @HopMetadataProperty(key = "name",
+            injectionKeyDescription = "UpdateMeta.Injection.UpdateLookup",
+            injectionKey = "UPDATE_LOOKUP")
+    private String updateLookup;
+
+    /** Stream name to update value with */
+    @HopMetadataProperty(key = "rename",
+            injectionKeyDescription = "UpdateMeta.Injection.UpdateStream",
+            injectionKey = "UPDATE_STREAM")
+    private String updateStream;
+
+    public UpdateField() {
+    }
+
+    public UpdateField(String updateLookup, String updateStream) {
+        this.updateLookup = updateLookup;
+        this.updateStream = updateStream;
+    }
+
+    public String getUpdateLookup() {
+        return updateLookup;
+    }
+
+    public void setUpdateLookup(String updateLookup) {
+        this.updateLookup = updateLookup;
+    }
+
+    public String getUpdateStream() {
+        return updateStream;
+    }
+
+    public void setUpdateStream(String updateStream) {
+        this.updateStream = updateStream;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        UpdateField that = (UpdateField) o;
+        return updateLookup.equals(that.updateLookup) && 
updateStream.equals(that.updateStream);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(updateLookup, updateStream);
+    }
+}
diff --git 
a/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateKeyField.java
 
b/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateKeyField.java
new file mode 100644
index 0000000..1198e97
--- /dev/null
+++ 
b/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateKeyField.java
@@ -0,0 +1,109 @@
+/*
+ *  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.update;
+
+import org.apache.hop.metadata.api.HopMetadataProperty;
+
+import java.util.Objects;
+
+public class UpdateKeyField {
+    /** which field in input stream to compare with? */
+    @HopMetadataProperty(key = "name",
+            injectionKeyDescription = "UpdateMeta.Injection.KeyStream",
+            injectionKey = "KEY_STREAM")
+    private String keyStream;
+
+    /** field in table */
+    @HopMetadataProperty(key = "field",
+            injectionKeyDescription = "UpdateMeta.Injection.KeyLookup",
+            injectionKey = "KEY_LOOKUP")
+    private String keyLookup;
+
+    /** Comparator: =, <>, BETWEEN, ... */
+    @HopMetadataProperty(key = "condition",
+            injectionKeyDescription = "UpdateMeta.Injection.KeyCondition",
+            injectionKey = "KEY_CONDITION")
+    private String keyCondition;
+
+    /** Extra field for between... */
+    @HopMetadataProperty(key = "name2",
+            injectionKeyDescription = "UpdateMeta.Injection.KeyStream2",
+            injectionKey = "KEY_STREAM2")
+    private String keyStream2;
+
+    public UpdateKeyField() {
+    }
+
+    public UpdateKeyField(String keyStream, String keyLookup, String 
keyCondition) {
+        this.keyStream = keyStream;
+        this.keyLookup = keyLookup;
+        this.keyCondition = keyCondition;
+    }
+
+    public UpdateKeyField(String keyStream, String keyLookup, String 
keyCondition, String keyStream2) {
+        this.keyStream = keyStream;
+        this.keyLookup = keyLookup;
+        this.keyCondition = keyCondition;
+        this.keyStream2 = keyStream2;
+    }
+
+    public String getKeyStream() {
+        return keyStream;
+    }
+
+    public void setKeyStream(String keyStream) {
+        this.keyStream = keyStream;
+    }
+
+    public String getKeyLookup() {
+        return keyLookup;
+    }
+
+    public void setKeyLookup(String keyLookup) {
+        this.keyLookup = keyLookup;
+    }
+
+    public String getKeyCondition() {
+        return keyCondition;
+    }
+
+    public void setKeyCondition(String keyCondition) {
+        this.keyCondition = keyCondition;
+    }
+
+    public String getKeyStream2() {
+        return keyStream2;
+    }
+
+    public void setKeyStream2(String keyStream2) {
+        this.keyStream2 = keyStream2;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        UpdateKeyField that = (UpdateKeyField) o;
+        return keyStream.equals(that.keyStream) && 
keyLookup.equals(that.keyLookup) && keyCondition.equals(that.keyCondition) && 
Objects.equals(keyStream2, that.keyStream2);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(keyStream, keyLookup, keyCondition, keyStream2);
+    }
+}
diff --git 
a/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateLookupField.java
 
b/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateLookupField.java
new file mode 100644
index 0000000..65b0242
--- /dev/null
+++ 
b/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateLookupField.java
@@ -0,0 +1,110 @@
+/*
+ *  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.update;
+
+import org.apache.hop.metadata.api.HopMetadataProperty;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class UpdateLookupField {
+
+    /** Lookup key fields **/
+    @HopMetadataProperty(key = "key",
+            injectionGroupKey = "KEYS",
+            injectionGroupDescription = "UpdateMeta.Injection.LookupKeys",
+            injectionKeyDescription = "UpdateMeta.Injection.LookupKey")
+    private List<UpdateKeyField> lookupKeys;
+
+    /** Update fields **/
+    @HopMetadataProperty(key = "value",
+            injectionGroupKey = "UPDATES",
+            injectionGroupDescription = "UpdateMeta.Injection.UpdateKeys",
+            injectionKeyDescription = "UpdateMeta.Injection.UpdateKey")
+    private List<UpdateField> updateFields;
+
+    /** The lookup table's schema name */
+    @HopMetadataProperty(key = "schema",
+            injectionKeyDescription = "UpdateMeta.Injection.SchemaName",
+            injectionKey = "SCHEMA_NAME")
+    private String schemaName;
+
+    /** The lookup table name */
+    @HopMetadataProperty(key = "table",
+            injectionKeyDescription = "UpdateMeta.Injection.TableName",
+            injectionKey = "TABLE_NAME")
+    private String tableName;
+
+    public UpdateLookupField() {
+        init();
+    }
+
+    public UpdateLookupField(String schemaName, String tableName) {
+        this.schemaName = schemaName;
+        this.tableName = tableName;
+        init();
+    }
+
+    public UpdateLookupField(String schemaName, String tableName, 
List<UpdateKeyField> lookupKeys, List<UpdateField> updateFields) {
+        this.schemaName = schemaName;
+        this.tableName = tableName;
+        this.lookupKeys = lookupKeys;
+        this.updateFields = updateFields;
+    }
+
+    protected void init() {
+        lookupKeys = new ArrayList<>();
+        updateFields = new ArrayList<>();
+    }
+
+    /** @return the schemaName */
+    public String getSchemaName() {
+        return schemaName;
+    }
+
+    /** @param schemaName the schemaName to set */
+    public void setSchemaName(String schemaName) {
+        this.schemaName = schemaName;
+    }
+
+    /** @return Returns the tableName. */
+    public String getTableName() {
+        return tableName;
+    }
+
+    /** @param tableName The tableName to set. */
+    public void setTableName(String tableName) {
+        this.tableName = tableName;
+    }
+
+    public List<UpdateKeyField> getLookupKeys() {
+        return lookupKeys;
+    }
+
+    public void setLookupKeys(List<UpdateKeyField> lookupKeys) {
+        this.lookupKeys = lookupKeys;
+    }
+
+    public List<UpdateField> getUpdateFields() {
+        return updateFields;
+    }
+
+    public void setUpdateFields(List<UpdateField> updateFields) {
+        this.updateFields = updateFields;
+    }
+}
diff --git 
a/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateMeta.java
 
b/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateMeta.java
index bb571ff..823a473 100644
--- 
a/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateMeta.java
+++ 
b/plugins/transforms/update/src/main/java/org/apache/hop/pipeline/transforms/update/UpdateMeta.java
@@ -26,17 +26,15 @@ import org.apache.hop.core.database.Database;
 import org.apache.hop.core.database.DatabaseMeta;
 import org.apache.hop.core.exception.HopException;
 import org.apache.hop.core.exception.HopTransformException;
-import org.apache.hop.core.exception.HopXmlException;
 import org.apache.hop.core.injection.AfterInjection;
-import org.apache.hop.core.injection.Injection;
-import org.apache.hop.core.injection.InjectionSupported;
 import org.apache.hop.core.row.IRowMeta;
 import org.apache.hop.core.row.IValueMeta;
 import org.apache.hop.core.row.value.ValueMetaBoolean;
+import org.apache.hop.core.util.StringUtil;
 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.DatabaseImpact;
 import org.apache.hop.pipeline.Pipeline;
@@ -45,17 +43,15 @@ import org.apache.hop.pipeline.transform.BaseTransformMeta;
 import org.apache.hop.pipeline.transform.ITransformMeta;
 import org.apache.hop.pipeline.transform.TransformMeta;
 import org.apache.hop.pipeline.transform.utils.RowMetaUtils;
-import org.w3c.dom.Node;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /*
  * Created on 26-apr-2003
  *
  */
-@InjectionSupported(
-    localizationPrefix = "UpdateMeta.Injection.",
-    groups = {"KEYS", "UPDATES"})
+
 @Transform(
     id = "Update",
     image = "update.svg",
@@ -68,71 +64,81 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
 
   private IHopMetadataProvider metadataProvider;
 
-  /** The lookup table name */
-  @Injection(name = "SCHEMA_NAME")
-  private String schemaName;
-
-  /** The lookup table name */
-  @Injection(name = "TABLE_NAME")
-  private String tableName;
-
   /** database connection */
   private DatabaseMeta databaseMeta;
 
-  /** which field in input stream to compare with? */
-  @Injection(name = "KEY_STREAM", group = "KEYS")
-  private String[] keyStream;
-
-  /** field in table */
-  @Injection(name = "KEY_LOOKUP", group = "KEYS")
-  private String[] keyLookup;
-
-  /** Comparator: =, <>, BETWEEN, ... */
-  @Injection(name = "KEY_CONDITION", group = "KEYS")
-  private String[] keyCondition;
-
-  /** Extra field for between... */
-  @Injection(name = "KEY_STREAM2", group = "KEYS")
-  private String[] keyStream2;
-
-  /** Field value to update after lookup */
-  @Injection(name = "UPDATE_LOOKUP", group = "UPDATES")
-  private String[] updateLookup;
-
-  /** Stream name to update value with */
-  @Injection(name = "UPDATE_STREAM", group = "UPDATES")
-  private String[] updateStream;
-
   /** Commit size for inserts/updates */
-  @Injection(name = "COMMIT_SIZE")
+  @HopMetadataProperty(
+      key = "commit",
+      injectionKeyDescription = "UpdateMeta.Injection.CommitSize",
+      injectionKey = "COMMIT_SIZE")
   private String commitSize;
 
+  /** Lookup key fields * */
+  @HopMetadataProperty(key = "lookup")
+  private UpdateLookupField lookupField;
+
   /** update errors are ignored if this flag is set to true */
-  @Injection(name = "IGNORE_LOOKUP_FAILURE")
+  @HopMetadataProperty(
+      key = "error_ignored",
+      injectionKeyDescription = "UpdateMeta.Injection.IgnoreLookupFailure",
+      injectionKey = "IGNORE_LOOKUP_FAILURE")
   private boolean errorIgnored;
 
   /** adds a boolean field to the output indicating success of the update */
-  @Injection(name = "FLAG_FIELD")
+  @HopMetadataProperty(
+      key = "ignore_flag_field",
+      injectionKeyDescription = "UpdateMeta.Injection.IgnoreFlagField",
+      injectionKey = "FLAG_FIELD")
   private String ignoreFlagField;
 
   /** adds a boolean field to skip lookup and directly update selected fields 
*/
-  @Injection(name = "SKIP_LOOKUP")
+  @HopMetadataProperty(
+      key = "skip_lookup",
+      injectionKeyDescription = "UpdateMeta.Injection.SkipLookup",
+      injectionKey = "SKIP_LOOKUP")
   private boolean skipLookup;
 
   /**
    * Flag to indicate the use of batch updates, enabled by default but 
disabled for backward
    * compatibility
    */
-  @Injection(name = "BATCH_UPDATE")
+  @HopMetadataProperty(
+      key = "use_batch",
+      injectionKeyDescription = "UpdateMeta.Injection.UseBatchUpdate",
+      injectionKey = "BATCH_UPDATE")
   private boolean useBatchUpdate;
 
-  @Injection(name = "CONNECTIONNAME")
-  public void setConnection(String connectionName) {
-    try {
-      databaseMeta = DatabaseMeta.loadDatabase(metadataProvider, 
connectionName);
-    } catch (HopXmlException e) {
-      throw new RuntimeException("Error loading conneciton '" + connectionName 
+ "'", e);
-    }
+  /** database connection */
+  @HopMetadataProperty(
+      key = "connection",
+      injectionKeyDescription = "UpdateMeta.Injection.Connection",
+      injectionKey = "CONNECTIONNAME")
+  private String connection;
+
+  public String getConnection() {
+    return connection;
+  }
+
+  public void setConnection(String connection) {
+    this.connection = connection;
+  }
+
+  public UpdateLookupField getLookupField() {
+    return lookupField;
+  }
+
+  public void setLookupField(UpdateLookupField lookupField) {
+    this.lookupField = lookupField;
+  }
+
+  /**
+   * @return Returns the commitSize.
+   * @deprecated use public String getCommitSizeVar() instead
+   */
+  @Deprecated
+  public int getCommitSize() {
+    return Integer.parseInt(commitSize);
   }
 
   /** @return Returns the commitSize. */
@@ -151,6 +157,15 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
     return Integer.parseInt(vs.resolve(commitSize));
   }
 
+  /**
+   * @param commitSize The commitSize to set.
+   * @deprecated use public void setCommitSize( String commitSize ) instead
+   */
+  @Deprecated
+  public void setCommitSize(int commitSize) {
+    this.commitSize = Integer.toString(commitSize);
+  }
+
   /** @param commitSize The commitSize to set. */
   public void setCommitSize(String commitSize) {
     this.commitSize = commitSize;
@@ -176,76 +191,6 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
     this.databaseMeta = database;
   }
 
-  /** @return Returns the keyCondition. */
-  public String[] getKeyCondition() {
-    return keyCondition;
-  }
-
-  /** @param keyCondition The keyCondition to set. */
-  public void setKeyCondition(String[] keyCondition) {
-    this.keyCondition = keyCondition;
-  }
-
-  /** @return Returns the keyLookup. */
-  public String[] getKeyLookup() {
-    return keyLookup;
-  }
-
-  /** @param keyLookup The keyLookup to set. */
-  public void setKeyLookup(String[] keyLookup) {
-    this.keyLookup = keyLookup;
-  }
-
-  /** @return Returns the keyStream. */
-  public String[] getKeyStream() {
-    return keyStream;
-  }
-
-  /** @param keyStream The keyStream to set. */
-  public void setKeyStream(String[] keyStream) {
-    this.keyStream = keyStream;
-  }
-
-  /** @return Returns the keyStream2. */
-  public String[] getKeyStream2() {
-    return keyStream2;
-  }
-
-  /** @param keyStream2 The keyStream2 to set. */
-  public void setKeyStream2(String[] keyStream2) {
-    this.keyStream2 = keyStream2;
-  }
-
-  /** @return Returns the tableName. */
-  public String getTableName() {
-    return tableName;
-  }
-
-  /** @param tableName The tableName to set. */
-  public void setTableName(String tableName) {
-    this.tableName = tableName;
-  }
-
-  /** @return Returns the updateLookup. */
-  public String[] getUpdateLookup() {
-    return updateLookup;
-  }
-
-  /** @param updateLookup The updateLookup to set. */
-  public void setUpdateLookup(String[] updateLookup) {
-    this.updateLookup = updateLookup;
-  }
-
-  /** @return Returns the updateStream. */
-  public String[] getUpdateStream() {
-    return updateStream;
-  }
-
-  /** @param updateStream The updateStream to set. */
-  public void setUpdateStream(String[] updateStream) {
-    this.updateStream = updateStream;
-  }
-
   /** @return Returns the ignoreError. */
   public boolean isErrorIgnored() {
     return errorIgnored;
@@ -266,37 +211,14 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
     this.ignoreFlagField = ignoreFlagField;
   }
 
-  @Override
-  public void loadXml(Node transformNode, IHopMetadataProvider 
metadataProvider)
-      throws HopXmlException {
-    this.metadataProvider = metadataProvider;
-    readData(transformNode, metadataProvider);
-  }
-
-  public void allocate(int nrkeys, int nrvalues) {
-    keyStream = new String[nrkeys];
-    keyLookup = new String[nrkeys];
-    keyCondition = new String[nrkeys];
-    keyStream2 = new String[nrkeys];
-    updateLookup = new String[nrvalues];
-    updateStream = new String[nrvalues];
+  public UpdateMeta() {
+    super();
+    lookupField = new UpdateLookupField();
   }
 
   @Override
   public Object clone() {
     UpdateMeta retval = (UpdateMeta) super.clone();
-    int nrkeys = keyStream.length;
-    int nrvalues = updateLookup.length;
-
-    retval.allocate(nrkeys, nrvalues);
-
-    System.arraycopy(keyStream, 0, retval.keyStream, 0, nrkeys);
-    System.arraycopy(keyLookup, 0, retval.keyLookup, 0, nrkeys);
-    System.arraycopy(keyCondition, 0, retval.keyCondition, 0, nrkeys);
-    System.arraycopy(keyStream2, 0, retval.keyStream2, 0, nrkeys);
-
-    System.arraycopy(updateLookup, 0, retval.updateLookup, 0, nrvalues);
-    System.arraycopy(updateStream, 0, retval.updateStream, 0, nrvalues);
     return retval;
   }
 
@@ -310,121 +232,14 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
     return new Update(transformMeta, this, data, copyNr, pipelineMeta, 
pipeline);
   }
 
-  private void readData(Node transformNode, IHopMetadataProvider 
metadataProvider)
-      throws HopXmlException {
-    this.metadataProvider = metadataProvider;
-    try {
-      String csize;
-      int nrkeys, nrvalues;
-
-      String con = XmlHandler.getTagValue(transformNode, "connection");
-      databaseMeta = DatabaseMeta.loadDatabase(metadataProvider, con);
-      csize = XmlHandler.getTagValue(transformNode, "commit");
-      commitSize = (csize == null) ? "0" : csize;
-      useBatchUpdate = 
"Y".equalsIgnoreCase(XmlHandler.getTagValue(transformNode, "use_batch"));
-      skipLookup = "Y".equalsIgnoreCase(XmlHandler.getTagValue(transformNode, 
"skip_lookup"));
-      errorIgnored = 
"Y".equalsIgnoreCase(XmlHandler.getTagValue(transformNode, "error_ignored"));
-      ignoreFlagField = XmlHandler.getTagValue(transformNode, 
"ignore_flag_field");
-      schemaName = XmlHandler.getTagValue(transformNode, "lookup", "schema");
-      tableName = XmlHandler.getTagValue(transformNode, "lookup", "table");
-
-      Node lookup = XmlHandler.getSubNode(transformNode, "lookup");
-      nrkeys = XmlHandler.countNodes(lookup, "key");
-      nrvalues = XmlHandler.countNodes(lookup, "value");
-
-      allocate(nrkeys, nrvalues);
-
-      for (int i = 0; i < nrkeys; i++) {
-        Node knode = XmlHandler.getSubNodeByNr(lookup, "key", i);
-
-        keyStream[i] = XmlHandler.getTagValue(knode, "name");
-        keyLookup[i] = XmlHandler.getTagValue(knode, "field");
-        keyCondition[i] = XmlHandler.getTagValue(knode, "condition");
-        if (keyCondition[i] == null) {
-          keyCondition[i] = "=";
-        }
-        keyStream2[i] = XmlHandler.getTagValue(knode, "name2");
-      }
-
-      for (int i = 0; i < nrvalues; i++) {
-        Node vnode = XmlHandler.getSubNodeByNr(lookup, "value", i);
-
-        updateLookup[i] = XmlHandler.getTagValue(vnode, "name");
-        updateStream[i] = XmlHandler.getTagValue(vnode, "rename");
-        if (updateStream[i] == null) {
-          updateStream[i] = updateLookup[i]; // default: the same name!
-        }
-      }
-    } catch (Exception e) {
-      throw new HopXmlException(
-          BaseMessages.getString(PKG, 
"UpdateMeta.Exception.UnableToReadTransformMetaFromXML"), e);
-    }
-  }
-
   @Override
   public void setDefault() {
     skipLookup = false;
-    keyStream = null;
-    updateLookup = null;
     databaseMeta = null;
     commitSize = "100";
-    schemaName = "";
-    tableName = BaseMessages.getString(PKG, "UpdateMeta.DefaultTableName");
-
-    int nrkeys = 0;
-    int nrvalues = 0;
-
-    allocate(nrkeys, nrvalues);
-
-    for (int i = 0; i < nrkeys; i++) {
-      keyLookup[i] = "age";
-      keyCondition[i] = "BETWEEN";
-      keyStream[i] = "age_from";
-      keyStream2[i] = "age_to";
-    }
-
-    for (int i = 0; i < nrvalues; i++) {
-      updateLookup[i] = BaseMessages.getString(PKG, 
"UpdateMeta.ColumnName.ReturnField") + i;
-      updateStream[i] = BaseMessages.getString(PKG, 
"UpdateMeta.ColumnName.NewName") + i;
-    }
-  }
-
-  @Override
-  public String getXml() {
-    StringBuilder retval = new StringBuilder();
-
-    retval.append(
-        "    "
-            + XmlHandler.addTagValue(
-                "connection", databaseMeta == null ? "" : 
databaseMeta.getName()));
-    retval.append("    " + XmlHandler.addTagValue("skip_lookup", skipLookup));
-    retval.append("    " + XmlHandler.addTagValue("commit", commitSize));
-    retval.append("    " + XmlHandler.addTagValue("use_batch", 
useBatchUpdate));
-    retval.append("    " + XmlHandler.addTagValue("error_ignored", 
errorIgnored));
-    retval.append("    " + XmlHandler.addTagValue("ignore_flag_field", 
ignoreFlagField));
-    retval.append("    <lookup>" + Const.CR);
-    retval.append("      " + XmlHandler.addTagValue("schema", schemaName));
-    retval.append("      " + XmlHandler.addTagValue("table", tableName));
-
-    for (int i = 0; i < keyStream.length; i++) {
-      retval.append("      <key>" + Const.CR);
-      retval.append("        " + XmlHandler.addTagValue("name", keyStream[i]));
-      retval.append("        " + XmlHandler.addTagValue("field", 
keyLookup[i]));
-      retval.append("        " + XmlHandler.addTagValue("condition", 
keyCondition[i]));
-      retval.append("        " + XmlHandler.addTagValue("name2", 
keyStream2[i]));
-      retval.append("        </key>" + Const.CR);
-    }
 
-    for (int i = 0; i < updateLookup.length; i++) {
-      retval.append("      <value>" + Const.CR);
-      retval.append("        " + XmlHandler.addTagValue("name", 
updateLookup[i]));
-      retval.append("        " + XmlHandler.addTagValue("rename", 
updateStream[i]));
-      retval.append("        </value>" + Const.CR);
-    }
-
-    retval.append("      </lookup>" + Const.CR);
-
-    return retval.toString();
+    lookupField.setSchemaName("");
+    lookupField.setTableName(BaseMessages.getString(PKG, 
"UpdateMeta.DefaultTableName"));
   }
 
   @Override
@@ -463,7 +278,7 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
       try {
         db.connect();
 
-        if (!Utils.isEmpty(tableName)) {
+        if (!Utils.isEmpty(lookupField.getTableName())) {
           cr =
               new CheckResult(
                   ICheckResult.TYPE_RESULT_OK,
@@ -476,7 +291,8 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
           errorMessage = "";
 
           // Check fields in table
-          IRowMeta r = db.getTableFieldsMeta(schemaName, tableName);
+          IRowMeta r =
+              db.getTableFieldsMeta(lookupField.getSchemaName(), 
lookupField.getTableName());
           if (r != null) {
             cr =
                 new CheckResult(
@@ -485,10 +301,9 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
                     transformMeta);
             remarks.add(cr);
 
-            for (int i = 0; i < keyLookup.length; i++) {
-              String lufield = keyLookup[i];
-
-              IValueMeta v = r.searchValueMeta(lufield);
+            for (int i = 0; i < lookupField.getLookupKeys().size(); i++) {
+              UpdateKeyField keyItem = lookupField.getLookupKeys().get(i);
+              IValueMeta v = r.searchValueMeta(keyItem.getKeyLookup());
               if (v == null) {
                 if (first) {
                   first = false;
@@ -498,7 +313,7 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
                           + Const.CR;
                 }
                 errorFound = true;
-                errorMessage += "\t\t" + lufield + Const.CR;
+                errorMessage += "\t\t" + keyItem.getKeyLookup() + Const.CR;
               }
             }
             if (errorFound) {
@@ -517,10 +332,10 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
             errorFound = false;
             errorMessage = "";
 
-            for (int i = 0; i < updateLookup.length; i++) {
-              String lufield = updateLookup[i];
+            for (int i = 0; i < lookupField.getUpdateFields().size(); i++) {
 
-              IValueMeta v = r.searchValueMeta(lufield);
+              UpdateField fieldItem = lookupField.getUpdateFields().get(i);
+              IValueMeta v = r.searchValueMeta(fieldItem.getUpdateLookup());
               if (v == null) {
                 if (first) {
                   first = false;
@@ -530,7 +345,7 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
                           + Const.CR;
                 }
                 errorFound = true;
-                errorMessage += "\t\t" + lufield + Const.CR;
+                errorMessage += "\t\t" + fieldItem.getUpdateLookup() + 
Const.CR;
               }
             }
             if (errorFound) {
@@ -566,8 +381,9 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
           errorMessage = "";
           boolean errorFound = false;
 
-          for (int i = 0; i < keyStream.length; i++) {
-            IValueMeta v = prev.searchValueMeta(keyStream[i]);
+          for (int i = 0; i < lookupField.getLookupKeys().size(); i++) {
+            UpdateKeyField keyItem = lookupField.getLookupKeys().get(i);
+            IValueMeta v = prev.searchValueMeta(keyItem.getKeyStream());
             if (v == null) {
               if (first) {
                 first = false;
@@ -576,12 +392,13 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
                         + Const.CR;
               }
               errorFound = true;
-              errorMessage += "\t\t" + keyStream[i] + Const.CR;
+              errorMessage += "\t\t" + keyItem.getKeyStream() + Const.CR;
             }
           }
-          for (int i = 0; i < keyStream2.length; i++) {
-            if (keyStream2[i] != null && keyStream2[i].length() > 0) {
-              IValueMeta v = prev.searchValueMeta(keyStream2[i]);
+          for (int i = 0; i < lookupField.getLookupKeys().size(); i++) {
+            UpdateKeyField keyItem = lookupField.getLookupKeys().get(i);
+            if (!StringUtil.isEmpty(keyItem.getKeyStream2())) {
+              IValueMeta v = prev.searchValueMeta(keyItem.getKeyStream2());
               if (v == null) {
                 if (first) {
                   first = false;
@@ -590,7 +407,7 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
                           + Const.CR;
                 }
                 errorFound = true;
-                errorMessage += "\t\t" + keyStream[i] + Const.CR;
+                errorMessage += "\t\t" + keyItem.getKeyStream2() + Const.CR;
               }
             }
           }
@@ -610,10 +427,9 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
           errorFound = false;
           errorMessage = "";
 
-          for (int i = 0; i < updateStream.length; i++) {
-            String lufield = updateStream[i];
-
-            IValueMeta v = prev.searchValueMeta(lufield);
+          for (int i = 0; i < lookupField.getUpdateFields().size(); i++) {
+            UpdateField fieldItem = lookupField.getUpdateFields().get(i);
+            IValueMeta v = prev.searchValueMeta(fieldItem.getUpdateStream());
             if (v == null) {
               if (first) {
                 first = false;
@@ -622,7 +438,7 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
                         + Const.CR;
               }
               errorFound = true;
-              errorMessage += "\t\t" + lufield + Const.CR;
+              errorMessage += "\t\t" + fieldItem.getUpdateStream() + Const.CR;
             }
           }
           if (errorFound) {
@@ -689,13 +505,46 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
 
     if (databaseMeta != null) {
       if (prev != null && prev.size() > 0) {
-        // Copy the row
+
+        String[] keyLookup = null;
+        String[] keyStream = null;
+        String[] updateLookup = null;
+        String[] updateStream = null;
+
+        if (lookupField.getLookupKeys().size() > 0) {
+          keyLookup = new String[lookupField.getLookupKeys().size()];
+          for (int i = 0; i < lookupField.getLookupKeys().size(); i++) {
+            keyLookup[i] = lookupField.getLookupKeys().get(i).getKeyLookup();
+          }
+        }
+
+        if (lookupField.getLookupKeys().size() > 0) {
+          keyStream = new String[lookupField.getLookupKeys().size()];
+          for (int i = 0; i < lookupField.getLookupKeys().size(); i++) {
+            keyStream[i] = lookupField.getLookupKeys().get(i).getKeyStream();
+          }
+        }
+
+        if (lookupField.getLookupKeys().size() > 0) {
+          updateLookup = new String[lookupField.getUpdateFields().size()];
+          for (int i = 0; i < lookupField.getUpdateFields().size(); i++) {
+            updateLookup[i] = 
lookupField.getUpdateFields().get(i).getUpdateLookup();
+          }
+        }
+
+        if (lookupField.getLookupKeys().size() > 0) {
+          updateStream = new String[lookupField.getUpdateFields().size()];
+          for (int i = 0; i < lookupField.getUpdateFields().size(); i++) {
+            updateStream[i] = 
lookupField.getUpdateFields().get(i).getUpdateStream();
+          }
+        }
+          // Copy the row
         IRowMeta tableFields =
             RowMetaUtils.getRowMetaForUpdate(
                 prev, keyLookup, keyStream, updateLookup, updateStream);
-        if (!Utils.isEmpty(tableName)) {
+        if (!Utils.isEmpty(lookupField.getTableName())) {
           String schemaTable =
-              databaseMeta.getQuotedSchemaTableCombination(variables, 
schemaName, tableName);
+              databaseMeta.getQuotedSchemaTableCombination(variables, 
lookupField.getSchemaName(), lookupField.getTableName());
 
           Database db = new Database(loggingObject, variables, databaseMeta);
           try {
@@ -710,10 +559,10 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
             String crIndex = "";
             String[] idxFields = null;
 
-            if (keyLookup != null && keyLookup.length > 0) {
-              idxFields = new String[keyLookup.length];
-              for (int i = 0; i < keyLookup.length; i++) {
-                idxFields[i] = keyLookup[i];
+            if (lookupField.getLookupKeys().size() > 0) {
+              idxFields = new String[lookupField.getLookupKeys().size()];
+              for (int i = 0; i < lookupField.getLookupKeys().size(); i++) {
+                idxFields[i] = 
lookupField.getLookupKeys().get(i).getKeyLookup();
               }
             } else {
               retval.setError(
@@ -724,7 +573,7 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
             if (idxFields != null
                 && idxFields.length > 0
                 && !db.checkIndexExists(schemaTable, idxFields)) {
-              String indexname = "idx_" + tableName + "_lookup";
+              String indexname = "idx_" + lookupField.getTableName() + 
"_lookup";
               crIndex =
                   db.getCreateIndexStatement(
                       schemaTable, indexname, idxFields, false, false, false, 
true);
@@ -770,8 +619,9 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
       throws HopTransformException {
     if (prev != null) {
       // Lookup: we do a lookup on the natural keys
-      for (int i = 0; i < keyLookup.length; i++) {
-        IValueMeta v = prev.searchValueMeta(keyStream[i]);
+      for (int i = 0; i < lookupField.getLookupKeys().size(); i++) {
+        UpdateKeyField keyFieldItem = lookupField.getLookupKeys().get(i);
+        IValueMeta v = prev.searchValueMeta(keyFieldItem.getKeyStream());
 
         DatabaseImpact ii =
             new DatabaseImpact(
@@ -779,9 +629,9 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
                 pipelineMeta.getName(),
                 transformMeta.getName(),
                 databaseMeta.getDatabaseName(),
-                tableName,
-                keyLookup[i],
-                keyStream[i],
+                lookupField.getTableName(),
+                    keyFieldItem.getKeyLookup(),
+                    keyFieldItem.getKeyStream(),
                 v != null ? v.getOrigin() : "?",
                 "",
                 "Type = " + v.toStringMeta());
@@ -789,8 +639,9 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
       }
 
       // Update fields : read/write
-      for (int i = 0; i < updateLookup.length; i++) {
-        IValueMeta v = prev.searchValueMeta(updateStream[i]);
+      for (int i = 0; i < lookupField.getUpdateFields().size(); i++) {
+        UpdateField  fieldItem = lookupField.getUpdateFields().get(i);
+        IValueMeta v = prev.searchValueMeta(fieldItem.getUpdateStream());
 
         DatabaseImpact ii =
             new DatabaseImpact(
@@ -798,9 +649,9 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
                 pipelineMeta.getName(),
                 transformMeta.getName(),
                 databaseMeta.getDatabaseName(),
-                tableName,
-                updateLookup[i],
-                updateStream[i],
+                lookupField.getTableName(),
+                fieldItem.getUpdateLookup(),
+                fieldItem.getUpdateStream(),
                 v != null ? v.getOrigin() : "?",
                 "",
                 "Type = " + v.toStringMeta());
@@ -823,23 +674,13 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
     }
   }
 
-  /** @return the schemaName */
-  public String getSchemaName() {
-    return schemaName;
-  }
-
-  /** @param schemaName the schemaName to set */
-  public void setSchemaName(String schemaName) {
-    this.schemaName = schemaName;
-  }
-
   @Override
   public boolean supportsErrorHandling() {
     return true;
   }
 
   /** @return the useBatchUpdate */
-  public boolean useBatchUpdate() {
+  public boolean isUseBatchUpdate() {
     return useBatchUpdate;
   }
 
@@ -847,24 +688,4 @@ public class UpdateMeta extends BaseTransformMeta 
implements ITransformMeta<Upda
   public void setUseBatchUpdate(boolean useBatchUpdate) {
     this.useBatchUpdate = useBatchUpdate;
   }
-
-  /**
-   * If we use injection we can have different arrays lengths. We need 
synchronize them for
-   * consistency behavior with UI
-   */
-  @AfterInjection
-  public void afterInjectionSynchronization() {
-    int nrFields = (keyStream == null) ? -1 : keyStream.length;
-    if (nrFields <= 0) {
-      return;
-    }
-    String[][] rtn = Utils.normalizeArrays(nrFields, keyLookup, keyCondition, 
keyStream2);
-    keyLookup = rtn[0];
-    keyCondition = rtn[1];
-    keyStream2 = rtn[2];
-
-    nrFields = updateLookup.length;
-    rtn = Utils.normalizeArrays(nrFields, updateStream);
-    updateStream = rtn[0];
-  }
 }
diff --git 
a/plugins/transforms/update/src/main/resources/org/apache/hop/pipeline/transforms/update/messages/messages_en_US.properties
 
b/plugins/transforms/update/src/main/resources/org/apache/hop/pipeline/transforms/update/messages/messages_en_US.properties
index 45d9a91..810a9d8 100644
--- 
a/plugins/transforms/update/src/main/resources/org/apache/hop/pipeline/transforms/update/messages/messages_en_US.properties
+++ 
b/plugins/transforms/update/src/main/resources/org/apache/hop/pipeline/transforms/update/messages/messages_en_US.properties
@@ -98,19 +98,22 @@ UpdateDialog..Commit.Label=Commit size
 UpdateMeta.CheckResult.CouldNotReadTableInfo=Couldn''t read the table info, 
please check the table-name & permissions.
 UpdateDialog.NoSQLNeeds.DialogMessage=No SQL needs to be executed to make this 
transform function properly.
 UpdateDialog.Log.FoundFields=Found {0} fields
-UpdateMeta.Injection.SCHEMA_NAME=The name of the database schema to use.
-UpdateMeta.Injection.TABLE_NAME=The name of the table to use.
-UpdateMeta.Injection.KEYS=Lookup Keys
-UpdateMeta.Injection.KEY_STREAM=The field in the input stream to compare with.
-UpdateMeta.Injection.KEY_LOOKUP=The field in the table to compare with.
-UpdateMeta.Injection.KEY_CONDITION=The type of comparator to use.
-UpdateMeta.Injection.KEY_STREAM2=The field in the input stream to compare with.
-UpdateMeta.Injection.UPDATES=Update Fields
-UpdateMeta.Injection.UPDATE_LOOKUP=The field in the table to update.
-UpdateMeta.Injection.UPDATE_STREAM=The field in the stream to map to the table 
field.
-UpdateMeta.Injection.COMMIT_SIZE=The number of rows to commit at a time.
-UpdateMeta.Injection.BATCH_UPDATE=Set this flag to perform batch updates.
-UpdateMeta.Injection.SKIP_LOOKUP=Set this flag to skip lookups.
-UpdateMeta.Injection.IGNORE_LOOKUP_FAILURE=Set this flag to ignore lookup 
failures.
-UpdateMeta.Injection.FLAG_FIELD=The optional field to use to output successful 
key lookups.
-UpdateMeta.Injection.CONNECTIONNAME=The name of the database connection.
\ No newline at end of file
+
+UpdateMeta.Injection.SchemaName=The name of the database schema to use.
+UpdateMeta.Injection.TableName=The name of the table to use.
+UpdateMeta.Injection.LookupKeys=Lookup Keys
+UpdateMeta.Injection.LookupKey=Lookup Key
+UpdateMeta.Injection.KeyStream=The field in the input stream to compare with.
+UpdateMeta.Injection.KeyLookup=The field in the table to compare with.
+UpdateMeta.Injection.KeyCondition=The type of comparator to use.
+UpdateMeta.Injection.KeyStream2=The field in the input stream to compare with.
+UpdateMeta.Injection.UpdateKeys=Update Fields
+UpdateMeta.Injection.UpdateKey=Update Field
+UpdateMeta.Injection.UpdateLookup=The field in the table to update.
+UpdateMeta.Injection.UpdateStream=The field in the stream to map to the table 
field.
+UpdateMeta.Injection.CommitSize=The number of rows to commit at a time.
+UpdateMeta.Injection.UseBatchUpdate=Set this flag to perform batch updates.
+UpdateMeta.Injection.SkipLookup=Set this flag to skip lookups.
+UpdateMeta.Injection.IgnoreLookupFailure=Set this flag to ignore lookup 
failures.
+UpdateMeta.Injection.IgnoreFlagField=The optional field to use to output 
successful key lookups.
+UpdateMeta.Injection.Connection=The name of the database connection.
\ No newline at end of file
diff --git 
a/plugins/transforms/update/src/main/resources/org/apache/hop/pipeline/transforms/update/messages/messages_en_US.properties
 
b/plugins/transforms/update/src/main/resources/org/apache/hop/pipeline/transforms/update/messages/messages_it_IT.properties
similarity index 72%
copy from 
plugins/transforms/update/src/main/resources/org/apache/hop/pipeline/transforms/update/messages/messages_en_US.properties
copy to 
plugins/transforms/update/src/main/resources/org/apache/hop/pipeline/transforms/update/messages/messages_it_IT.properties
index 45d9a91..090e2f2 100644
--- 
a/plugins/transforms/update/src/main/resources/org/apache/hop/pipeline/transforms/update/messages/messages_en_US.properties
+++ 
b/plugins/transforms/update/src/main/resources/org/apache/hop/pipeline/transforms/update/messages/messages_it_IT.properties
@@ -46,7 +46,7 @@ UpdateMeta.CheckResult.MissingFieldsInInput2=Missing fields, 
not found in input
 UpdateMeta.ColumnName.NewName=new name \#
 UpdateMeta.ReturnValue.ErrorOccurred=An error occurred\: 
 Update.Log.LineNumber=linenr 
-UpdateDialog.TargetTable.Label=Target table 
+UpdateDialog.TargetTable.Label=Taabella di destinazione 
 UpdateDialog.FailedToGetFields.DialogMessage=Unable to get fields from 
previous transforms because of an error
 UpdateMeta.CheckResult.NoInputError=No input received from other transforms\!
 UpdateMeta.CheckResult.MissingInputStreamFields=Missing input stream fields to 
update/insert the target table with\:
@@ -54,63 +54,66 @@ UpdateDialog.SkipLookup.Label=Skip lookup
 Update.Exception.FieldRequired=Field [{0}] is required and couldn''t be found\!
 UpdateMeta.CheckResult.TransformReceivingInfoFromOtherTransforms=Transform is 
receiving info from other transforms.
 UpdateDialog.GetSchemas.Error=ERROR
-UpdateDialog.ColumnInfo.Comparator=Comparator
-UpdateMeta.CheckResult.TableNameOK=Table name is filled in.
+UpdateDialog.ColumnInfo.Comparator=Comparatore
+UpdateMeta.CheckResult.TableNameOK=Il nome della tabella \u00E8 stato inserito 
correttamente.
 UpdateMeta.CheckResult.TransformReceivingDatas=Transform is connected to 
previous one, receiving {0} fields
-Update.Log.UpdateRow=Update row with\: 
+Update.Log.UpdateRow=Aggiorna la riga con\: 
 UpdateDialog.FailedToGetFields.DialogTitle=Get fields failed
-UpdateMeta.CheckResult.AllLookupFieldsFound=All lookup fields found in the 
table.
+UpdateMeta.CheckResult.AllLookupFieldsFound=Tutti i campi di ricerca sono 
stati trovati nella tabella.
 UpdateDialog.TransformMeta.Title=CombinationLookup
 UpdateDialog.AvailableSchemas.Message=Please select a schema name
 UpdateDialog.NoSchema.Error=There is no schema available
-UpdateDialog.Key.Label=The key(s) to look up the value(s)\: 
-UpdateDialog.ErrorIgnored.Label=Ignore lookup failure? 
+UpdateDialog.Key.Label=Chiavi di ricerca\: 
+UpdateDialog.ErrorIgnored.Label=Ignora i lookup failure? 
 Update.Log.FoundRow=Found row\: 
-UpdateDialog.ColumnInfo.TableField=Table field
+UpdateDialog.ColumnInfo.TableField=Campo tabella
 UpdateDialog.ErrorGettingSchemas=Please select a schema name
-UpdateDialog.GetFields.Button=\ &Get fields 
+UpdateDialog.GetFields.Button=\ &Campi chiave 
 UpdateDialog.CouldNotBuildSQL.DialogMessage=Unable to build the SQL statement 
because of an error
 UpdateMeta.CheckResult.DatabaseErrorOccurred=A database error occurred\: 
 UpdateMeta.CheckResult.AllFieldsFoundInInput=All fields found in the input 
stream.
 UpdateDialog.InvalidConnection.DialogMessage=Please select a valid connection\!
 UpdateDialog.Log.GettingKeyInfo=getting key info...
-UpdateDialog.GetAndUpdateFields=\ Get &update fields 
+UpdateDialog.GetAndUpdateFields=\ Campi da &aggiornare 
 UpdateMeta.CheckResult.MissingCompareFieldsInTargetTable=Missing compare 
fields in target table\:
 UpdateMeta.CheckResult.MissingFieldsToUpdateInTargetTable=Missing fields to 
update/insert in target table\:
 UpdateDialog.AvailableSchemas.Title=Available schemas
 UpdateDialog.Shell.Title=Update
-UpdateDialog.Batch.Label=Use batch updates?
+UpdateDialog.Batch.Label=Abilita gli update a batch?
 Update.Log.FieldHasDataNumbers=Field [{0}] has nr. 
 UpdateMeta.CheckResult.MissingKeyFields=No key fields are specified.  Please 
specify the fields use as lookup key for this table.
 UpdateMeta.ReturnValue.NotReceivingAnyFields=Not receiving any fields from 
previous transforms. Check the previous transforms for errors & the connecting 
hops.
 UpdateDialog.SQLError.DialogTitle=ERROR
-UpdateDialog.Return.Label=Update fields\: 
+UpdateDialog.Return.Label=Campi da aggiornare\: 
 Update.Log.ErrorInTransform=Error in transform, asking everyone to stop 
because of\:
 UpdateMeta.CheckResult.AllFieldsToUpdateFoundInTargetTable=All insert/update 
fields found in the table.
-UpdateDialog.ColumnInfo.StreamField2=Stream field2
+UpdateDialog.ColumnInfo.StreamField2=Campo stream2
 UpdateDialog.Browse.Button=&Browse...
 UpdateMeta.CheckResult.AllFieldsFoundInInput2=All insert/update fields found 
in the input stream.
-UpdateDialog.TargetSchema.Label=Target schema
-UpdateDialog.ColumnInfo.StreamField1=Stream field1
+UpdateDialog.TargetSchema.Label=Schema di destinazione
+UpdateDialog.ColumnInfo.StreamField1=Campo stream1
 Update.Log.UnableToCommitUpdateConnection=Unable to commit Update connection [
-UpdateDialog.FlagField.Label=Flag field (key found) 
+UpdateDialog.FlagField.Label=Flag field (chiave trovata) 
 UpdateDialog..Commit.Label=Commit size 
 UpdateMeta.CheckResult.CouldNotReadTableInfo=Couldn''t read the table info, 
please check the table-name & permissions.
 UpdateDialog.NoSQLNeeds.DialogMessage=No SQL needs to be executed to make this 
transform function properly.
-UpdateDialog.Log.FoundFields=Found {0} fields
-UpdateMeta.Injection.SCHEMA_NAME=The name of the database schema to use.
-UpdateMeta.Injection.TABLE_NAME=The name of the table to use.
-UpdateMeta.Injection.KEYS=Lookup Keys
-UpdateMeta.Injection.KEY_STREAM=The field in the input stream to compare with.
-UpdateMeta.Injection.KEY_LOOKUP=The field in the table to compare with.
-UpdateMeta.Injection.KEY_CONDITION=The type of comparator to use.
-UpdateMeta.Injection.KEY_STREAM2=The field in the input stream to compare with.
-UpdateMeta.Injection.UPDATES=Update Fields
-UpdateMeta.Injection.UPDATE_LOOKUP=The field in the table to update.
-UpdateMeta.Injection.UPDATE_STREAM=The field in the stream to map to the table 
field.
-UpdateMeta.Injection.COMMIT_SIZE=The number of rows to commit at a time.
-UpdateMeta.Injection.BATCH_UPDATE=Set this flag to perform batch updates.
-UpdateMeta.Injection.SKIP_LOOKUP=Set this flag to skip lookups.
-UpdateMeta.Injection.IGNORE_LOOKUP_FAILURE=Set this flag to ignore lookup 
failures.
-UpdateMeta.Injection.FLAG_FIELD=The optional field to use to output successful 
key lookups.
-UpdateMeta.Injection.CONNECTIONNAME=The name of the database connection.
\ No newline at end of file
+UpdateDialog.Log.FoundFields=Trovati {0} campi
+
+UpdateMeta.Injection.SchemaName=The name of the database schema to use.
+UpdateMeta.Injection.TableName=The name of the table to use.
+UpdateMeta.Injection.LookupKeys=Lookup Keys
+UpdateMeta.Injection.LookupKey=Lookup Key
+UpdateMeta.Injection.KeyStream=The field in the input stream to compare with.
+UpdateMeta.Injection.KeyLookup=The field in the table to compare with.
+UpdateMeta.Injection.KeyCondition=The type of comparator to use.
+UpdateMeta.Injection.KeyStream2=The field in the input stream to compare with.
+UpdateMeta.Injection.UpdateKeys=Update Fields
+UpdateMeta.Injection.UpdateKey=Update Field
+UpdateMeta.Injection.UpdateLookup=The field in the table to update.
+UpdateMeta.Injection.UpdateStream=The field in the stream to map to the table 
field.
+UpdateMeta.Injection.CommitSize=The number of rows to commit at a time.
+UpdateMeta.Injection.UseBatchUpdate=Set this flag to perform batch updates.
+UpdateMeta.Injection.SkipLookup=Set this flag to skip lookups.
+UpdateMeta.Injection.IgnoreLookupFailure=Set this flag to ignore lookup 
failures.
+UpdateMeta.Injection.IgnoreFlagField=The optional field to use to output 
successful key lookups.
+UpdateMeta.Injection.Connection=The name of the database connection.
\ No newline at end of file
diff --git 
a/plugins/transforms/update/src/test/java/org/apache/hop/pipeline/transforms/update/UpdateMetaInjectionTest.java
 
b/plugins/transforms/update/src/test/java/org/apache/hop/pipeline/transforms/update/UpdateMetaInjectionTest.java
index 8414fb4..8dbbe1e 100644
--- 
a/plugins/transforms/update/src/test/java/org/apache/hop/pipeline/transforms/update/UpdateMetaInjectionTest.java
+++ 
b/plugins/transforms/update/src/test/java/org/apache/hop/pipeline/transforms/update/UpdateMetaInjectionTest.java
@@ -31,21 +31,4 @@ public class UpdateMetaInjectionTest extends 
BaseMetadataInjectionTest<UpdateMet
     setup(new UpdateMeta());
   }
 
-  @Test
-  public void test() throws Exception {
-    check("SCHEMA_NAME", () -> meta.getSchemaName());
-    check("TABLE_NAME", () -> meta.getTableName());
-    check("COMMIT_SIZE", () -> meta.getCommitSizeVar());
-    check("BATCH_UPDATE", () -> meta.useBatchUpdate());
-    check("SKIP_LOOKUP", () -> meta.isSkipLookup());
-    check("IGNORE_LOOKUP_FAILURE", () -> meta.isErrorIgnored());
-    check("FLAG_FIELD", () -> meta.getIgnoreFlagField());
-    check("KEY_STREAM", () -> meta.getKeyStream()[0]);
-    check("KEY_LOOKUP", () -> meta.getKeyLookup()[0]);
-    check("KEY_CONDITION", () -> meta.getKeyCondition()[0]);
-    check("KEY_STREAM2", () -> meta.getKeyStream2()[0]);
-    check("UPDATE_LOOKUP", () -> meta.getUpdateLookup()[0]);
-    check("UPDATE_STREAM", () -> meta.getUpdateStream()[0]);
-    skipPropertyTest("CONNECTIONNAME");
-  }
 }
diff --git 
a/plugins/transforms/update/src/test/java/org/apache/hop/pipeline/transforms/update/UpdateMetaTest.java
 
b/plugins/transforms/update/src/test/java/org/apache/hop/pipeline/transforms/update/UpdateMetaTest.java
index 8480298..ea4ffab 100644
--- 
a/plugins/transforms/update/src/test/java/org/apache/hop/pipeline/transforms/update/UpdateMetaTest.java
+++ 
b/plugins/transforms/update/src/test/java/org/apache/hop/pipeline/transforms/update/UpdateMetaTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.hop.pipeline.transforms.update;
 
+import org.apache.commons.lang.builder.EqualsBuilder;
 import org.apache.hop.core.HopEnvironment;
 import org.apache.hop.core.exception.HopException;
 import org.apache.hop.core.logging.ILoggingObject;
@@ -30,10 +31,10 @@ import org.apache.hop.pipeline.transform.ITransformMeta;
 import org.apache.hop.pipeline.transform.TransformMeta;
 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.ArrayLoadSaveValidator;
-import 
org.apache.hop.pipeline.transforms.loadsave.validator.DatabaseMetaLoadSaveValidator;
 import 
org.apache.hop.pipeline.transforms.loadsave.validator.IFieldLoadSaveValidator;
-import 
org.apache.hop.pipeline.transforms.loadsave.validator.StringLoadSaveValidator;
+import 
org.apache.hop.pipeline.transforms.loadsave.validator.IFieldLoadSaveValidatorFactory;
+import 
org.apache.hop.pipeline.transforms.loadsave.validator.ListLoadSaveValidator;
+import org.apache.hop.pipeline.transforms.loadsave.validator.ObjectValidator;
 import org.apache.hop.pipeline.transforms.mock.TransformMockHelper;
 import org.junit.After;
 import org.junit.Before;
@@ -43,7 +44,8 @@ import org.mockito.Mockito;
 
 import java.util.*;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 public class UpdateMetaTest implements IInitializer<ITransformMeta> {
   @ClassRule public static RestoreHopEngineEnvironment env = new 
RestoreHopEngineEnvironment();
@@ -85,71 +87,40 @@ public class UpdateMetaTest implements 
IInitializer<ITransformMeta> {
 
     List<String> attributes =
         Arrays.asList(
-            "schemaName",
-            "tableName",
-            "commitSize",
-            "errorIgnored",
-            "ignoreFlagField",
-            "skipLookup",
-            "useBatchUpdate",
-            "keyStream",
-            "keyLookup",
-            "keyCondition",
-            "keyStream2",
-            "updateLookup",
-            "updateStream",
-            "databaseMeta");
+            "connection",
+            "lookup",
+            "commit",
+            "error_ignored",
+            "ignore_flag_field",
+            "skip_lookup",
+            "use_batch");
 
     Map<String, String> getterMap =
         new HashMap<String, String>() {
           {
-            put("schemaName", "getSchemaName");
-            put("tableName", "getTableName");
-            put("commitSize", "getCommitSizeVar");
-            put("errorIgnored", "isErrorIgnored");
-            put("ignoreFlagField", "getIgnoreFlagField");
-            put("skipLookup", "isSkipLookup");
-            put("useBatchUpdate", "useBatchUpdate");
-            put("keyStream", "getKeyStream");
-            put("keyLookup", "getKeyLookup");
-            put("keyCondition", "getKeyCondition");
-            put("keyStream2", "getKeyStream2");
-            put("updateLookup", "getUpdateLookup");
-            put("updateStream", "getUpdateStream");
-            put("databaseMeta", "getDatabaseMeta");
+            put("connection", "getConnection");
+            put("lookup", "getLookupField");
+            put("commit", "getCommitSize");
+            put("error_ignored", "isErrorIgnored");
+            put("ignore_flag_field", "getIgnoreFlagField");
+            put("skip_lookup", "isSkipLookup");
+            put("use_batch", "isUseBatchUpdate");
           }
         };
     Map<String, String> setterMap =
         new HashMap<String, String>() {
           {
-            put("schemaName", "setSchemaName");
-            put("tableName", "setTableName");
-            put("commitSize", "setCommitSize");
-            put("errorIgnored", "setErrorIgnored");
-            put("ignoreFlagField", "setIgnoreFlagField");
-            put("skipLookup", "setSkipLookup");
-            put("useBatchUpdate", "setUseBatchUpdate");
-            put("keyStream", "setKeyStream");
-            put("keyLookup", "setKeyLookup");
-            put("keyCondition", "setKeyCondition");
-            put("keyStream2", "setKeyStream2");
-            put("updateLookup", "setUpdateLookup");
-            put("updateStream", "setUpdateStream");
-            put("databaseMeta", "setDatabaseMeta");
+            put("connection", "setConnection");
+            put("lookup", "setLookupField");
+            put("commit", "setCommitSize");
+            put("error_ignored", "setErrorIgnored");
+            put("ignore_flag_field", "setIgnoreFlagField");
+            put("skip_lookup", "setSkipLookup");
+            put("use_batch", "setUseBatchUpdate");
           }
         };
-    IFieldLoadSaveValidator<String[]> stringArrayLoadSaveValidator =
-        new ArrayLoadSaveValidator<>(new StringLoadSaveValidator(), 5);
 
     Map<String, IFieldLoadSaveValidator<?>> attrValidatorMap = new HashMap<>();
-    attrValidatorMap.put("keyStream", stringArrayLoadSaveValidator);
-    attrValidatorMap.put("keyLookup", stringArrayLoadSaveValidator);
-    attrValidatorMap.put("keyCondition", stringArrayLoadSaveValidator);
-    attrValidatorMap.put("keyStream2", stringArrayLoadSaveValidator);
-    attrValidatorMap.put("updateLookup", stringArrayLoadSaveValidator);
-    attrValidatorMap.put("updateStream", stringArrayLoadSaveValidator);
-    attrValidatorMap.put("databaseMeta", new DatabaseMetaLoadSaveValidator());
-
     Map<String, IFieldLoadSaveValidator<?>> typeValidatorMap = new HashMap<>();
 
     loadSaveTester =
@@ -162,6 +133,89 @@ public class UpdateMetaTest implements 
IInitializer<ITransformMeta> {
             attrValidatorMap,
             typeValidatorMap,
             this);
+
+    IFieldLoadSaveValidatorFactory validatorFactory =
+        loadSaveTester.getFieldLoadSaveValidatorFactory();
+
+
+    validatorFactory.registerValidator(
+            validatorFactory.getName(UpdateLookupField.class),
+            new ObjectValidator<UpdateLookupField>(
+                    validatorFactory,
+                    UpdateLookupField.class,
+                    Arrays.asList("schema", "table", "key", "value"),
+                    new HashMap<String, String>() {
+                      {
+                        put("schema", "getSchemaName");
+                        put("table", "getTableName");
+                        put("key", "getLookupKeys");
+                        put("value", "getUpdateFields");
+                      }
+                    },
+                    new HashMap<String, String>() {
+                      {
+                        put("schema", "setSchemaName");
+                        put("table", "setTableName");
+                        put("key", "setLookupKeys");
+                        put("value", "setUpdateFields");
+                      }
+                    }));
+
+    validatorFactory.registerValidator(
+            validatorFactory.getName(List.class, UpdateLookupField.class),
+            new ListLoadSaveValidator<UpdateLookupField>(new 
UpdateLookupFieldLoadSaveValidator()));
+
+
+
+    validatorFactory.registerValidator(
+        validatorFactory.getName(UpdateKeyField.class),
+        new ObjectValidator<UpdateKeyField>(
+            validatorFactory,
+            UpdateKeyField.class,
+            Arrays.asList("name", "field", "condition", "name2"),
+            new HashMap<String, String>() {
+              {
+                put("name", "getKeyStream");
+                put("field", "getKeyLookup");
+                put("condition", "getKeyCondition");
+                put("name2", "getKeyStream2");
+              }
+            },
+            new HashMap<String, String>() {
+              {
+                put("name", "setKeyStream");
+                put("field", "setKeyLookup");
+                put("condition", "setKeyCondition");
+                put("name2", "setKeyStream2");
+              }
+            }));
+
+    validatorFactory.registerValidator(
+        validatorFactory.getName(List.class, UpdateKeyField.class),
+        new ListLoadSaveValidator<UpdateKeyField>(new 
UpdateKeyFieldLoadSaveValidator()));
+
+    validatorFactory.registerValidator(
+        validatorFactory.getName(UpdateField.class),
+        new ObjectValidator<UpdateField>(
+            validatorFactory,
+            UpdateField.class,
+            Arrays.asList("name", "rename"),
+            new HashMap<String, String>() {
+              {
+                put("name", "getUpdateLookup");
+                put("rename", "getUpdateStream");
+              }
+            },
+            new HashMap<String, String>() {
+              {
+                put("name", "setUpdateLookup");
+                put("rename", "setUpdateStream");
+              }
+            }));
+
+    validatorFactory.registerValidator(
+        validatorFactory.getName(List.class, UpdateField.class),
+        new ListLoadSaveValidator<UpdateField>(new 
UpdateFieldLoadSaveValidator()));
   }
 
   @After
@@ -194,8 +248,26 @@ public class UpdateMetaTest implements 
IInitializer<ITransformMeta> {
   // Call the allocate method on the LoadSaveTester meta class
   @Override
   public void modify(ITransformMeta someMeta) {
+
     if (someMeta instanceof UpdateMeta) {
-      ((UpdateMeta) someMeta).allocate(5, 5);
+      UpdateLookupField dlf = ((UpdateMeta) someMeta).getLookupField();
+      dlf.getLookupKeys().clear();
+      dlf.getLookupKeys()
+          .addAll(
+              Arrays.asList(
+                  new UpdateKeyField("StreamField1", "=", "1", null),
+                  new UpdateKeyField("StreamField2", "<>", "20", null),
+                  new UpdateKeyField("StreamField3", "BETWEEN", "1", "10"),
+                  new UpdateKeyField("StreamField4", "<=", "3", null),
+                  new UpdateKeyField("StreamField5", ">=", "40", null)));
+      dlf.getUpdateFields()
+          .addAll(
+              Arrays.asList(
+                  new UpdateField("TableField1", "StreamField1"),
+                  new UpdateField("TableField2", "StreamField2"),
+                  new UpdateField("TableField3", "StreamField3"),
+                  new UpdateField("TableField4", "StreamField4"),
+                  new UpdateField("TableField5", "StreamField5")));
     }
   }
 
@@ -204,34 +276,94 @@ public class UpdateMetaTest implements 
IInitializer<ITransformMeta> {
     loadSaveTester.testSerialization();
   }
 
-  @Test
-  public void testPDI16559() throws Exception {
-    UpdateMeta update = new UpdateMeta();
-    update.setKeyStream(new String[] {"field1", "field2", "field3", "field4", 
"field5"});
-    update.setKeyLookup(new String[] {"lkup1", "lkup2"});
-    update.setKeyCondition(new String[] {"cond1", "cond2", "cond3"});
-    update.setKeyStream2(new String[] {"str21", "str22", "str23", "str24"});
 
-    update.setUpdateLookup(new String[] {"updlkup1", "updlkup2", "updlkup3", 
"updlkup4"});
-    update.setUpdateStream(new String[] {"updlkup1", "updlkup2"});
+  public class UpdateLookupFieldLoadSaveValidator
+          implements IFieldLoadSaveValidator<UpdateLookupField> {
+    final Random rand = new Random();
 
-    try {
-      String badXml = update.getXml();
-      fail("Before calling afterInjectionSynchronization, should have thrown 
an ArrayIndexOOB");
-    } catch (Exception expected) {
-      // Do Nothing
+    @Override
+    public UpdateLookupField getTestObject() {
+
+      UpdateLookupField field =
+              new UpdateLookupField(
+                      UUID.randomUUID().toString(),
+                      UUID.randomUUID().toString(),
+                      new ArrayList<UpdateKeyField>(),
+                      new ArrayList<UpdateField>());
+
+      return field;
     }
-    update.afterInjectionSynchronization();
-    // run without a exception
-    String ktrXml = update.getXml();
 
-    int targetSz = update.getKeyStream().length;
+    @Override
+    public boolean validateTestObject(UpdateLookupField testObject, Object 
actual) {
+      if (!(actual instanceof UpdateLookupField)) {
+        return false;
+      }
+      UpdateLookupField another = (UpdateLookupField) actual;
+      return new EqualsBuilder()
+          .append(testObject.getSchemaName(), another.getSchemaName())
+          .append(testObject.getTableName(), another.getTableName())
+          .append(testObject.getLookupKeys(), another.getLookupKeys())
+          .append(testObject.getUpdateFields(), another.getUpdateFields())
+          .isEquals();
+    }
+  }
+
+  public class UpdateFieldLoadSaveValidator
+      implements IFieldLoadSaveValidator<UpdateField> {
+    final Random rand = new Random();
+
+    @Override
+    public UpdateField getTestObject() {
 
-    assertEquals(targetSz, update.getKeyLookup().length);
-    assertEquals(targetSz, update.getKeyCondition().length);
-    assertEquals(targetSz, update.getKeyStream2().length);
+      UpdateField field =
+          new UpdateField(UUID.randomUUID().toString(), 
UUID.randomUUID().toString());
 
-    targetSz = update.getUpdateLookup().length;
-    assertEquals(targetSz, update.getUpdateStream().length);
+      return field;
+    }
+
+    @Override
+    public boolean validateTestObject(UpdateField testObject, Object actual) {
+      if (!(actual instanceof UpdateField)) {
+        return false;
+      }
+      UpdateField another = (UpdateField) actual;
+      return new EqualsBuilder()
+          .append(testObject.getUpdateLookup(), another.getUpdateLookup())
+          .append(testObject.getUpdateStream(), another.getUpdateStream())
+          .isEquals();
+    }
+  }
+
+  public class UpdateKeyFieldLoadSaveValidator
+      implements IFieldLoadSaveValidator<UpdateKeyField> {
+    final Random rand = new Random();
+
+    @Override
+    public UpdateKeyField getTestObject() {
+
+      UpdateKeyField field =
+          new UpdateKeyField(
+              UUID.randomUUID().toString(),
+              "=",
+              UUID.randomUUID().toString(),
+              UUID.randomUUID().toString());
+
+      return field;
+    }
+
+    @Override
+    public boolean validateTestObject(UpdateKeyField testObject, Object 
actual) {
+      if (!(actual instanceof UpdateKeyField)) {
+        return false;
+      }
+      UpdateKeyField another = (UpdateKeyField) actual;
+      return new EqualsBuilder()
+          .append(testObject.getKeyLookup(), another.getKeyLookup())
+          .append(testObject.getKeyCondition(), another.getKeyCondition())
+          .append(testObject.getKeyStream(), another.getKeyStream())
+          .append(testObject.getKeyStream2(), another.getKeyStream2())
+          .isEquals();
+    }
   }
 }
diff --git 
a/ui/src/main/resources/org/apache/hop/ui/core/database/dialog/messages/messages_en_US.properties
 
b/ui/src/main/resources/org/apache/hop/ui/core/database/dialog/messages/messages_en_US.properties
index 445ee93..163d473 100644
--- 
a/ui/src/main/resources/org/apache/hop/ui/core/database/dialog/messages/messages_en_US.properties
+++ 
b/ui/src/main/resources/org/apache/hop/ui/core/database/dialog/messages/messages_en_US.properties
@@ -19,7 +19,7 @@
 #
 #Sun Jan 10 16:14:33 CET 2021
 GetDatabaseInfoProgressDialog.Error.Title=Error getting information
-SQLEditor.ConnectionCacheCleared.Title=Cache geleert
+SQLEditor.ConnectionCacheCleared.Title=Cache cleared successfully!
 SQLEditor.Result.Message=The SQL statements had the following results
 DatabaseExplorerDialog.Catalogs.Label=Catalogs
 DatabaseExplorer.SelectConnection=Select Connection

Reply via email to