From ffc84256b70ab2380669ceaa7e2593f493396cab Mon Sep 17 00:00:00 2001
From: pesse <derpesse@gmail.com>
Date: Mon, 15 Jul 2019 17:01:40 +0200
Subject: [PATCH 01/12] We don't want to have this publicly accessible

---
 .../api/testRunner/AbstractTestRunnerStatement.java    |  1 -
 .../org/utplsql/api/{ => testRunner}/FileMapper.java   | 10 +++++++---
 .../org/utplsql/api/{ => testRunner}/FileMapperIT.java |  7 ++++++-
 3 files changed, 13 insertions(+), 5 deletions(-)
 rename src/main/java/org/utplsql/api/{ => testRunner}/FileMapper.java (93%)
 rename src/test/java/org/utplsql/api/{ => testRunner}/FileMapperIT.java (88%)

diff --git a/src/main/java/org/utplsql/api/testRunner/AbstractTestRunnerStatement.java b/src/main/java/org/utplsql/api/testRunner/AbstractTestRunnerStatement.java
index dbd5086..d53863e 100644
--- a/src/main/java/org/utplsql/api/testRunner/AbstractTestRunnerStatement.java
+++ b/src/main/java/org/utplsql/api/testRunner/AbstractTestRunnerStatement.java
@@ -2,7 +2,6 @@
 
 import oracle.jdbc.OracleConnection;
 import org.utplsql.api.CustomTypes;
-import org.utplsql.api.FileMapper;
 import org.utplsql.api.FileMapping;
 import org.utplsql.api.TestRunnerOptions;
 
diff --git a/src/main/java/org/utplsql/api/FileMapper.java b/src/main/java/org/utplsql/api/testRunner/FileMapper.java
similarity index 93%
rename from src/main/java/org/utplsql/api/FileMapper.java
rename to src/main/java/org/utplsql/api/testRunner/FileMapper.java
index 1e5ac66..bf08bac 100644
--- a/src/main/java/org/utplsql/api/FileMapper.java
+++ b/src/main/java/org/utplsql/api/testRunner/FileMapper.java
@@ -1,10 +1,14 @@
-package org.utplsql.api;
+package org.utplsql.api.testRunner;
 
 
 import oracle.jdbc.OracleConnection;
 import oracle.jdbc.OracleTypes;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.utplsql.api.CustomTypes;
+import org.utplsql.api.FileMapperOptions;
+import org.utplsql.api.FileMapping;
+import org.utplsql.api.KeyValuePair;
 
 import java.sql.*;
 import java.util.ArrayList;
