diff --git a/.gitattributes b/.gitattributes
index 4bf4c97b7..622538467 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,2 +1,4 @@
 *.txt text
 
+# Override default behavior: BAT files always have CRLF line endings.
+*.bat text eol=crlf
diff --git a/README.md b/README.md
index c56876b53..bf8fb180e 100644
--- a/README.md
+++ b/README.md
@@ -98,13 +98,11 @@ Update the version of the SDK before creating a new release. The format is `<maj
 `<major>.<minor>` numbers must match the version of BP. The `<patch>` is an incrementing number that increments with 
 each SDK release for a given major/minor release.
 
-The build number is specified in the `build.gradle` file:
+The build number is specified in the `buildSrc/src/main/kotlin/ds3-java-sdk-library-convention.gradle.kts` file:
 
 ```
-allprojects {
-    group = 'com.spectralogic.ds3'
-    version = '5.4.0'
-}
+group = "com.spectralogic.ds3"
+version = "5.4.1"
 ```
 
 When a release is created in github, it is automatically published on [jitpack.io](https://jitpack.io/#SpectraLogic/ds3_java_sdk).
diff --git a/SETUP.md b/SETUP.md
index ae0f77fde..412b0690f 100644
--- a/SETUP.md
+++ b/SETUP.md
@@ -15,5 +15,5 @@ If using Eclipse:
 
 If using Intellij:
 * Open Intellij and select `Import Project`
-* Find the `build.gradle` file contained at the root of the project and select it
+* Find the `settings.gradle.kts` file contained at the root of the project and select it
 * Accept the defaults
diff --git a/build.gradle b/build.gradle
deleted file mode 100644
index f3015d04b..000000000
--- a/build.gradle
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * ******************************************************************************
- *   Copyright 2014-2019 Spectra Logic Corporation. All Rights Reserved.
- *   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
- *   this file except in compliance with the License. A copy of the License is located at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- *   or in the "license" file accompanying this file.
- *   This file 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.
- * ****************************************************************************
- */
-
-buildscript {
-    ext.kotlin_version = '1.2.70'
-
-    repositories {
-        mavenCentral()
-        jcenter()
-    }
-
-    dependencies {
-        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
-        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
-        classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.2'
-        classpath 'com.github.ben-manes:gradle-versions-plugin:0.21.0'
-    }
-}
-
-
-plugins {
-    id "com.palantir.git-version" version "0.10.1"
-}
-
-allprojects {
-    group = 'com.spectralogic.ds3'
-    version = '5.4.1'
-}
-
-subprojects {
-    apply plugin: 'com.github.ben-manes.versions'
-    apply plugin: 'maven'
-    apply plugin: 'java'
-    apply plugin: 'kotlin'
-    apply plugin: 'findbugs'
-
-    sourceCompatibility = JavaVersion.VERSION_1_8
-    repositories {
-        mavenCentral()
-        mavenLocal()
-    }
-
-    dependencies {
-        compile "org.slf4j:slf4j-api:$slf4jVersion"
-        testCompile ("org.mockito:mockito-core:$mockitoVersion") {
-            exclude group: 'org.hamcrest'
-        }
-
-        testCompile "junit:junit:$junitVersion"
-        testCompile "org.slf4j:slf4j-simple:$slf4jVersion"
-    }
-}
-
-task wrapper(type: Wrapper) {
-    gradleVersion = '4.7'
-}
-
-project(':ds3-sdk') {
-    dependencies {
-        compile project(':ds3-interfaces')
-        compile project(':ds3-utils')
-    }
-}
-
-project(':ds3-metadata') {
-    dependencies {
-        compile project(':ds3-interfaces')
-        compile project(':ds3-utils')
-    }
-}
-
-project(':ds3-sdk-integration') {
-    dependencies {
-        compile project(':ds3-sdk')
-        compile project(':ds3-metadata')
-    }
-}
-
-project(':ds3-sdk-samples') {
-    dependencies {
-        compile project(':ds3-sdk')
-    }
-}
-
-project(':ds3-utils') {
-    dependencies {
-        compile project(':ds3-interfaces')
-    }
-}
diff --git a/settings.gradle b/buildSrc/build.gradle.kts
similarity index 76%
rename from settings.gradle
rename to buildSrc/build.gradle.kts
index 3216a5378..36d73dd5f 100644
--- a/settings.gradle
+++ b/buildSrc/build.gradle.kts
@@ -1,6 +1,6 @@
 /*
  * ******************************************************************************
- *   Copyright 2014-2019 Spectra Logic Corporation. All Rights Reserved.
+ *   Copyright 2002 Spectra Logic Corporation. All Rights Reserved.
  *   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
  *   this file except in compliance with the License. A copy of the License is located at
  *
@@ -13,5 +13,10 @@
  * ****************************************************************************
  */
 
-include 'ds3-sdk-integration', 'ds3-sdk', 'ds3-sdk-samples', 'ds3-interfaces', 'ds3-metadata', 'ds3-utils'
-rootProject.name = 'ds3-java-sdk'
+plugins {
+    `kotlin-dsl`
+}
+
+repositories {
+    mavenCentral()
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/ds3-java-sdk-internal-convention.gradle.kts b/buildSrc/src/main/kotlin/ds3-java-sdk-internal-convention.gradle.kts
new file mode 100644
index 000000000..0162406b3
--- /dev/null
+++ b/buildSrc/src/main/kotlin/ds3-java-sdk-internal-convention.gradle.kts
@@ -0,0 +1,24 @@
+/*
+ * ******************************************************************************
+ *   Copyright 2002 Spectra Logic Corporation. All Rights Reserved.
+ *   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
+ *   this file except in compliance with the License. A copy of the License is located at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   or in the "license" file accompanying this file.
+ *   This file 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.
+ * ****************************************************************************
+ */
+
+plugins {
+    `java`
+}
+
+java {
+    toolchain {
+        languageVersion.set(JavaLanguageVersion.of(8))
+    }
+}
diff --git a/ds3-sdk-samples/build.gradle b/buildSrc/src/main/kotlin/ds3-java-sdk-library-convention.gradle.kts
similarity index 73%
rename from ds3-sdk-samples/build.gradle
rename to buildSrc/src/main/kotlin/ds3-java-sdk-library-convention.gradle.kts
index 5fdd170c8..8470746c5 100644
--- a/ds3-sdk-samples/build.gradle
+++ b/buildSrc/src/main/kotlin/ds3-java-sdk-library-convention.gradle.kts
@@ -1,6 +1,6 @@
 /*
  * ******************************************************************************
- *   Copyright 2014-2019 Spectra Logic Corporation. All Rights Reserved.
+ *   Copyright 2002 Spectra Logic Corporation. All Rights Reserved.
  *   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
  *   this file except in compliance with the License. A copy of the License is located at
  *
@@ -13,10 +13,15 @@
  * ****************************************************************************
  */
 
-apply plugin: 'application'
+plugins {
+    `java-library`
+}
 
-mainClassName = 'com.spectralogic.ds3client.samples.PartialObjectGetExample'
+group = "com.spectralogic.ds3"
+version = "5.4.1"
 
-dependencies {
-    compile "org.slf4j:slf4j-simple:$slf4jVersion"
+java {
+    toolchain {
+        languageVersion.set(JavaLanguageVersion.of(8))
+    }
 }
diff --git a/ds3-interfaces/build.gradle b/ds3-interfaces/build.gradle.kts
similarity index 84%
rename from ds3-interfaces/build.gradle
rename to ds3-interfaces/build.gradle.kts
index f5f6aa52d..94ddde559 100644
--- a/ds3-interfaces/build.gradle
+++ b/ds3-interfaces/build.gradle.kts
@@ -1,6 +1,6 @@
 /*
  * ******************************************************************************
- *   Copyright 2014-2019 Spectra Logic Corporation. All Rights Reserved.
+ *   Copyright 2002 Spectra Logic Corporation. All Rights Reserved.
  *   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
  *   this file except in compliance with the License. A copy of the License is located at
  *
@@ -13,4 +13,6 @@
  * ****************************************************************************
  */
 
-apply from: "$rootDir/gradle/scripts/publish.gradle"
+plugins {
+    `ds3-java-sdk-library-convention`
+}
diff --git a/ds3-metadata/build.gradle b/ds3-metadata/build.gradle
deleted file mode 100644
index c0ee177a1..000000000
--- a/ds3-metadata/build.gradle
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * ******************************************************************************
- *   Copyright 2014-2019 Spectra Logic Corporation. All Rights Reserved.
- *   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
- *   this file except in compliance with the License. A copy of the License is located at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- *   or in the "license" file accompanying this file.
- *   This file 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.
- * ****************************************************************************
- */
-
-apply plugin: 'com.github.johnrengelman.shadow'
-
-apply from: "$rootDir/gradle/scripts/publish.gradle"
-
-shadowJar {
-    relocate 'org.apache', 'ds3metafatjar.org.apache'
-    relocate 'com.google', 'ds3metafatjar.com.google'
-    relocate 'com.sun.jna', 'ds3metafatjar.net.java.dev.jna'
-    relocate 'org.jetbrains', 'ds3metafatjar.org.jetbrains'
-    relocate 'org.intellij', 'ds3metafatjar.org.intellij'
-    relocate 'org.codehaus', 'ds3metafatjar.org.codehaus'
-
-    dependencies {
-        exclude(project(":ds3-interfaces")) // this is being excluded since it must be used with the sdk, which already has this dependency included
-        exclude(project(":ds3-utils")) // this is being excluded since it must be used with the sdk, which already has this dependency included
-        exclude(dependency("org.hamcrest:hamcrest-library:$hamcrestVersion"))
-        exclude(dependency("org.mockito:mockito-core:$mockitoVersion"))
-        exclude(dependency("junit:junit:$junitVersion"))
-        exclude(dependency("org.slf4j:slf4j-api:$slf4jVersion"))
-        exclude(dependency("org.slf4j:slf4j-simple:$slf4jVersion"))
-        exclude(dependency("org.apache.commons:commons-lang3:$commonslangVersion"))
-    }
-}
-
-artifacts {
-    archives shadowJar
-}
-
-dependencies {
-    compile     group: 'net.java.dev.jna', name: 'jna-platform', version: "$jnaVersion"
-    compile     group: 'net.java.dev.jna', name: 'jna', version: "$jnaVersion"
-    compile     "commons-io:commons-io:$commonsioVersion"
-    compile     "org.apache.httpcomponents:httpclient:$httpclientVersion"
-
-    testCompile group: 'org.apache.commons', name: 'commons-lang3', version: "$commonslangVersion"
-}
diff --git a/ds3-metadata/build.gradle.kts b/ds3-metadata/build.gradle.kts
new file mode 100644
index 000000000..ab1152793
--- /dev/null
+++ b/ds3-metadata/build.gradle.kts
@@ -0,0 +1,60 @@
+/*
+ * ******************************************************************************
+ *   Copyright 2002 Spectra Logic Corporation. All Rights Reserved.
+ *   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
+ *   this file except in compliance with the License. A copy of the License is located at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   or in the "license" file accompanying this file.
+ *   This file 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.
+ * ****************************************************************************
+ */
+
+// bug in IntelliJ in which `libs` shows up as not being accessible
+// see https://youtrack.jetbrains.com/issue/KTIJ-19369
+@Suppress("DSL_SCOPE_VIOLATION")
+plugins {
+    `ds3-java-sdk-library-convention`
+    alias(libs.plugins.shadowPlugin)
+}
+
+dependencies {
+    api(project(":ds3-interfaces"))
+
+    implementation(project(":ds3-utils"))
+
+    implementation(libs.guava)
+    implementation(libs.jna)
+    implementation(libs.jnaPlatform)
+    implementation(libs.slf4jApi)
+
+    testImplementation(libs.commonsIo)
+    testImplementation(libs.commonsLang)
+    testImplementation(libs.httpclient)
+    testImplementation(libs.junit)
+
+    testRuntimeOnly(libs.slf4jSimple)
+}
+
+tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
+    relocate("org.apache", "ds3metafatjar.org.apache")
+    relocate("com.google", "ds3metafatjar.com.google")
+    relocate("com.sun.jna", "ds3metafatjar.net.java.dev.jna")
+    relocate("org.jetbrains", "ds3metafatjar.org.jetbrains")
+    relocate("org.intellij", "ds3metafatjar.org.intellij")
+    relocate("org.codehaus", "ds3metafatjar.org.codehaus")
+    dependencies {
+        exclude(project(":ds3-interfaces")) // this is being excluded since it must be used with the sdk, which already has this dependency included
+        exclude(project(":ds3-utils")) // this is being excluded since it must be used with the sdk, which already has this dependency included
+        exclude(dependency(libs.slf4jApi.get().toString()))
+        exclude(dependency(libs.slf4jSimple.get().toString()))
+        exclude(dependency(libs.hamcrest.get().toString()))
+        exclude(dependency(libs.mockitoCore.get().toString()))
+        exclude(dependency(libs.junit.get().toString()))
+        exclude(dependency(libs.commonsLang.get().toString()))
+    }
+    dependsOn(tasks.jar)
+}
diff --git a/ds3-sdk-integration/build.gradle.kts b/ds3-sdk-integration/build.gradle.kts
new file mode 100644
index 000000000..06755b8ac
--- /dev/null
+++ b/ds3-sdk-integration/build.gradle.kts
@@ -0,0 +1,34 @@
+/*
+ * ******************************************************************************
+ *   Copyright 2002 Spectra Logic Corporation. All Rights Reserved.
+ *   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
+ *   this file except in compliance with the License. A copy of the License is located at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   or in the "license" file accompanying this file.
+ *   This file 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.
+ * ****************************************************************************
+ */
+
+plugins {
+    `ds3-java-sdk-internal-convention`
+}
+
+dependencies {
+    implementation(project(":ds3-utils"))
+    implementation(project(":ds3-sdk"))
+
+    implementation(libs.commonsIo)
+    implementation(libs.guava)
+    implementation(libs.slf4jApi)
+    implementation(libs.hamcrest)
+    implementation(libs.junit)
+
+    testImplementation(project(":ds3-metadata"))
+
+    testImplementation(libs.httpclient)
+    testImplementation(libs.commonsLang)
+}
\ No newline at end of file
diff --git a/ds3-sdk-integration/build.gradle b/ds3-sdk-samples/build.gradle.kts
similarity index 67%
rename from ds3-sdk-integration/build.gradle
rename to ds3-sdk-samples/build.gradle.kts
index 7c77b95b5..e06d4df38 100644
--- a/ds3-sdk-integration/build.gradle
+++ b/ds3-sdk-samples/build.gradle.kts
@@ -1,6 +1,6 @@
 /*
  * ******************************************************************************
- *   Copyright 2014-2019 Spectra Logic Corporation. All Rights Reserved.
+ *   Copyright 2002 Spectra Logic Corporation. All Rights Reserved.
  *   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
  *   this file except in compliance with the License. A copy of the License is located at
  *
@@ -13,10 +13,18 @@
  * ****************************************************************************
  */
 
+plugins {
+    `ds3-java-sdk-internal-convention`
+    `application`
+}
+
 dependencies {
-    compile "commons-codec:commons-codec:$commonscodecVersion"
-    compile "junit:junit:$junitVersion"
-    testCompile "org.hamcrest:hamcrest-library:$hamcrestVersion"
-    testCompile group: 'org.apache.commons', name: 'commons-lang3', version: "$commonslangVersion"
+    implementation(project(":ds3-sdk"))
+    implementation(project(":ds3-utils"))
+
+    implementation(libs.guava)
 }
 
+application {
+    mainClass.set("com.spectralogic.ds3client.samples.PartialObjectGetExample")
+}
\ No newline at end of file
diff --git a/ds3-sdk/build.gradle b/ds3-sdk/build.gradle
deleted file mode 100644
index 8f8e1636c..000000000
--- a/ds3-sdk/build.gradle
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * ******************************************************************************
- *   Copyright 2014-2019 Spectra Logic Corporation. All Rights Reserved.
- *   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
- *   this file except in compliance with the License. A copy of the License is located at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- *   or in the "license" file accompanying this file.
- *   This file 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.
- * ****************************************************************************
- */
-
-import java.nio.file.Files
-import java.nio.file.Path
-
-apply plugin: 'com.github.johnrengelman.shadow'
-
-apply from: "$rootDir/gradle/scripts/publish.gradle"
-
-shadowJar {
-    relocate 'com.google', 'ds3fatjar.com.google'
-    relocate 'org.jetbrains', 'ds3fatjar.org.jetbrains'
-    relocate 'org.intellij', 'ds3fatjar.org.intellij'
-    relocate 'org.codehaus', 'ds3fatjar.org.codehaus'
-    relocate 'kotlin', 'ds3fatjar.kotlin'
-    relocate 'edu.umd', 'ds3fatjar.edu.emd'
-    relocate 'net.jcip', 'ds3fatjar.net.jcip'
-    relocate 'com.ctc', 'ds3fatjar.com.ctc'
-    relocate 'org.apache', 'ds3fatjar.org.apache'
-    relocate 'com.fasterxml', 'ds3fatjar.com.fasterxml'
-    dependencies {
-        exclude(dependency("org.hamcrest:hamcrest-library:$hamcrestVersion"))
-        exclude(dependency("org.mockito:mockito-core:$mockitoVersion"))
-        exclude(dependency("junit:junit:$junitVersion"))
-        exclude(dependency("org.slf4j:slf4j-api:$slf4jVersion"))
-        exclude(dependency("org.slf4j:slf4j-simple:$slf4jVersion"))
-        exclude(dependency("org.apache.commons:commons-lang3:$commonslangVersion"))
-    }
-
-    mergeServiceFiles()
-}
-
-artifacts {
-    archives shadowJar
-}
-
-task genConfigProperties {
-    doLast {
-        def productionBuild = System.getenv('productionBuild')
-        if (productionBuild == null) { productionBuild = 'false' }
-
-        File configFile = new File(sourceSets.main.output.resourcesDir, "/ds3_sdk.properties")
-        Path configPath = sourceSets.main.output.resourcesDir.toPath()
-        if (!Files.exists(configPath)) {
-            Files.createDirectories(configPath)
-        }
-
-        def gitInfo = versionDetails()
-
-        configFile.withWriter{out ->
-            out.writeLine("productionBuild=" + productionBuild.toString())
-            out.writeLine("version=" + version.toString())
-            out.writeLine("build.date=" + new Date().toString())
-            out.writeLine("git.commitHash=" + gitInfo.gitHashFull)
-        }
-    }
-}
-
-task zip(type: Zip) {
-  from configurations.runtime.allArtifacts.files
-  from configurations.runtime
-  into (project.name + "-" + project.version)
-}
-
-zip.dependsOn jar
-
-jar {
-    from sourceSets.main.allJava
-}
-
-jar.dependsOn genConfigProperties
-shadowJar.dependsOn genConfigProperties
-
-dependencies {
-    compile     "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
-    compile     "org.apache.httpcomponents:httpclient:$httpclientVersion"
-    compile     "com.fasterxml.jackson.datatype:jackson-datatype-jdk8:$jacksonVersion"
-    compile     "com.fasterxml.jackson.dataformat:jackson-dataformat-xml:$jacksonVersion"
-    compile     "com.google.guava:guava:$guavaVersion"
-    compile     'org.codehaus.woodstox:woodstox-core-asl:4.4.1'
-    compile     'com.google.code.findbugs:annotations:3.0.1'
-    testCompile "org.hamcrest:hamcrest-library:$hamcrestVersion"
-}
diff --git a/ds3-sdk/build.gradle.kts b/ds3-sdk/build.gradle.kts
new file mode 100644
index 000000000..dcfe985db
--- /dev/null
+++ b/ds3-sdk/build.gradle.kts
@@ -0,0 +1,94 @@
+/*
+ * ******************************************************************************
+ *   Copyright 2002 Spectra Logic Corporation. All Rights Reserved.
+ *   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
+ *   this file except in compliance with the License. A copy of the License is located at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   or in the "license" file accompanying this file.
+ *   This file 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.
+ * ****************************************************************************
+ */
+
+import java.time.Instant
+// bug in IntelliJ in which `libs` shows up as not being accessible
+// see https://youtrack.jetbrains.com/issue/KTIJ-19369
+@Suppress("DSL_SCOPE_VIOLATION")
+plugins {
+    `ds3-java-sdk-library-convention`
+    alias(libs.plugins.kotlinJvmPlugin)
+    alias(libs.plugins.shadowPlugin)
+    alias(libs.plugins.gitVersionPlugin)
+}
+
+dependencies {
+    implementation(platform(libs.jacksonBom))
+
+    api(project(":ds3-interfaces"))
+
+    implementation(project(":ds3-utils"))
+
+    implementation(libs.kotlinStdLib)
+    implementation(libs.commonsIo)
+    implementation(libs.guava)
+    implementation(libs.httpclient)
+    implementation(libs.jacksonDatatypeJdk8)
+    implementation(libs.jacksonDataformatXml)
+    implementation(libs.slf4jApi)
+    implementation(libs.findbugs)
+    implementation(libs.woodstoxCoreAsl)
+
+    testImplementation(platform(libs.mockitoBom))
+
+    testImplementation(libs.junit)
+    testImplementation(libs.mockitoCore)
+    testImplementation(libs.hamcrest)
+
+    testRuntimeOnly(libs.slf4jSimple)
+}
+
+val versionDetails: groovy.lang.Closure<com.palantir.gradle.gitversion.VersionDetails> by extra
+
+val genConfigProperties by tasks.registering(WriteProperties::class,) {
+    group = "build"
+    val getProdBuild = { value: String? -> value ?: "false" }
+    val gitDetails = versionDetails()
+    property("productionBuild", getProdBuild(System.getenv("productionBuild")))
+    property("version", version.toString())
+    property("build.date", Instant.now())
+    property("git.commitHash", gitDetails.gitHash)
+    outputFile = file("${buildDir}/ds3_sdk.properties")
+    encoding = "UTF-8"
+}
+
+tasks.jar {
+    dependsOn(genConfigProperties)
+}
+
+tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
+    relocate("com.ctc", "ds3fatjar.com.ctc")
+    relocate("com.fasterxml", "ds3fatjar.com.fasterxml")
+    relocate("com.google", "ds3fatjar.com.google")
+    relocate("edu.umd", "ds3fatjar.edu.emd")
+    relocate("kotlin", "ds3fatjar.kotlin")
+    relocate("net.jcip", "ds3fatjar.net.jcip")
+    relocate("org.apache", "ds3fatjar.org.apache")
+    relocate("org.codehaus", "ds3fatjar.org.codehaus")
+    relocate("org.intellij", "ds3fatjar.org.intellij")
+    relocate("org.jetbrains", "ds3fatjar.org.jetbrains")
+    dependencies {
+        exclude(dependency(libs.slf4jApi.get().toString()))
+    }
+    mergeServiceFiles()
+    dependsOn(tasks.jar)
+}
+
+val allProjectJars by tasks.registering(Zip::class) {
+    archiveFileName.set(project.name + "-" + project.version + ".zip")
+    destinationDirectory.set(layout.buildDirectory.dir("dist"))
+    from(configurations.runtimeClasspath)
+    dependsOn(tasks.jar)
+}
diff --git a/ds3-sdk/src/main/java/com/spectralogic/ds3client/serializer/XmlOutput.java b/ds3-sdk/src/main/java/com/spectralogic/ds3client/serializer/XmlOutput.java
index 0be57456c..34061180f 100644
--- a/ds3-sdk/src/main/java/com/spectralogic/ds3client/serializer/XmlOutput.java
+++ b/ds3-sdk/src/main/java/com/spectralogic/ds3client/serializer/XmlOutput.java
@@ -1,6 +1,6 @@
 /*
  * ******************************************************************************
- *   Copyright 2014-2019 Spectra Logic Corporation. All Rights Reserved.
+ *   Copyright 2014-2022 Spectra Logic Corporation. All Rights Reserved.
  *   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
  *   this file except in compliance with the License. A copy of the License is located at
  *
@@ -20,6 +20,7 @@
 import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
 import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule;
 import com.fasterxml.jackson.dataformat.xml.XmlMapper;
+import com.fasterxml.jackson.dataformat.xml.deser.FromXmlParser;
 import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
 import com.spectralogic.ds3client.models.bulk.Ds3ObjectList;
 import org.slf4j.Logger;
@@ -29,7 +30,6 @@
 import java.io.InputStream;
 import java.util.Properties;
 
-
 public final class XmlOutput {
     private static final JacksonXmlModule module;
     private static final XmlMapper mapper;
@@ -40,6 +40,9 @@ public final class XmlOutput {
         module = new JacksonXmlModule();
         module.setDefaultUseWrapper(false);
         mapper = new XmlMapper(module);
+        // we must treat <tag/> as having nil value - see discussion at
+        // https://github.com/SpectraLogic/ds3_java_sdk/pull/595
+        mapper.configure(FromXmlParser.Feature.EMPTY_ELEMENT_AS_NULL, true);
 
         mapper.registerModule(new Jdk8Module());
         final SimpleFilterProvider filterProvider = new SimpleFilterProvider().setFailOnUnknownId(false);
diff --git a/ds3-sdk/src/test/java/com/spectralogic/ds3client/helpers/Ds3ClientHelpers_Test.java b/ds3-sdk/src/test/java/com/spectralogic/ds3client/helpers/Ds3ClientHelpers_Test.java
index f8b6c94b8..38188bfe1 100644
--- a/ds3-sdk/src/test/java/com/spectralogic/ds3client/helpers/Ds3ClientHelpers_Test.java
+++ b/ds3-sdk/src/test/java/com/spectralogic/ds3client/helpers/Ds3ClientHelpers_Test.java
@@ -32,10 +32,10 @@
 import com.spectralogic.ds3client.networking.ConnectionDetails;
 import com.spectralogic.ds3client.networking.FailedRequestException;
 import com.spectralogic.ds3client.utils.ByteArraySeekableByteChannel;
+import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.Matchers;
 import org.mockito.Mockito;
 
 import java.io.IOException;
@@ -109,7 +109,7 @@ public SeekableByteChannel buildChannel(final String key) throws IOException {
     public void testReadObjectsWithFailedGet() throws IOException, ParseException {
         final Ds3Client ds3Client = mock(Ds3Client.class);
 
-        Mockito.when(ds3Client.newForNode(Matchers.any())).thenReturn(ds3Client);
+        Mockito.when(ds3Client.newForNode(any())).thenReturn(ds3Client);
 
         final GetBulkJobSpectraS3Response buildBulkGetResponse = buildBulkGetResponse();
         Mockito.when(ds3Client.getBulkJobSpectraS3(hasChunkOrdering(JobChunkClientProcessingOrderGuarantee.NONE))).thenReturn(buildBulkGetResponse);
@@ -144,7 +144,7 @@ public void testWriteObjects() throws IOException, ParseException {
         final Ds3Client ds3Client = buildDs3ClientForBulk();
 
         final PutBulkJobSpectraS3Response bulkPutResponse = buildBulkPutResponse();
-        Mockito.when(ds3Client.putBulkJobSpectraS3(Matchers.any(PutBulkJobSpectraS3Request.class))).thenReturn(bulkPutResponse);
+        Mockito.when(ds3Client.putBulkJobSpectraS3(any(PutBulkJobSpectraS3Request.class))).thenReturn(bulkPutResponse);
         
         final AllocateJobChunkSpectraS3Response allocateResponse1 = buildAllocateResponse1();
         final AllocateJobChunkSpectraS3Response allocateResponse2 = buildAllocateResponse2();
@@ -204,11 +204,11 @@ public void testWriteObjectsWithFailedPut() throws IOException, ParseException {
         final ConnectionDetails details = mock(ConnectionDetails.class);
         Mockito.when(details.getEndpoint()).thenReturn("localhost");
 
-        Mockito.when(ds3Client.newForNode(Matchers.any())).thenReturn(ds3Client);
+        Mockito.when(ds3Client.newForNode(any())).thenReturn(ds3Client);
         Mockito.when(ds3Client.getConnectionDetails()).thenReturn(details);
 
         final PutBulkJobSpectraS3Response buildBulkPutResponse = buildBulkPutResponse();
-        Mockito.when(ds3Client.putBulkJobSpectraS3(Matchers.any(PutBulkJobSpectraS3Request.class))).thenReturn(buildBulkPutResponse);
+        Mockito.when(ds3Client.putBulkJobSpectraS3(any(PutBulkJobSpectraS3Request.class))).thenReturn(buildBulkPutResponse);
 
         final AllocateJobChunkSpectraS3Response allocateResponse2 = buildAllocateResponse2();
         final AllocateJobChunkSpectraS3Response allocateResponse3 = buildAllocateResponse3();
@@ -296,7 +296,7 @@ public void testRecoverWriteJob() throws IOException, JobRecoveryException, Pars
         final Ds3Client ds3Client = buildDs3ClientForBulk();
 
         final ModifyJobSpectraS3Response modifyWriteJobResponse = buildModifyWriteJobResponse();
-        Mockito.when(ds3Client.modifyJobSpectraS3(Matchers.any(ModifyJobSpectraS3Request.class))).thenReturn(modifyWriteJobResponse);
+        Mockito.when(ds3Client.modifyJobSpectraS3(any(ModifyJobSpectraS3Request.class))).thenReturn(modifyWriteJobResponse);
 
         final Job job = Ds3ClientHelpers.wrap(ds3Client).recoverWriteJob(jobId);
         assertThat(job.getJobId(), is(jobId));
@@ -308,7 +308,7 @@ public void testRecoverWriteJobThrowsJobRecoveryExceptionForWrongRequestType() t
         final Ds3Client ds3Client = buildDs3ClientForBulk();
 
         final ModifyJobSpectraS3Response modifyReadJobResponse = buildModifyReadJobResponse();
-        Mockito.when(ds3Client.modifyJobSpectraS3(Matchers.any(ModifyJobSpectraS3Request.class))).thenReturn(modifyReadJobResponse);
+        Mockito.when(ds3Client.modifyJobSpectraS3(any(ModifyJobSpectraS3Request.class))).thenReturn(modifyReadJobResponse);
 
         Ds3ClientHelpers.wrap(ds3Client).recoverWriteJob(jobId);
     }
@@ -318,7 +318,7 @@ public void testRecoverReadJob() throws IOException, JobRecoveryException, Parse
         final Ds3Client ds3Client = buildDs3ClientForBulk();
 
         final ModifyJobSpectraS3Response modifyReadJobResponse = buildModifyReadJobResponse();
-        Mockito.when(ds3Client.modifyJobSpectraS3(Matchers.any(ModifyJobSpectraS3Request.class))).thenReturn(modifyReadJobResponse);
+        Mockito.when(ds3Client.modifyJobSpectraS3(any(ModifyJobSpectraS3Request.class))).thenReturn(modifyReadJobResponse);
 
         final Job job = Ds3ClientHelpers.wrap(ds3Client).recoverReadJob(jobId);
         assertThat(job.getJobId(), is(jobId));
@@ -330,7 +330,7 @@ public void testRecoverReadJobThrowsJobRecoveryExceptionForWrongRequestType() th
         final Ds3Client ds3Client = buildDs3ClientForBulk();
 
         final ModifyJobSpectraS3Response modifyWriteJobResponse = buildModifyWriteJobResponse();
-        Mockito.when(ds3Client.modifyJobSpectraS3(Matchers.any(ModifyJobSpectraS3Request.class))).thenReturn(modifyWriteJobResponse);
+        Mockito.when(ds3Client.modifyJobSpectraS3(any(ModifyJobSpectraS3Request.class))).thenReturn(modifyWriteJobResponse);
 
         Ds3ClientHelpers.wrap(ds3Client).recoverReadJob(jobId);
     }
@@ -424,7 +424,7 @@ private static Ds3Client buildDs3ClientForBulk() throws IOException,
             .thenReturn(jobChunksResponse2)
             .thenReturn(jobChunksResponse3);
 
-        Mockito.when(ds3Client.newForNode(Matchers.any())).thenReturn(ds3Client);
+        Mockito.when(ds3Client.newForNode(any())).thenReturn(ds3Client);
         Mockito.when(ds3Client.getConnectionDetails()).thenReturn(details);
         return ds3Client;
     }
@@ -613,7 +613,7 @@ public void testWriteObjectsWithRetryAfter() throws IOException, ParseException
 
         final PutBulkJobSpectraS3Response bulkPutResponse = buildBulkPutResponse();
         Mockito.when(ds3Client
-                .putBulkJobSpectraS3(Matchers.any(PutBulkJobSpectraS3Request.class)))
+                .putBulkJobSpectraS3(any(PutBulkJobSpectraS3Request.class)))
                 .thenReturn(bulkPutResponse);
 
         final AllocateJobChunkSpectraS3Response allocateResponse1 = buildAllocateResponse1();
@@ -675,22 +675,22 @@ public SeekableByteChannel buildChannel(final String key) throws IOException {
     public void testEnsureBucketExistsRace() throws IOException {
         final Ds3Client ds3Client = mock(Ds3Client.class);
         final HeadBucketResponse response = buildHeadBucketResponse(HeadBucketResponse.Status.DOESNTEXIST);
-        Mockito.when(ds3Client.headBucket(Matchers.any(HeadBucketRequest.class))).thenReturn(response);
-        Mockito.when(ds3Client.putBucket(Matchers.any(PutBucketRequest.class)))
+        Mockito.when(ds3Client.headBucket(any(HeadBucketRequest.class))).thenReturn(response);
+        Mockito.when(ds3Client.putBucket(any(PutBucketRequest.class)))
                 .thenThrow(new FailedRequestException(ImmutableList.of(202, 409), 409, new Error(), "Conflict", "5"));
 
         final Ds3ClientHelpers helpers = Ds3ClientHelpers.wrap(ds3Client);
 
         helpers.ensureBucketExists("fake_bucket"); // if this throws an exception, then this test should fail
-        verify(ds3Client, atLeastOnce()).putBucket(Matchers.any(PutBucketRequest.class));
+        verify(ds3Client, atLeastOnce()).putBucket(any(PutBucketRequest.class));
     }
 
     @Test(expected = FailedRequestException.class)
     public void testEnsureBucketExistsReturnsError() throws IOException {
         final Ds3Client ds3Client = mock(Ds3Client.class);
         final HeadBucketResponse response = buildHeadBucketResponse(HeadBucketResponse.Status.DOESNTEXIST);
-        Mockito.when(ds3Client.headBucket(Matchers.any(HeadBucketRequest.class))).thenReturn(response);
-        Mockito.when(ds3Client.putBucket(Matchers.any(PutBucketRequest.class)))
+        Mockito.when(ds3Client.headBucket(any(HeadBucketRequest.class))).thenReturn(response);
+        Mockito.when(ds3Client.putBucket(any(PutBucketRequest.class)))
                 .thenThrow(new FailedRequestException(ImmutableList.of(202, 409, 500), 500, new Error(), "Error", "5"));
 
         final Ds3ClientHelpers helpers = Ds3ClientHelpers.wrap(ds3Client);
diff --git a/ds3-sdk/src/test/java/com/spectralogic/ds3client/helpers/FileObjectGetter_Test.java b/ds3-sdk/src/test/java/com/spectralogic/ds3client/helpers/FileObjectGetter_Test.java
index 4a89a6366..b9409947c 100644
--- a/ds3-sdk/src/test/java/com/spectralogic/ds3client/helpers/FileObjectGetter_Test.java
+++ b/ds3-sdk/src/test/java/com/spectralogic/ds3client/helpers/FileObjectGetter_Test.java
@@ -44,7 +44,7 @@ public void testThatNamedPipeThrows() throws IOException, InterruptedException {
 
         final String tempPathPrefix = null;
         final Path tempDirectory = Files.createTempDirectory(Paths.get("."), tempPathPrefix);
-
+        tempDirectory.toFile().deleteOnExit();
         final String FIFO_NAME = "bFifo";
 
         final AtomicBoolean caughtException = new AtomicBoolean(false);
@@ -55,8 +55,6 @@ public void testThatNamedPipeThrows() throws IOException, InterruptedException {
         } catch (final UnrecoverableIOException e) {
             assertTrue(e.getMessage().contains(FIFO_NAME));
             caughtException.set(true);
-        } finally {
-            FileUtils.deleteDirectory(tempDirectory.toFile());
         }
 
         assertTrue(caughtException.get());
diff --git a/ds3-sdk/src/test/java/com/spectralogic/ds3client/helpers/FileObjectPutter_Test.java b/ds3-sdk/src/test/java/com/spectralogic/ds3client/helpers/FileObjectPutter_Test.java
index da894e7b9..665796118 100644
--- a/ds3-sdk/src/test/java/com/spectralogic/ds3client/helpers/FileObjectPutter_Test.java
+++ b/ds3-sdk/src/test/java/com/spectralogic/ds3client/helpers/FileObjectPutter_Test.java
@@ -160,7 +160,7 @@ public void testThatNamedPipeThrows() throws IOException, InterruptedException {
 
         final String tempPathPrefix = null;
         final Path tempDirectory = Files.createTempDirectory(Paths.get("."), tempPathPrefix);
-
+        tempDirectory.toFile().deleteOnExit();
         final String FIFO_NAME = "bFifo";
 
         final AtomicBoolean caughtException = new AtomicBoolean(false);
@@ -171,8 +171,6 @@ public void testThatNamedPipeThrows() throws IOException, InterruptedException {
         } catch (final UnrecoverableIOException e) {
             assertTrue(e.getMessage().contains(FIFO_NAME));
             caughtException.set(true);
-        } finally {
-            FileUtils.deleteDirectory(tempDirectory.toFile());
         }
 
         assertTrue(caughtException.get());
diff --git a/ds3-sdk/src/test/java/com/spectralogic/ds3client/helpers/RequestMatchers.java b/ds3-sdk/src/test/java/com/spectralogic/ds3client/helpers/RequestMatchers.java
index b96015a48..c8a914501 100644
--- a/ds3-sdk/src/test/java/com/spectralogic/ds3client/helpers/RequestMatchers.java
+++ b/ds3-sdk/src/test/java/com/spectralogic/ds3client/helpers/RequestMatchers.java
@@ -1,6 +1,6 @@
 /*
  * ******************************************************************************
- *   Copyright 2014-2019 Spectra Logic Corporation. All Rights Reserved.
+ *   Copyright 2014-2022 Spectra Logic Corporation. All Rights Reserved.
  *   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
  *   this file except in compliance with the License. A copy of the License is located at
  *
@@ -23,16 +23,17 @@
 import com.spectralogic.ds3client.commands.spectrads3.GetJobChunksReadyForClientProcessingSpectraS3Request;
 import com.spectralogic.ds3client.models.JobChunkClientProcessingOrderGuarantee;
 import org.apache.commons.io.IOUtils;
+import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
 import org.hamcrest.TypeSafeMatcher;
-import org.mockito.ArgumentMatcher;
 
 import java.io.IOException;
 import java.nio.channels.Channels;
 import java.nio.channels.SeekableByteChannel;
 import java.util.UUID;
 
-import static org.mockito.Matchers.argThat;
+import static org.mockito.hamcrest.MockitoHamcrest.argThat;
+
 
 public final class RequestMatchers {
     public static GetBulkJobSpectraS3Request hasChunkOrdering(final JobChunkClientProcessingOrderGuarantee chunkOrdering) {
@@ -211,22 +212,34 @@ private static String channelToString(final SeekableByteChannel channel) {
             throw new RuntimeException(e);
         }
     }
-    
+
     public static GetBucketRequest getBucketHas(final String bucket, final String marker) {
-        return argThat(new ArgumentMatcher<GetBucketRequest>() {
-            @Override
-            public boolean matches(final Object argument) {
-                if (!(argument instanceof GetBucketRequest)) {
-                    return false;
-                }
-                final GetBucketRequest getBucketRequest = ((GetBucketRequest)argument);
-                return
-                        getBucketRequest.getBucketName().equals(bucket)
-                        && (marker == null
+        return argThat(new GetBucketRequestMatcher(bucket, marker));
+    }
+
+    private static final class GetBucketRequestMatcher extends BaseMatcher<GetBucketRequest> {
+        private final String bucket;
+        private final String marker;
+        public GetBucketRequestMatcher(final String bucket, final String marker) {
+            this.bucket = bucket;
+            this.marker = marker;
+        }
+        @Override
+        public boolean matches(Object argument) {
+            if (!(argument instanceof GetBucketRequest)) {
+                return false;
+            }
+            final GetBucketRequest getBucketRequest = ((GetBucketRequest)argument);
+            return
+                    getBucketRequest.getBucketName().equals(bucket)
+                            && (marker == null
                             ? null == getBucketRequest.getMarker()
                             : marker.equals(getBucketRequest.getMarker()));
 
-            }
-        });
+        }
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("getBucketRequest matches");
+        }
     }
 }
diff --git a/ds3-sdk/src/test/java/com/spectralogic/ds3client/utils/JobUtils_Test.java b/ds3-sdk/src/test/java/com/spectralogic/ds3client/utils/JobUtils_Test.java
index 19529779e..5f90fdfca 100644
--- a/ds3-sdk/src/test/java/com/spectralogic/ds3client/utils/JobUtils_Test.java
+++ b/ds3-sdk/src/test/java/com/spectralogic/ds3client/utils/JobUtils_Test.java
@@ -1,6 +1,6 @@
 /*
  * ******************************************************************************
- *   Copyright 2014-2019 Spectra Logic Corporation. All Rights Reserved.
+ *   Copyright 2014-2022 Spectra Logic Corporation. All Rights Reserved.
  *   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
  *   this file except in compliance with the License. A copy of the License is located at
  *
@@ -35,7 +35,7 @@
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.Matchers.any;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
diff --git a/ds3-utils/build.gradle b/ds3-utils/build.gradle.kts
similarity index 70%
rename from ds3-utils/build.gradle
rename to ds3-utils/build.gradle.kts
index 370813280..8af1c3436 100644
--- a/ds3-utils/build.gradle
+++ b/ds3-utils/build.gradle.kts
@@ -1,7 +1,6 @@
-
 /*
  * ******************************************************************************
- *   Copyright 2014-2019 Spectra Logic Corporation. All Rights Reserved.
+ *   Copyright 2002 Spectra Logic Corporation. All Rights Reserved.
  *   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
  *   this file except in compliance with the License. A copy of the License is located at
  *
@@ -14,10 +13,16 @@
  * ****************************************************************************
  */
 
-apply from: "$rootDir/gradle/scripts/publish.gradle"
+plugins {
+    `ds3-java-sdk-library-convention`
+}
 
 dependencies {
-    compile "commons-codec:commons-codec:$commonscodecVersion"
-    compile "commons-io:commons-io:$commonsioVersion"
-    compile "com.google.guava:guava:$guavaVersion"
+    api(project(":ds3-interfaces"))
+
+    implementation(libs.commonsCodec)
+    implementation(libs.commonsIo)
+    implementation(libs.guava)
+
+    testImplementation(libs.junit)
 }
diff --git a/gradle.properties b/gradle.properties
deleted file mode 100644
index 81eac5e78..000000000
--- a/gradle.properties
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# *******************************************************************************
-#   Copyright 2014-2019 Spectra Logic Corporation. All Rights Reserved.
-#   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
-#   this file except in compliance with the License. A copy of the License is located at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-#   or in the "license" file accompanying this file.
-#   This file 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.
-# *****************************************************************************
-#
-
-commonscodecVersion=1.10
-commonsioVersion=2.4
-commonslangVersion=3.6
-guavaVersion=23.0
-hamcrestVersion=1.3
-httpclientVersion=4.5.3
-jacksonVersion=2.9.0
-jnaVersion=4.2.2
-junitVersion=4.12
-mockitoVersion=1.10.+
-slf4jVersion=1.7.25
\ No newline at end of file
diff --git a/gradle/scripts/publish.gradle b/gradle/scripts/publish.gradle
deleted file mode 100644
index 7c973e883..000000000
--- a/gradle/scripts/publish.gradle
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * ******************************************************************************
- *   Copyright 2014-2019 Spectra Logic Corporation. All Rights Reserved.
- *   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
- *   this file except in compliance with the License. A copy of the License is located at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- *   or in the "license" file accompanying this file.
- *   This file 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.
- * ****************************************************************************
- */
-
-apply plugin: 'com.jfrog.bintray'
-
-bintray {
-    user = System.getenv('BINTRAY_USER')
-    key = System.getenv('BINTRAY_KEY')
-
-    configurations = ['archives']
-
-    //dryRun = true
-    //publish = true
-
-    pkg {
-        name = "$project.name"
-        repo = "ds3"
-        userOrg = "spectralogic"
-        websiteUrl = "https://github.com/SpectraLogic/ds3_java_sdk"
-        vcsUrl = "https://github.com/SpectraLogic/ds3_java_sdk.git"
-        licenses = ['Apache-2.0']
-        version {
-            name = "$project.version"
-        }
-    }
-}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index f6b961fd5..249e5832f 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index b251836b4..ae04661ee 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,20 +1,5 @@
-#
-# *******************************************************************************
-#   Copyright 2014-2019 Spectra Logic Corporation. All Rights Reserved.
-#   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
-#   this file except in compliance with the License. A copy of the License is located at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-#   or in the "license" file accompanying this file.
-#   This file 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.
-# *****************************************************************************
-#
-
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index cccdd3d51..a69d9cb6c 100755
--- a/gradlew
+++ b/gradlew
@@ -1,78 +1,129 @@
-#!/usr/bin/env sh
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed 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
+#
+#      https://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.
+#
 
 ##############################################################################
-##
-##  Gradle start up script for UN*X
-##
+#
+#   Gradle start up script for POSIX generated by Gradle.
+#
+#   Important for running:
+#
+#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+#       noncompliant, but you have some other compliant shell such as ksh or
+#       bash, then to run this script, type that shell name before the whole
+#       command line, like:
+#
+#           ksh Gradle
+#
+#       Busybox and similar reduced shells will NOT work, because this script
+#       requires all of these POSIX shell features:
+#         * functions;
+#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+#         * compound commands having a testable exit status, especially «case»;
+#         * various built-in commands including «command», «set», and «ulimit».
+#
+#   Important for patching:
+#
+#   (2) This script targets any POSIX shell, so it avoids extensions provided
+#       by Bash, Ksh, etc; in particular arrays are avoided.
+#
+#       The "traditional" practice of packing multiple parameters into a
+#       space-separated string is a well documented source of bugs and security
+#       problems, so this is (mostly) avoided, by progressively accumulating
+#       options in "$@", and eventually passing that to Java.
+#
+#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+#       see the in-line comments for details.
+#
+#       There are tweaks for specific operating systems such as AIX, CygWin,
+#       Darwin, MinGW, and NonStop.
+#
+#   (3) This script is generated from the Groovy template
+#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       within the Gradle project.
+#
+#       You can find Gradle at https://github.com/gradle/gradle/.
+#
 ##############################################################################
 
 # Attempt to set APP_HOME
+
 # Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
+    [ -h "$app_path" ]
+do
+    ls=$( ls -ld "$app_path" )
+    link=${ls#*' -> '}
+    case $link in             #(
+      /*)   app_path=$link ;; #(
+      *)    app_path=$APP_HOME$link ;;
+    esac
 done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
 
 APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
+APP_BASE_NAME=${0##*/}
 
 # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 
 # Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
 
 warn () {
     echo "$*"
-}
+} >&2
 
 die () {
     echo
     echo "$*"
     echo
     exit 1
-}
+} >&2
 
 # OS specific support (must be 'true' or 'false').
 cygwin=false
 msys=false
 darwin=false
 nonstop=false
-case "`uname`" in
-  CYGWIN* )
-    cygwin=true
-    ;;
-  Darwin* )
-    darwin=true
-    ;;
-  MINGW* )
-    msys=true
-    ;;
-  NONSTOP* )
-    nonstop=true
-    ;;
+case "$( uname )" in                #(
+  CYGWIN* )         cygwin=true  ;; #(
+  Darwin* )         darwin=true  ;; #(
+  MSYS* | MINGW* )  msys=true    ;; #(
+  NONSTOP* )        nonstop=true ;;
 esac
 
 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 
+
 # Determine the Java command to use to start the JVM.
 if [ -n "$JAVA_HOME" ] ; then
     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
         # IBM's JDK on AIX uses strange locations for the executables
-        JAVACMD="$JAVA_HOME/jre/sh/java"
+        JAVACMD=$JAVA_HOME/jre/sh/java
     else
-        JAVACMD="$JAVA_HOME/bin/java"
+        JAVACMD=$JAVA_HOME/bin/java
     fi
     if [ ! -x "$JAVACMD" ] ; then
         die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -81,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
 location of your Java installation."
     fi
 else
-    JAVACMD="java"
+    JAVACMD=java
     which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 
 Please set the JAVA_HOME variable in your environment to match the
@@ -89,84 +140,101 @@ location of your Java installation."
 fi
 
 # Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
-    MAX_FD_LIMIT=`ulimit -H -n`
-    if [ $? -eq 0 ] ; then
-        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
-            MAX_FD="$MAX_FD_LIMIT"
-        fi
-        ulimit -n $MAX_FD
-        if [ $? -ne 0 ] ; then
-            warn "Could not set maximum file descriptor limit: $MAX_FD"
-        fi
-    else
-        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
-    fi
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+    case $MAX_FD in #(
+      max*)
+        MAX_FD=$( ulimit -H -n ) ||
+            warn "Could not query maximum file descriptor limit"
+    esac
+    case $MAX_FD in  #(
+      '' | soft) :;; #(
+      *)
+        ulimit -n "$MAX_FD" ||
+            warn "Could not set maximum file descriptor limit to $MAX_FD"
+    esac
 fi
 
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
-    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
+# Collect all arguments for the java command, stacking in reverse order:
+#   * args from the command line
+#   * the main class name
+#   * -classpath
+#   * -D...appname settings
+#   * --module-path (only if needed)
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+    JAVACMD=$( cygpath --unix "$JAVACMD" )
 
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
-    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
-    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-    JAVACMD=`cygpath --unix "$JAVACMD"`
-
-    # We build the pattern for arguments to be converted via cygpath
-    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
-    SEP=""
-    for dir in $ROOTDIRSRAW ; do
-        ROOTDIRS="$ROOTDIRS$SEP$dir"
-        SEP="|"
-    done
-    OURCYGPATTERN="(^($ROOTDIRS))"
-    # Add a user-defined pattern to the cygpath arguments
-    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
-        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
-    fi
     # Now convert the arguments - kludge to limit ourselves to /bin/sh
-    i=0
-    for arg in "$@" ; do
-        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
-        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
-
-        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
-            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
-        else
-            eval `echo args$i`="\"$arg\""
+    for arg do
+        if
+            case $arg in                                #(
+              -*)   false ;;                            # don't mess with options #(
+              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
+                    [ -e "$t" ] ;;                      #(
+              *)    false ;;
+            esac
+        then
+            arg=$( cygpath --path --ignore --mixed "$arg" )
         fi
-        i=$((i+1))
+        # Roll the args list around exactly as many times as the number of
+        # args, so each arg winds up back in the position where it started, but
+        # possibly modified.
+        #
+        # NB: a `for` loop captures its iteration list before it begins, so
+        # changing the positional parameters here affects neither the number of
+        # iterations, nor the values presented in `arg`.
+        shift                   # remove old arg
+        set -- "$@" "$arg"      # push replacement arg
     done
-    case $i in
-        (0) set -- ;;
-        (1) set -- "$args0" ;;
-        (2) set -- "$args0" "$args1" ;;
-        (3) set -- "$args0" "$args1" "$args2" ;;
-        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
-        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
-        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
-        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
-        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
-        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
-    esac
 fi
 
-# Escape application args
-save () {
-    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
-    echo " "
-}
-APP_ARGS=$(save "$@")
-
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
-  cd "$(dirname "$0")"
+# Collect all arguments for the java command;
+#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+#     shell script including quotes and variable substitutions, so put them in
+#     double quotes to make sure that they get re-expanded; and
+#   * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+        "-Dorg.gradle.appname=$APP_BASE_NAME" \
+        -classpath "$CLASSPATH" \
+        org.gradle.wrapper.GradleWrapperMain \
+        "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+    die "xargs is not available"
 fi
 
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+#   set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+        xargs -n1 |
+        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+        tr '\n' ' '
+    )" '"$@"'
+
 exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index e95643d6a..f127cfd49 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,84 +1,91 @@
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem  Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 000000000..00c4a77ab
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,78 @@
+/*
+ * ******************************************************************************
+ *   Copyright 2022 Spectra Logic Corporation. All Rights Reserved.
+ *   Licensed under the Apache License, Version 2.0 (the "License"). You may not use
+ *   this file except in compliance with the License. A copy of the License is located at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   or in the "license" file accompanying this file.
+ *   This file 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.
+ * ****************************************************************************
+ */
+
+rootProject.name = "ds3-java-sdk"
+
+include("ds3-interfaces")
+include("ds3-utils")
+include("ds3-sdk")
+include("ds3-metadata")
+include("ds3-sdk-samples")
+include("ds3-sdk-integration")
+
+dependencyResolutionManagement {
+    repositories {
+        mavenCentral()
+    }
+    versionCatalogs {
+        create("libs") {
+            version("kotlin", "1.6.10")
+            version("commons-codec", "1.15")
+            version("commons-io", "2.11.0")
+            version("commons-lang", "3.12.0")
+            version("findbugs", "3.0.1")
+            version("git-version-plugin", "0.12.2") // stuck on this version until we move from building with java 8
+            version("guava", "31.1-jre")
+            version("hamcrest", "2.2")
+            version("httpclient", "4.5.13")
+            version("jackson", "2.13.3")
+            version("jna", "4.5.1")
+            version("junit", "4.13.2")
+            version("mockito", "4.7.0")
+            version("shadow-plugin", "7.1.2")
+            version("slf4j", "1.7.36")
+            version("woodstox", "4.4.1")
+
+            library("commonsCodec", "commons-codec", "commons-codec").versionRef("commons-codec")
+            library("commonsIo", "commons-io","commons-io").versionRef("commons-io")
+            library("findbugs", "com.google.code.findbugs", "annotations").versionRef("findbugs")
+            library("guava", "com.google.guava", "guava").versionRef("guava")
+            library("httpclient", "org.apache.httpcomponents", "httpclient").versionRef("httpclient")
+            library("jacksonBom", "com.fasterxml.jackson", "jackson-bom").versionRef("jackson")
+            library("jacksonDatatypeJdk8", "com.fasterxml.jackson.datatype", "jackson-datatype-jdk8").withoutVersion()
+            library("jacksonDataformatXml", "com.fasterxml.jackson.dataformat", "jackson-dataformat-xml").withoutVersion()
+            library("jna", "net.java.dev.jna", "jna").versionRef("jna")
+            library("jnaPlatform", "net.java.dev.jna", "jna-platform").versionRef("jna")
+            library("kotlinStdLib", "org.jetbrains.kotlin", "kotlin-stdlib").versionRef("kotlin")
+            library("slf4jApi", "org.slf4j", "slf4j-api").versionRef("slf4j")
+            library("woodstoxCoreAsl", "org.codehaus.woodstox", "woodstox-core-asl").versionRef("woodstox")
+
+            // test only libraries
+            library("commonsLang", "org.apache.commons","commons-lang3").versionRef("commons-lang")
+            library("hamcrest", "org.hamcrest", "hamcrest").versionRef("hamcrest")
+            library("junit", "junit", "junit").versionRef("junit")
+            library("mockitoBom", "org.mockito", "mockito-bom").versionRef("mockito")
+            library("mockitoCore", "org.mockito", "mockito-core").withoutVersion()
+            library("slf4jSimple", "org.slf4j", "slf4j-simple").versionRef("slf4j")
+
+            //bundle("groovy", listOf("groovy-core", "groovy-json", "groovy-nio"))
+
+            // gradle plugins
+            plugin("gitVersionPlugin", "com.palantir.git-version").versionRef("git-version-plugin")
+            plugin("kotlinJvmPlugin", "org.jetbrains.kotlin.jvm").versionRef("kotlin")
+            plugin("shadowPlugin", "com.github.johnrengelman.shadow").versionRef("shadow-plugin")
+        }
+    }
+}