@@ -21,7 +25,7 @@ private FileMapper() {
     /**
      * Call the database api to build the custom file mappings.
      */
-    public static Array buildFileMappingArray(
+    private static Array buildFileMappingArray(
             Connection conn, FileMapperOptions mapperOptions) throws SQLException {
         OracleConnection oraConn = conn.unwrap(OracleConnection.class);
 
@@ -95,7 +99,7 @@ public static Array buildFileMappingArray(
         return callableStatement.getArray(1);
     }
 
-    public static List<FileMapping> buildFileMappingList(
+    static List<FileMapping> buildFileMappingList(
             Connection conn, FileMapperOptions mapperOptions) throws SQLException {
         java.sql.Array fileMappings = buildFileMappingArray(conn, mapperOptions);
 
diff --git a/src/test/java/org/utplsql/api/FileMapperIT.java b/src/test/java/org/utplsql/api/testRunner/FileMapperIT.java
similarity index 88%
rename from src/test/java/org/utplsql/api/FileMapperIT.java
rename to src/test/java/org/utplsql/api/testRunner/FileMapperIT.java
index 20ff1b4..89a6d9b 100644
--- a/src/test/java/org/utplsql/api/FileMapperIT.java
+++ b/src/test/java/org/utplsql/api/testRunner/FileMapperIT.java
@@ -1,6 +1,11 @@
-package org.utplsql.api;
+package org.utplsql.api.testRunner;
 
 import org.junit.jupiter.api.Test;
+import org.utplsql.api.AbstractDatabaseTest;
+import org.utplsql.api.FileMapperOptions;
+import org.utplsql.api.FileMapping;
+import org.utplsql.api.KeyValuePair;
+import org.utplsql.api.testRunner.FileMapper;
 
 import java.sql.SQLException;
 import java.util.ArrayList;

From 952d3446a7c2e805ea84986d2c302190e4e74f6e Mon Sep 17 00:00:00 2001
From: pesse <derpesse@gmail.com>
Date: Tue, 16 Jul 2019 22:39:15 +0200
Subject: [PATCH 02/12] Default TypeMapping is used on NULL and also empty
 typeMap parameter

Fixes https://github.com/utPLSQL/utPLSQL-cli/issues/162
---
 .../utplsql/api/testRunner/FileMapper.java    |  2 +-
 .../utplsql/api/testRunner/FileMapperIT.java  | 34 +++++++++++++++++++
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/src/main/java/org/utplsql/api/testRunner/FileMapper.java b/src/main/java/org/utplsql/api/testRunner/FileMapper.java
index bf08bac..c6491f8 100644
--- a/src/main/java/org/utplsql/api/testRunner/FileMapper.java
+++ b/src/main/java/org/utplsql/api/testRunner/FileMapper.java
@@ -64,7 +64,7 @@ private static Array buildFileMappingArray(
         callableStatement.setArray(
                 ++paramIdx, oraConn.createOracleArray(CustomTypes.UT_VARCHAR2_LIST, filePathsArray));
 
-        if (mapperOptions.getTypeMappings() == null) {
+        if (mapperOptions.getTypeMappings() == null || mapperOptions.getTypeMappings().size() == 0) {
             callableStatement.setNull(++paramIdx, Types.ARRAY, CustomTypes.UT_KEY_VALUE_PAIRS);
         } else {
             callableStatement.setArray(
diff --git a/src/test/java/org/utplsql/api/testRunner/FileMapperIT.java b/src/test/java/org/utplsql/api/testRunner/FileMapperIT.java
index 89a6d9b..5c7a306 100644
--- a/src/test/java/org/utplsql/api/testRunner/FileMapperIT.java
+++ b/src/test/java/org/utplsql/api/testRunner/FileMapperIT.java
@@ -1,5 +1,6 @@
 package org.utplsql.api.testRunner;
 
+import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.utplsql.api.AbstractDatabaseTest;
 import org.utplsql.api.FileMapperOptions;
@@ -50,4 +51,37 @@ private void assertMapping(FileMapping fileMapping, String owner, String name, S
         assertEquals(type, fileMapping.getObjectType());
     }
 
+    @Nested
+    class Default_type_mapping {
+
+        void checkTypeMapping( List<KeyValuePair> typeMappings ) throws SQLException {
+            List<String> filePaths = java.util.Arrays.asList(
+                    "/award_bonus.prc",
+                    "/betwnstr.fnc",
+                    "/package_body.pkb",
+                    "/type_body.tpb",
+                    "/trigger.trg");
+            FileMapperOptions mapperOptions = new FileMapperOptions(filePaths);
+            mapperOptions.setTypeMappings(typeMappings);
+
+            List<FileMapping> fileMappings = FileMapper.buildFileMappingList(getConnection(), mapperOptions);
+
+            assertEquals("PROCEDURE", fileMappings.get(0).getObjectType());
+            assertEquals("FUNCTION", fileMappings.get(1).getObjectType());
+            assertEquals("PACKAGE BODY", fileMappings.get(2).getObjectType());
+            assertEquals("TYPE BODY", fileMappings.get(3).getObjectType());
+            assertEquals("TRIGGER", fileMappings.get(4).getObjectType());
+        }
+
+        @Test
+        void is_used_on_null_parameter() throws SQLException {
+            checkTypeMapping(null);
+        }
+
+        @Test
+        void is_used_on_empty_parameter() throws SQLException {
+            checkTypeMapping(new ArrayList<>());
+        }
+    }
+
 }

From 8a326f9977463908acbe2eaea308a2642316766e Mon Sep 17 00:00:00 2001
From: pesse <derpesse@gmail.com>
Date: Tue, 16 Jul 2019 22:39:34 +0200
Subject: [PATCH 03/12] FileMapper doesn't need to be public

---
 src/main/java/org/utplsql/api/testRunner/FileMapper.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/java/org/utplsql/api/testRunner/FileMapper.java b/src/main/java/org/utplsql/api/testRunner/FileMapper.java
index c6491f8..1d7a48e 100644
--- a/src/main/java/org/utplsql/api/testRunner/FileMapper.java
+++ b/src/main/java/org/utplsql/api/testRunner/FileMapper.java
@@ -15,7 +15,7 @@
 import java.util.List;
 import java.util.Map;
 
-public final class FileMapper {
+final class FileMapper {
 
     private static final Logger logger = LoggerFactory.getLogger(FileMapper.class);
 

From d329e8eb3944cdc19c8f0617fd1e37d520ae8c86 Mon Sep 17 00:00:00 2001
From: pesse <derpesse@gmail.com>
Date: Thu, 18 Jul 2019 22:57:26 +0200
Subject: [PATCH 04/12] Simple DynamicParameterList object to make some PL/SQL
 calls easier

---
 .../utplsql/api/db/DynamicParameterList.java  | 28 ++++++++++++++++++
 .../api/db/DynamicParameterListBuilder.java   | 29 +++++++++++++++++++
 .../api/db/DynamicParameterListTest.java      | 29 +++++++++++++++++++
 3 files changed, 86 insertions(+)
 create mode 100644 src/main/java/org/utplsql/api/db/DynamicParameterList.java
 create mode 100644 src/main/java/org/utplsql/api/db/DynamicParameterListBuilder.java
 create mode 100644 src/test/java/org/utplsql/api/db/DynamicParameterListTest.java

diff --git a/src/main/java/org/utplsql/api/db/DynamicParameterList.java b/src/main/java/org/utplsql/api/db/DynamicParameterList.java
new file mode 100644
index 0000000..6ee4e2f
--- /dev/null
+++ b/src/main/java/org/utplsql/api/db/DynamicParameterList.java
@@ -0,0 +1,28 @@
+package org.utplsql.api.db;
+
+import java.util.LinkedHashMap;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+public class DynamicParameterList {
+
+    LinkedHashMap<String, Consumer<Integer>> params;
+
+    DynamicParameterList(LinkedHashMap<String, Consumer<Integer>> params) {
+        this.params = params;
+    }
+
+    public String getSql() {
+        return params.keySet().stream()
+                .map(e -> e + " = ?")
+                .collect(Collectors.joining(", "));
+    }
+
+    public void applyFromIndex( int startIndex ) {
+        int index = startIndex;
+        for ( Consumer<Integer> function : params.values() ) {
+            function.accept(index++);
+        }
+    }
+
+}
diff --git a/src/main/java/org/utplsql/api/db/DynamicParameterListBuilder.java b/src/main/java/org/utplsql/api/db/DynamicParameterListBuilder.java
new file mode 100644
index 0000000..898da8e
--- /dev/null
+++ b/src/main/java/org/utplsql/api/db/DynamicParameterListBuilder.java
@@ -0,0 +1,29 @@
+package org.utplsql.api.db;
+
+import java.util.LinkedHashMap;
+import java.util.function.Consumer;
+
+public class DynamicParameterListBuilder {
+
+    private LinkedHashMap<String, Consumer<Integer>> params = new LinkedHashMap<>();
+
+    private DynamicParameterListBuilder() {
+
+    }
+
+    public DynamicParameterListBuilder addParameter(String identifier, Consumer<Integer> function) {
+
+        params.put(identifier, function);
+
+        return this;
+    }
+
+    public DynamicParameterList build() {
+        return new DynamicParameterList(params);
+    }
+
+
+    public static DynamicParameterListBuilder create() {
+        return new DynamicParameterListBuilder();
+    }
+}
diff --git a/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java b/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java
new file mode 100644
index 0000000..daf0dd7
--- /dev/null
+++ b/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java
@@ -0,0 +1,29 @@
+package org.utplsql.api.db;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class DynamicParameterListTest {
+
+    @Test
+    void firstTest() {
+
+        final ArrayList<Object> resultArray = new ArrayList<>();
+
+        DynamicParameterList parameterList = DynamicParameterListBuilder.create()
+                .addParameter("a_object_owner", i -> resultArray.add(i + ": MyOwner"))
+                .addParameter("a_num_param", i -> resultArray.add( i + ": 123"))
+                .build();
+
+        parameterList.applyFromIndex(5);
+        assertEquals("a_object_owner = ?, a_num_param = ?", parameterList.getSql());
+
+        ArrayList<Object> expectedList = new ArrayList<>();
+        expectedList.add("5: MyOwner");
+        expectedList.add("6: 123");
+        assertEquals( expectedList, resultArray);
+    }
+}

From e6f3a572597a69335b259deaef54c334b7c2947f Mon Sep 17 00:00:00 2001
From: pesse <derpesse@gmail.com>
Date: Thu, 18 Jul 2019 23:48:17 +0200
Subject: [PATCH 05/12] Let's do it cleaner and use several DynamicParameter
 implementations

---
 build.gradle.kts                              |  4 +
 .../utplsql/api/db/DynamicParameterList.java  | 75 +++++++++++++++++--
 .../api/db/DynamicParameterListBuilder.java   | 23 ++++--
 .../api/db/DynamicParameterListTest.java      | 30 +++++---
 4 files changed, 110 insertions(+), 22 deletions(-)

diff --git a/build.gradle.kts b/build.gradle.kts
index a8c6dc2..a997de9 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -38,6 +38,7 @@ repositories {
         }
     }
     mavenCentral()
+    jcenter()
 }
 
 dependencies {
@@ -55,6 +56,9 @@ dependencies {
     testImplementation("org.junit.jupiter:junit-jupiter:$junitVersion")
     testImplementation("org.hamcrest:hamcrest:2.1")
 
+    // Mockito
+    testCompile("org.mockito:mockito-core:2.+")
+
     // deployer for packagecloud
     deployerJars("io.packagecloud.maven.wagon:maven-packagecloud-wagon:0.0.6")
 }
diff --git a/src/main/java/org/utplsql/api/db/DynamicParameterList.java b/src/main/java/org/utplsql/api/db/DynamicParameterList.java
index 6ee4e2f..c4a92be 100644
--- a/src/main/java/org/utplsql/api/db/DynamicParameterList.java
+++ b/src/main/java/org/utplsql/api/db/DynamicParameterList.java
@@ -1,14 +1,77 @@
 package org.utplsql.api.db;
 
+import oracle.jdbc.OracleConnection;
+
+import java.sql.CallableStatement;
+import java.sql.SQLException;
+import java.sql.Types;
 import java.util.LinkedHashMap;
-import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
 public class DynamicParameterList {
 
-    LinkedHashMap<String, Consumer<Integer>> params;
+    LinkedHashMap<String, DynamicParameter> params;
+
+    interface DynamicParameter {
+        void setParam( CallableStatement statement, int index ) throws SQLException;
+    }
+
+    static class DynamicStringParameter implements DynamicParameter {
+        private final String value;
+
+        DynamicStringParameter( String value ) {
+            this.value = value;
+        }
+
+        @Override
+        public void setParam(CallableStatement statement, int index) throws SQLException {
+            if ( value == null ) {
+                statement.setNull(index, Types.VARCHAR);
+            } else {
+                statement.setString(index, value);
+            }
+        }
+    }
+    static class DynamicIntegerParameter implements DynamicParameter {
+        private final Integer value;
+
+        DynamicIntegerParameter( Integer value ) {
+            this.value = value;
+        }
+
+        @Override
+        public void setParam(CallableStatement statement, int index) throws SQLException {
+            if ( value == null ) {
+                statement.setNull(index, Types.INTEGER);
+            } else {
+                statement.setInt(index, value);
+            }
+        }
+    }
+    static class DynamicArrayParameter implements DynamicParameter {
+        private final Object[] value;
+        private final String customTypeName;
+        private final OracleConnection oraConnection;
+
+        DynamicArrayParameter( Object[] value, String customTypeName, OracleConnection oraConnection ) {
+            this.value = value;
+            this.customTypeName = customTypeName;
+            this.oraConnection = oraConnection;
+        }
+
+        @Override
+        public void setParam(CallableStatement statement, int index) throws SQLException {
+            if ( value == null ) {
+                statement.setNull(index, Types.ARRAY, customTypeName);
+            } else {
+                statement.setArray(
+                        index, oraConnection.createOracleArray(customTypeName, value)
+                );
+            }
+        }
+    }
 
-    DynamicParameterList(LinkedHashMap<String, Consumer<Integer>> params) {
+    DynamicParameterList(LinkedHashMap<String, DynamicParameter> params) {
         this.params = params;
     }
 
@@ -18,10 +81,10 @@ public String getSql() {
                 .collect(Collectors.joining(", "));
     }
 
-    public void applyFromIndex( int startIndex ) {
+    public void setParamsStartWithIndex(CallableStatement statement, int startIndex ) throws SQLException {
         int index = startIndex;
-        for ( Consumer<Integer> function : params.values() ) {
-            function.accept(index++);
+        for ( DynamicParameter param : params.values() ) {
+            param.setParam(statement, index++);
         }
     }
 
diff --git a/src/main/java/org/utplsql/api/db/DynamicParameterListBuilder.java b/src/main/java/org/utplsql/api/db/DynamicParameterListBuilder.java
index 898da8e..793cfce 100644
--- a/src/main/java/org/utplsql/api/db/DynamicParameterListBuilder.java
+++ b/src/main/java/org/utplsql/api/db/DynamicParameterListBuilder.java
@@ -1,20 +1,33 @@
 package org.utplsql.api.db;
 
+import oracle.jdbc.OracleConnection;
+
 import java.util.LinkedHashMap;
-import java.util.function.Consumer;
 
 public class DynamicParameterListBuilder {
 
-    private LinkedHashMap<String, Consumer<Integer>> params = new LinkedHashMap<>();
+    private LinkedHashMap<String, DynamicParameterList.DynamicParameter> params = new LinkedHashMap<>();
+    private boolean addIfNullOrEmpty = true;
 
     private DynamicParameterListBuilder() {
 
     }
 
-    public DynamicParameterListBuilder addParameter(String identifier, Consumer<Integer> function) {
-
-        params.put(identifier, function);
+    public DynamicParameterListBuilder onlyAddIfNotEmpty() {
+        addIfNullOrEmpty = false;
+        return this;
+    }
 
+    public DynamicParameterListBuilder add( String identifier, String value ) {
+        params.put(identifier, new DynamicParameterList.DynamicStringParameter(value));
+        return this;
+    }
+    public DynamicParameterListBuilder add( String identifier, Integer value ) {
+        params.put(identifier, new DynamicParameterList.DynamicIntegerParameter(value));
+        return this;
+    }
+    public DynamicParameterListBuilder add(String identifier, Object[] value, String customTypeName, OracleConnection oraConnection ) {
+        params.put(identifier, new DynamicParameterList.DynamicArrayParameter(value, customTypeName, oraConnection));
         return this;
     }
 
diff --git a/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java b/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java
index daf0dd7..fbc1844 100644
--- a/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java
+++ b/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java
@@ -1,29 +1,37 @@
 package org.utplsql.api.db;
 
+import oracle.jdbc.OracleConnection;
 import org.junit.jupiter.api.Test;
 
-import java.util.ArrayList;
+import java.sql.CallableStatement;
+import java.sql.SQLException;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
 public class DynamicParameterListTest {
 
     @Test
-    void firstTest() {
+    void callWithThreeDifferentTypes() throws SQLException {
 
-        final ArrayList<Object> resultArray = new ArrayList<>();
+        CallableStatement mockedStatement = mock(CallableStatement.class);
+        OracleConnection mockedConn = mock(OracleConnection.class);
+
+        Object[] numArr = new Object[]{1, 2};
 
         DynamicParameterList parameterList = DynamicParameterListBuilder.create()
-                .addParameter("a_object_owner", i -> resultArray.add(i + ": MyOwner"))
-                .addParameter("a_num_param", i -> resultArray.add( i + ": 123"))
+                .add("a_object_owner", "MyOwner")
+                .add("a_num_param", 123)
+                .add("a_num_array", numArr, "MY_NUM_ARR", mockedConn)
                 .build();
 
-        parameterList.applyFromIndex(5);
-        assertEquals("a_object_owner = ?, a_num_param = ?", parameterList.getSql());
+        assertEquals("a_object_owner = ?, a_num_param = ?, a_num_array = ?", parameterList.getSql());
 
-        ArrayList<Object> expectedList = new ArrayList<>();
-        expectedList.add("5: MyOwner");
-        expectedList.add("6: 123");
-        assertEquals( expectedList, resultArray);
+        parameterList.setParamsStartWithIndex(mockedStatement, 5);
+        verify(mockedStatement).setString(5, "MyOwner");
+        verify(mockedStatement).setInt(6, 123);
+        verify(mockedConn).createOracleArray("MY_NUM_ARR", numArr);
+        verify(mockedStatement).setArray(7, null);
     }
 }

From c799e6aa1167e8a94a9db6a8047c13faa0c8e6b0 Mon Sep 17 00:00:00 2001
From: pesse <derpesse@gmail.com>
Date: Fri, 19 Jul 2019 00:00:16 +0200
Subject: [PATCH 06/12] Add functionality to ignore null or empty adds

---
 .../utplsql/api/db/DynamicParameterList.java  |  2 +-
 .../api/db/DynamicParameterListBuilder.java   | 12 ++++++---
 .../api/db/DynamicParameterListTest.java      | 27 ++++++++++++++++---
 3 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/src/main/java/org/utplsql/api/db/DynamicParameterList.java b/src/main/java/org/utplsql/api/db/DynamicParameterList.java
index c4a92be..0129181 100644
--- a/src/main/java/org/utplsql/api/db/DynamicParameterList.java
+++ b/src/main/java/org/utplsql/api/db/DynamicParameterList.java
@@ -10,7 +10,7 @@
 
 public class DynamicParameterList {
 
-    LinkedHashMap<String, DynamicParameter> params;
+    private LinkedHashMap<String, DynamicParameter> params;
 
     interface DynamicParameter {
         void setParam( CallableStatement statement, int index ) throws SQLException;
diff --git a/src/main/java/org/utplsql/api/db/DynamicParameterListBuilder.java b/src/main/java/org/utplsql/api/db/DynamicParameterListBuilder.java
index 793cfce..640c8fb 100644
--- a/src/main/java/org/utplsql/api/db/DynamicParameterListBuilder.java
+++ b/src/main/java/org/utplsql/api/db/DynamicParameterListBuilder.java
@@ -19,15 +19,21 @@ public DynamicParameterListBuilder onlyAddIfNotEmpty() {
     }
 
     public DynamicParameterListBuilder add( String identifier, String value ) {
-        params.put(identifier, new DynamicParameterList.DynamicStringParameter(value));
+        if ( addIfNullOrEmpty || (value != null && !value.isEmpty()) ) {
+            params.put(identifier, new DynamicParameterList.DynamicStringParameter(value));
+        }
         return this;
     }
     public DynamicParameterListBuilder add( String identifier, Integer value ) {
-        params.put(identifier, new DynamicParameterList.DynamicIntegerParameter(value));
+        if ( addIfNullOrEmpty || (value != null)) {
+            params.put(identifier, new DynamicParameterList.DynamicIntegerParameter(value));
+        }
         return this;
     }
     public DynamicParameterListBuilder add(String identifier, Object[] value, String customTypeName, OracleConnection oraConnection ) {
-        params.put(identifier, new DynamicParameterList.DynamicArrayParameter(value, customTypeName, oraConnection));
+        if ( addIfNullOrEmpty || (value != null && value.length > 0 )) {
+            params.put(identifier, new DynamicParameterList.DynamicArrayParameter(value, customTypeName, oraConnection));
+        }
         return this;
     }
 
diff --git a/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java b/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java
index fbc1844..4fbaa08 100644
--- a/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java
+++ b/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java
@@ -7,13 +7,12 @@
 import java.sql.SQLException;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.*;
 
 public class DynamicParameterListTest {
 
     @Test
-    void callWithThreeDifferentTypes() throws SQLException {
+    void call_with_three_different_types() throws SQLException {
 
         CallableStatement mockedStatement = mock(CallableStatement.class);
         OracleConnection mockedConn = mock(OracleConnection.class);
@@ -29,9 +28,31 @@ void callWithThreeDifferentTypes() throws SQLException {
         assertEquals("a_object_owner = ?, a_num_param = ?, a_num_array = ?", parameterList.getSql());
 
         parameterList.setParamsStartWithIndex(mockedStatement, 5);
+
         verify(mockedStatement).setString(5, "MyOwner");
         verify(mockedStatement).setInt(6, 123);
         verify(mockedConn).createOracleArray("MY_NUM_ARR", numArr);
         verify(mockedStatement).setArray(7, null);
     }
+
+    @Test
+    void when_not_accept_empty_filter_empty_elements() throws SQLException {
+
+        CallableStatement mockedStatement = mock(CallableStatement.class);
+        OracleConnection mockedConn = mock(OracleConnection.class);
+
+        DynamicParameterList parameterList = DynamicParameterListBuilder.create()
+                .onlyAddIfNotEmpty()
+                .add("a_object_owner", (String)null)
+                .add("a_num_param", (Integer)null)
+                .add("a_num_array", new Object[]{}, "MY_NUM_ARR", mockedConn)
+                .build();
+
+        assertEquals("", parameterList.getSql());
+
+        parameterList.setParamsStartWithIndex(mockedStatement, 2);
+
+        verifyNoMoreInteractions(mockedStatement);
+        verifyNoMoreInteractions(mockedConn);
+    }
 }

From c01e8c27d313f464147d6fba4fb296fe8e163335 Mon Sep 17 00:00:00 2001
From: pesse <derpesse@gmail.com>
Date: Fri, 19 Jul 2019 00:16:39 +0200
Subject: [PATCH 07/12] Fix PL/SQL bug - it's not = but =>

---
 src/main/java/org/utplsql/api/db/DynamicParameterList.java     | 2 +-
 src/test/java/org/utplsql/api/db/DynamicParameterListTest.java | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/main/java/org/utplsql/api/db/DynamicParameterList.java b/src/main/java/org/utplsql/api/db/DynamicParameterList.java
index 0129181..ba5e5fd 100644
--- a/src/main/java/org/utplsql/api/db/DynamicParameterList.java
+++ b/src/main/java/org/utplsql/api/db/DynamicParameterList.java
@@ -77,7 +77,7 @@ public void setParam(CallableStatement statement, int index) throws SQLException
 
     public String getSql() {
         return params.keySet().stream()
-                .map(e -> e + " = ?")
+                .map(e -> e + " => ?")
                 .collect(Collectors.joining(", "));
     }
 
diff --git a/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java b/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java
index 4fbaa08..cccdfe2 100644
--- a/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java
+++ b/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java
@@ -25,7 +25,7 @@ void call_with_three_different_types() throws SQLException {
                 .add("a_num_array", numArr, "MY_NUM_ARR", mockedConn)
                 .build();
 
-        assertEquals("a_object_owner = ?, a_num_param = ?, a_num_array = ?", parameterList.getSql());
+        assertEquals("a_object_owner => ?, a_num_param => ?, a_num_array => ?", parameterList.getSql());
 
         parameterList.setParamsStartWithIndex(mockedStatement, 5);
 

From 9cd9937e73d716cc8479a713a66e804c5cc4df57 Mon Sep 17 00:00:00 2001
From: pesse <derpesse@gmail.com>
Date: Fri, 19 Jul 2019 00:17:00 +0200
Subject: [PATCH 08/12] Now let's use that sweet new
 DynamicParameterListBuilder

---
 .../utplsql/api/testRunner/FileMapper.java    | 80 ++++++-------------
 1 file changed, 26 insertions(+), 54 deletions(-)

diff --git a/src/main/java/org/utplsql/api/testRunner/FileMapper.java b/src/main/java/org/utplsql/api/testRunner/FileMapper.java
index 1d7a48e..80feb56 100644
--- a/src/main/java/org/utplsql/api/testRunner/FileMapper.java
+++ b/src/main/java/org/utplsql/api/testRunner/FileMapper.java
@@ -9,11 +9,11 @@
 import org.utplsql.api.FileMapperOptions;
 import org.utplsql.api.FileMapping;
 import org.utplsql.api.KeyValuePair;
+import org.utplsql.api.db.DynamicParameterList;
+import org.utplsql.api.db.DynamicParameterListBuilder;
 
 import java.sql.*;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 final class FileMapper {
 
@@ -34,66 +34,38 @@ private static Array buildFileMappingArray(
         typeMap.put(CustomTypes.UT_KEY_VALUE_PAIR, KeyValuePair.class);
         conn.setTypeMap(typeMap);
 
-        CallableStatement callableStatement = conn.prepareCall(
-                "BEGIN " +
-                        "? := ut_file_mapper.build_file_mappings(" +
-                        "a_object_owner                => ?, " +
-                        "a_file_paths                  => ?, " +
-                        "a_file_to_object_type_mapping => ?, " +
-                        "a_regex_pattern               => ?, " +
-                        "a_object_owner_subexpression  => ?, " +
-                        "a_object_name_subexpression   => ?, " +
-                        "a_object_type_subexpression   => ?); " +
-                        "END;");
-
-        int paramIdx = 0;
-        callableStatement.registerOutParameter(++paramIdx, OracleTypes.ARRAY, CustomTypes.UT_FILE_MAPPINGS);
-
-        if (mapperOptions.getObjectOwner() == null) {
-            callableStatement.setNull(++paramIdx, Types.VARCHAR);
-        } else {
-            callableStatement.setString(++paramIdx, mapperOptions.getObjectOwner());
-        }
-
         logger.debug("Building fileMappingArray");
-        Object[] filePathsArray = mapperOptions.getFilePaths().toArray();
+        final Object[] filePathsArray = mapperOptions.getFilePaths().toArray();
         for ( Object elem : filePathsArray ) {
             logger.debug("Path: " + elem);
         }
-
-        callableStatement.setArray(
-                ++paramIdx, oraConn.createOracleArray(CustomTypes.UT_VARCHAR2_LIST, filePathsArray));
-
-        if (mapperOptions.getTypeMappings() == null || mapperOptions.getTypeMappings().size() == 0) {
-            callableStatement.setNull(++paramIdx, Types.ARRAY, CustomTypes.UT_KEY_VALUE_PAIRS);
-        } else {
-            callableStatement.setArray(
-                    ++paramIdx, oraConn.createOracleArray(CustomTypes.UT_KEY_VALUE_PAIRS, mapperOptions.getTypeMappings().toArray()));
+        Object[] typeMapArray = null;
+        if ( mapperOptions.getTypeMappings() != null ) {
+            typeMapArray = mapperOptions.getTypeMappings().toArray();
         }
 
-        if (mapperOptions.getRegexPattern() == null) {
-            callableStatement.setNull(++paramIdx, Types.VARCHAR);
-        } else {
-            callableStatement.setString(++paramIdx, mapperOptions.getRegexPattern());
-        }
+        DynamicParameterList parameterList =  DynamicParameterListBuilder.create()
+                .add("a_file_paths", filePathsArray, CustomTypes.UT_VARCHAR2_LIST, oraConn)
+                .onlyAddIfNotEmpty()
+                .add("a_object_owner", mapperOptions.getObjectOwner())
+                .add("a_file_to_object_type_mapping", typeMapArray, CustomTypes.UT_KEY_VALUE_PAIRS, oraConn)
+                .add("a_regex_pattern", mapperOptions.getRegexPattern())
+                .add("a_object_owner_subexpression", mapperOptions.getOwnerSubExpression())
+                .add("a_object_name_subexpression", mapperOptions.getNameSubExpression())
+                .add("a_object_type_subexpression", mapperOptions.getTypeSubExpression())
+                .build();
 
-        if (mapperOptions.getOwnerSubExpression() == null) {
-            callableStatement.setNull(++paramIdx, Types.INTEGER);
-        } else {
-            callableStatement.setInt(++paramIdx, mapperOptions.getOwnerSubExpression());
-        }
+        CallableStatement callableStatement = conn.prepareCall(
+                "BEGIN " +
+                        "? := ut_file_mapper.build_file_mappings(" +
+                        parameterList.getSql() +
+                        "); " +
+                        "END;");
 
-        if (mapperOptions.getNameSubExpression() == null) {
-            callableStatement.setNull(++paramIdx, Types.INTEGER);
-        } else {
-            callableStatement.setInt(++paramIdx, mapperOptions.getNameSubExpression());
-        }
+        int paramIdx = 0;
+        callableStatement.registerOutParameter(++paramIdx, OracleTypes.ARRAY, CustomTypes.UT_FILE_MAPPINGS);
 
-        if (mapperOptions.getTypeSubExpression() == null) {
-            callableStatement.setNull(++paramIdx, Types.INTEGER);
-        } else {
-            callableStatement.setInt(++paramIdx, mapperOptions.getTypeSubExpression());
-        }
+        parameterList.setParamsStartWithIndex(callableStatement, ++paramIdx);
 
         callableStatement.execute();
         return callableStatement.getArray(1);

From db3e1fb97612f84b5d37ccabad1720d88feb9901 Mon Sep 17 00:00:00 2001
From: pesse <derpesse@gmail.com>
Date: Fri, 19 Jul 2019 08:31:44 +0200
Subject: [PATCH 09/12] Inlining DynamicParameterListBuilder

---
 .../utplsql/api/db/DynamicParameterList.java  | 42 ++++++++++++++++
 .../api/db/DynamicParameterListBuilder.java   | 48 -------------------
 .../utplsql/api/testRunner/FileMapper.java    |  3 +-
 .../api/db/DynamicParameterListTest.java      |  4 +-
 4 files changed, 45 insertions(+), 52 deletions(-)
 delete mode 100644 src/main/java/org/utplsql/api/db/DynamicParameterListBuilder.java

diff --git a/src/main/java/org/utplsql/api/db/DynamicParameterList.java b/src/main/java/org/utplsql/api/db/DynamicParameterList.java
index ba5e5fd..6e3765e 100644
--- a/src/main/java/org/utplsql/api/db/DynamicParameterList.java
+++ b/src/main/java/org/utplsql/api/db/DynamicParameterList.java
@@ -88,4 +88,46 @@ public void setParamsStartWithIndex(CallableStatement statement, int startIndex
         }
     }
 
+    public static DynamicParameterListBuilder builder() {
+        return new DynamicParameterListBuilder();
+    }
+
+    public static class DynamicParameterListBuilder {
+
+        private LinkedHashMap<String, DynamicParameterList.DynamicParameter> params = new LinkedHashMap<>();
+        private boolean addIfNullOrEmpty = true;
+
+        private DynamicParameterListBuilder() {
+
+        }
+
+        public DynamicParameterListBuilder onlyAddIfNotEmpty() {
+            addIfNullOrEmpty = false;
+            return this;
+        }
+
+        public DynamicParameterListBuilder add(String identifier, String value ) {
+            if ( addIfNullOrEmpty || (value != null && !value.isEmpty()) ) {
+                params.put(identifier, new DynamicParameterList.DynamicStringParameter(value));
+            }
+            return this;
+        }
+        public DynamicParameterListBuilder add(String identifier, Integer value ) {
+            if ( addIfNullOrEmpty || (value != null)) {
+                params.put(identifier, new DynamicParameterList.DynamicIntegerParameter(value));
+            }
+            return this;
+        }
+        public DynamicParameterListBuilder add(String identifier, Object[] value, String customTypeName, OracleConnection oraConnection ) {
+            if ( addIfNullOrEmpty || (value != null && value.length > 0 )) {
+                params.put(identifier, new DynamicParameterList.DynamicArrayParameter(value, customTypeName, oraConnection));
+            }
+            return this;
+        }
+
+        public DynamicParameterList build() {
+            return new DynamicParameterList(params);
+        }
+    }
+
 }
diff --git a/src/main/java/org/utplsql/api/db/DynamicParameterListBuilder.java b/src/main/java/org/utplsql/api/db/DynamicParameterListBuilder.java
deleted file mode 100644
index 640c8fb..0000000
--- a/src/main/java/org/utplsql/api/db/DynamicParameterListBuilder.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package org.utplsql.api.db;
-
-import oracle.jdbc.OracleConnection;
-
-import java.util.LinkedHashMap;
-
-public class DynamicParameterListBuilder {
-
-    private LinkedHashMap<String, DynamicParameterList.DynamicParameter> params = new LinkedHashMap<>();
-    private boolean addIfNullOrEmpty = true;
-
-    private DynamicParameterListBuilder() {
-
-    }
-
-    public DynamicParameterListBuilder onlyAddIfNotEmpty() {
-        addIfNullOrEmpty = false;
-        return this;
-    }
-
-    public DynamicParameterListBuilder add( String identifier, String value ) {
-        if ( addIfNullOrEmpty || (value != null && !value.isEmpty()) ) {
-            params.put(identifier, new DynamicParameterList.DynamicStringParameter(value));
-        }
-        return this;
-    }
-    public DynamicParameterListBuilder add( String identifier, Integer value ) {
-        if ( addIfNullOrEmpty || (value != null)) {
-            params.put(identifier, new DynamicParameterList.DynamicIntegerParameter(value));
-        }
-        return this;
-    }
-    public DynamicParameterListBuilder add(String identifier, Object[] value, String customTypeName, OracleConnection oraConnection ) {
-        if ( addIfNullOrEmpty || (value != null && value.length > 0 )) {
-            params.put(identifier, new DynamicParameterList.DynamicArrayParameter(value, customTypeName, oraConnection));
-        }
-        return this;
-    }
-
-    public DynamicParameterList build() {
-        return new DynamicParameterList(params);
-    }
-
-
-    public static DynamicParameterListBuilder create() {
-        return new DynamicParameterListBuilder();
-    }
-}
diff --git a/src/main/java/org/utplsql/api/testRunner/FileMapper.java b/src/main/java/org/utplsql/api/testRunner/FileMapper.java
index 80feb56..05705b2 100644
--- a/src/main/java/org/utplsql/api/testRunner/FileMapper.java
+++ b/src/main/java/org/utplsql/api/testRunner/FileMapper.java
@@ -10,7 +10,6 @@
 import org.utplsql.api.FileMapping;
 import org.utplsql.api.KeyValuePair;
 import org.utplsql.api.db.DynamicParameterList;
-import org.utplsql.api.db.DynamicParameterListBuilder;
 
 import java.sql.*;
 import java.util.*;
@@ -44,7 +43,7 @@ private static Array buildFileMappingArray(
             typeMapArray = mapperOptions.getTypeMappings().toArray();
         }
 
-        DynamicParameterList parameterList =  DynamicParameterListBuilder.create()
+        DynamicParameterList parameterList =  DynamicParameterList.builder()
                 .add("a_file_paths", filePathsArray, CustomTypes.UT_VARCHAR2_LIST, oraConn)
                 .onlyAddIfNotEmpty()
                 .add("a_object_owner", mapperOptions.getObjectOwner())
diff --git a/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java b/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java
index cccdfe2..1b966a5 100644
--- a/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java
+++ b/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java
@@ -19,7 +19,7 @@ void call_with_three_different_types() throws SQLException {
 
         Object[] numArr = new Object[]{1, 2};
 
-        DynamicParameterList parameterList = DynamicParameterListBuilder.create()
+        DynamicParameterList parameterList = DynamicParameterList.builder()
                 .add("a_object_owner", "MyOwner")
                 .add("a_num_param", 123)
                 .add("a_num_array", numArr, "MY_NUM_ARR", mockedConn)
@@ -41,7 +41,7 @@ void when_not_accept_empty_filter_empty_elements() throws SQLException {
         CallableStatement mockedStatement = mock(CallableStatement.class);
         OracleConnection mockedConn = mock(OracleConnection.class);
 
-        DynamicParameterList parameterList = DynamicParameterListBuilder.create()
+        DynamicParameterList parameterList = DynamicParameterList.builder()
                 .onlyAddIfNotEmpty()
                 .add("a_object_owner", (String)null)
                 .add("a_num_param", (Integer)null)

From e0291ab3fb2c37009397ee67a687f11979966e71 Mon Sep 17 00:00:00 2001
From: pesse <derpesse@gmail.com>
Date: Fri, 19 Jul 2019 08:51:28 +0200
Subject: [PATCH 10/12] Reducing visibilty of some classes and methods, adding
 comments

---
 .../utplsql/api/db/DynamicParameterList.java  | 149 +++++++++++-------
 1 file changed, 93 insertions(+), 56 deletions(-)

diff --git a/src/main/java/org/utplsql/api/db/DynamicParameterList.java b/src/main/java/org/utplsql/api/db/DynamicParameterList.java
index 6e3765e..1982b1f 100644
--- a/src/main/java/org/utplsql/api/db/DynamicParameterList.java
+++ b/src/main/java/org/utplsql/api/db/DynamicParameterList.java
@@ -8,6 +8,12 @@
 import java.util.LinkedHashMap;
 import java.util.stream.Collectors;
 
+/** Lets you build a list of parameters for a CallableStatement
+ * <br>
+ * Create it with the Builder (DynamicParameterList.builder())
+ *
+ * @author pesse
+ */
 public class DynamicParameterList {
 
     private LinkedHashMap<String, DynamicParameter> params;
@@ -16,71 +22,28 @@ interface DynamicParameter {
         void setParam( CallableStatement statement, int index ) throws SQLException;
     }
 
-    static class DynamicStringParameter implements DynamicParameter {
-        private final String value;
-
-        DynamicStringParameter( String value ) {
-            this.value = value;
-        }
-
-        @Override
-        public void setParam(CallableStatement statement, int index) throws SQLException {
-            if ( value == null ) {
-                statement.setNull(index, Types.VARCHAR);
-            } else {
-                statement.setString(index, value);
-            }
-        }
-    }
-    static class DynamicIntegerParameter implements DynamicParameter {
-        private final Integer value;
-
-        DynamicIntegerParameter( Integer value ) {
-            this.value = value;
-        }
-
-        @Override
-        public void setParam(CallableStatement statement, int index) throws SQLException {
-            if ( value == null ) {
-                statement.setNull(index, Types.INTEGER);
-            } else {
-                statement.setInt(index, value);
-            }
-        }
-    }
-    static class DynamicArrayParameter implements DynamicParameter {
-        private final Object[] value;
-        private final String customTypeName;
-        private final OracleConnection oraConnection;
-
-        DynamicArrayParameter( Object[] value, String customTypeName, OracleConnection oraConnection ) {
-            this.value = value;
-            this.customTypeName = customTypeName;
-            this.oraConnection = oraConnection;
-        }
-
-        @Override
-        public void setParam(CallableStatement statement, int index) throws SQLException {
-            if ( value == null ) {
-                statement.setNull(index, Types.ARRAY, customTypeName);
-            } else {
-                statement.setArray(
-                        index, oraConnection.createOracleArray(customTypeName, value)
-                );
-            }
-        }
-    }
-
-    DynamicParameterList(LinkedHashMap<String, DynamicParameter> params) {
+    private DynamicParameterList(LinkedHashMap<String, DynamicParameter> params) {
         this.params = params;
     }
 
+    /** Returns the SQL of this ParameterList as comma-separated list of the parameter identifiers:<br>
+     *
+     * e.g. "a_parameter1 => ?, a_parameter2 => ?"
+     *
+     * @return comma-separated list of parameter identifiers
+     */
     public String getSql() {
         return params.keySet().stream()
                 .map(e -> e + " => ?")
                 .collect(Collectors.joining(", "));
     }
 
+    /** Sets the contained parameters in the order they were added to the given statement by index, starting with the given one
+     *
+     * @param statement The statement to set the parameters to
+     * @param startIndex The index to start with
+     * @throws SQLException SQLException of the underlying statement.setX methods
+     */
     public void setParamsStartWithIndex(CallableStatement statement, int startIndex ) throws SQLException {
         int index = startIndex;
         for ( DynamicParameter param : params.values() ) {
@@ -88,10 +51,26 @@ public void setParamsStartWithIndex(CallableStatement statement, int startIndex
         }
     }
 
+    /** Returns a builder to create a DynamicParameterList
+     *
+     * @return Builder
+     */
     public static DynamicParameterListBuilder builder() {
         return new DynamicParameterListBuilder();
     }
 
+    /** Builder-class for DynamicParameterList
+     * <br>
+     * Usage:
+     * <pre>
+     *  DynamicParameterList.builder()
+     *      .add("parameter1", "StringParameter")
+     *      .add("parameter2", 123)
+     *      .build();
+     * </pre>
+     *
+     * @author pesse
+     */
     public static class DynamicParameterListBuilder {
 
         private LinkedHashMap<String, DynamicParameterList.DynamicParameter> params = new LinkedHashMap<>();
@@ -130,4 +109,62 @@ public DynamicParameterList build() {
         }
     }
 
+    /* Implementations of DynamicStringParameter */
+    private static class DynamicStringParameter implements DynamicParameter {
+        private final String value;
+
+        DynamicStringParameter( String value ) {
+            this.value = value;
+        }
+
+        @Override
+        public void setParam(CallableStatement statement, int index) throws SQLException {
+            if ( value == null ) {
+                statement.setNull(index, Types.VARCHAR);
+            } else {
+                statement.setString(index, value);
+            }
+        }
+    }
+
+    private static class DynamicIntegerParameter implements DynamicParameter {
+        private final Integer value;
+
+        DynamicIntegerParameter( Integer value ) {
+            this.value = value;
+        }
+
+        @Override
+        public void setParam(CallableStatement statement, int index) throws SQLException {
+            if ( value == null ) {
+                statement.setNull(index, Types.INTEGER);
+            } else {
+                statement.setInt(index, value);
+            }
+        }
+    }
+
+    private static class DynamicArrayParameter implements DynamicParameter {
+        private final Object[] value;
+        private final String customTypeName;
+        private final OracleConnection oraConnection;
+
+        DynamicArrayParameter( Object[] value, String customTypeName, OracleConnection oraConnection ) {
+            this.value = value;
+            this.customTypeName = customTypeName;
+            this.oraConnection = oraConnection;
+        }
+
+        @Override
+        public void setParam(CallableStatement statement, int index) throws SQLException {
+            if ( value == null ) {
+                statement.setNull(index, Types.ARRAY, customTypeName);
+            } else {
+                statement.setArray(
+                        index, oraConnection.createOracleArray(customTypeName, value)
+                );
+            }
+        }
+    }
+
 }

From d2292cfd5bf8283428f5467573c85aec4e57eb87 Mon Sep 17 00:00:00 2001
From: pesse <derpesse@gmail.com>
Date: Fri, 19 Jul 2019 08:57:09 +0200
Subject: [PATCH 11/12] Add addIfNotEmpty method, remove allowEmpty-flag

---
 .../utplsql/api/db/DynamicParameterList.java  | 33 ++++++++++++-------
 .../utplsql/api/testRunner/FileMapper.java    | 13 ++++----
 .../api/db/DynamicParameterListTest.java      |  7 ++--
 3 files changed, 31 insertions(+), 22 deletions(-)

diff --git a/src/main/java/org/utplsql/api/db/DynamicParameterList.java b/src/main/java/org/utplsql/api/db/DynamicParameterList.java
index 1982b1f..68f88a1 100644
--- a/src/main/java/org/utplsql/api/db/DynamicParameterList.java
+++ b/src/main/java/org/utplsql/api/db/DynamicParameterList.java
@@ -65,7 +65,7 @@ public static DynamicParameterListBuilder builder() {
      * <pre>
      *  DynamicParameterList.builder()
      *      .add("parameter1", "StringParameter")
-     *      .add("parameter2", 123)
+     *      .addIfNotEmpty("parameter2", 123)
      *      .build();
      * </pre>
      *
@@ -74,32 +74,43 @@ public static DynamicParameterListBuilder builder() {
     public static class DynamicParameterListBuilder {
 
         private LinkedHashMap<String, DynamicParameterList.DynamicParameter> params = new LinkedHashMap<>();
-        private boolean addIfNullOrEmpty = true;
 
         private DynamicParameterListBuilder() {
 
         }
 
-        public DynamicParameterListBuilder onlyAddIfNotEmpty() {
-            addIfNullOrEmpty = false;
+        public DynamicParameterListBuilder add(String identifier, String value ) {
+            params.put(identifier, new DynamicParameterList.DynamicStringParameter(value));
             return this;
         }
 
-        public DynamicParameterListBuilder add(String identifier, String value ) {
-            if ( addIfNullOrEmpty || (value != null && !value.isEmpty()) ) {
-                params.put(identifier, new DynamicParameterList.DynamicStringParameter(value));
+        public DynamicParameterListBuilder addIfNotEmpty(String identifier, String value ) {
+            if ( value != null && !value.isEmpty() ) {
+                add(identifier, value);
             }
             return this;
         }
+
         public DynamicParameterListBuilder add(String identifier, Integer value ) {
-            if ( addIfNullOrEmpty || (value != null)) {
-                params.put(identifier, new DynamicParameterList.DynamicIntegerParameter(value));
+            params.put(identifier, new DynamicParameterList.DynamicIntegerParameter(value));
+            return this;
+        }
+
+        public DynamicParameterListBuilder addIfNotEmpty(String identifier, Integer value ) {
+            if ( value != null) {
+                add(identifier, value);
             }
             return this;
         }
+
         public DynamicParameterListBuilder add(String identifier, Object[] value, String customTypeName, OracleConnection oraConnection ) {
-            if ( addIfNullOrEmpty || (value != null && value.length > 0 )) {
-                params.put(identifier, new DynamicParameterList.DynamicArrayParameter(value, customTypeName, oraConnection));
+            params.put(identifier, new DynamicParameterList.DynamicArrayParameter(value, customTypeName, oraConnection));
+            return this;
+        }
+
+        public DynamicParameterListBuilder addIfNotEmpty(String identifier, Object[] value, String customTypeName, OracleConnection oraConnection ) {
+            if ( value != null && value.length > 0 ) {
+                add(identifier, value, customTypeName, oraConnection);
             }
             return this;
         }
diff --git a/src/main/java/org/utplsql/api/testRunner/FileMapper.java b/src/main/java/org/utplsql/api/testRunner/FileMapper.java
index 05705b2..b599a5a 100644
--- a/src/main/java/org/utplsql/api/testRunner/FileMapper.java
+++ b/src/main/java/org/utplsql/api/testRunner/FileMapper.java
@@ -45,13 +45,12 @@ private static Array buildFileMappingArray(
 
         DynamicParameterList parameterList =  DynamicParameterList.builder()
                 .add("a_file_paths", filePathsArray, CustomTypes.UT_VARCHAR2_LIST, oraConn)
-                .onlyAddIfNotEmpty()
-                .add("a_object_owner", mapperOptions.getObjectOwner())
-                .add("a_file_to_object_type_mapping", typeMapArray, CustomTypes.UT_KEY_VALUE_PAIRS, oraConn)
-                .add("a_regex_pattern", mapperOptions.getRegexPattern())
-                .add("a_object_owner_subexpression", mapperOptions.getOwnerSubExpression())
-                .add("a_object_name_subexpression", mapperOptions.getNameSubExpression())
-                .add("a_object_type_subexpression", mapperOptions.getTypeSubExpression())
+                .addIfNotEmpty("a_object_owner", mapperOptions.getObjectOwner())
+                .addIfNotEmpty("a_file_to_object_type_mapping", typeMapArray, CustomTypes.UT_KEY_VALUE_PAIRS, oraConn)
+                .addIfNotEmpty("a_regex_pattern", mapperOptions.getRegexPattern())
+                .addIfNotEmpty("a_object_owner_subexpression", mapperOptions.getOwnerSubExpression())
+                .addIfNotEmpty("a_object_name_subexpression", mapperOptions.getNameSubExpression())
+                .addIfNotEmpty("a_object_type_subexpression", mapperOptions.getTypeSubExpression())
                 .build();
 
         CallableStatement callableStatement = conn.prepareCall(
diff --git a/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java b/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java
index 1b966a5..e2bd6b2 100644
--- a/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java
+++ b/src/test/java/org/utplsql/api/db/DynamicParameterListTest.java
@@ -42,10 +42,9 @@ void when_not_accept_empty_filter_empty_elements() throws SQLException {
         OracleConnection mockedConn = mock(OracleConnection.class);
 
         DynamicParameterList parameterList = DynamicParameterList.builder()
-                .onlyAddIfNotEmpty()
-                .add("a_object_owner", (String)null)
-                .add("a_num_param", (Integer)null)
-                .add("a_num_array", new Object[]{}, "MY_NUM_ARR", mockedConn)
+                .addIfNotEmpty("a_object_owner", (String)null)
+                .addIfNotEmpty("a_num_param", (Integer)null)
+                .addIfNotEmpty("a_num_array", new Object[]{}, "MY_NUM_ARR", mockedConn)
                 .build();
 
         assertEquals("", parameterList.getSql());

From 1bd0f48065c96f6effe88fd73917a37f56b47e4a Mon Sep 17 00:00:00 2001
From: pesse <derpesse@gmail.com>
Date: Fri, 19 Jul 2019 08:59:30 +0200
Subject: [PATCH 12/12] Use newer mockito framework and have it as
 testImplementation

---
 build.gradle.kts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build.gradle.kts b/build.gradle.kts
index a997de9..0bc2c52 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -57,7 +57,7 @@ dependencies {
     testImplementation("org.hamcrest:hamcrest:2.1")
 
     // Mockito
-    testCompile("org.mockito:mockito-core:2.+")
+    testImplementation("org.mockito:mockito-core:3.0.0")
 
     // deployer for packagecloud
     deployerJars("io.packagecloud.maven.wagon:maven-packagecloud-wagon:0.0.6")