Repository: rest-assured/rest-assured
Pull request #1745 (2023-11-05 21:16:43)

Migrate from GMaven to GMavenPlus
Splitting the migration to GMavenPlus in #1742 into a separate PR.

appiepollo14: Works perfectly on JDK11!
keeganwitt: > Works perfectly on JDK11!

Ah, interesting. I was getting some weird Mockito errors I didn't understand on Java 8.
appiepollo14: No I'm sorry, It doesn't work like a charm. Mvn clean package does work in fact. But mvn clean install throws the same errors on the integration tests as I've written in my pull request. IMO some groovy exception throwing is different once switching to gmavenplus....?
appiepollo14: Checkout master, build with JDK 8, works
Checkout master, build with JDK 11 to java 1.8, exception in phase 'class generation' in source unit, unsupported Target MODULE
Checkout master, build with JDK 11, to java 11, with gmavenplus, throws errors as mentioned earlier. 

Any guidance?
keeganwitt: I don't understand yet why changing plugins would cause a change in behavior. The only thing I can guess is that there's different versions of Groovy dependencies on the classpath during compilation, but I haven't found them yet.
appiepollo14: Hi @keeganwitt did you figure anything out or have any ideas on how to figure it out? If not I'm kinda stuck 
keeganwitt: > Hi @keeganwitt did you figure anything out or have any ideas on how to figure it out? If not I'm kinda stuck

Not yet. I've reached out to the other Groovy devs to see if they have any ideas. This seems very strange.
keeganwitt: I can't even build the main branch on Windows, even when using Docker like
```powershell
docker run --rm -v "${HOME}/.m2:/root/.m2" -v "${pwd}:/project" -w /project maven:3.8-eclipse-temurin-11 mvn clean test
```
appiepollo14: @keeganwitt Im no windhoos user so I can't guide you 🥺
keeganwitt: What's strange is I'm getting lots of errors like
```
[ERROR] /project/modules/json-schema-validator/src/main/java/io/restassured/module/jsv/JsonSchemaValidator.java:[188,29] cannot find symbol
[ERROR]   symbol:   class JsonSchemaFactory
[ERROR]   location: class io.restassured.module.jsv.JsonSchemaValidator
```
And neither JsonSchemaFactory or JsonSchemaValidator are Groovy classes.
keeganwitt: Integration tests are failing, but compilation is succeeding.

Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a2b3f10e..64c074eb 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,7 +1,13 @@
 ---
 name: Java CI
 
-on: [push]
+on:
+  push:
+    branches:
+      - master
+  pull_request:
+    branches:
+      - master
 
 jobs:
   test:
@@ -22,6 +28,4 @@ jobs:
           java-version: ${{ matrix.java }}
           distribution: 'zulu'
       - name: Verify with Maven
-        run: mvn verify -B --file pom.xml
-
-...
+        run: mvn verify -B
diff --git a/.gitignore b/.gitignore
index c8fdc219..a2fecc2d 100755
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,9 @@ target
 .settings
 .springBeans
 .idea
+.metals
+.vscode
+.bloop
 classes/
 lib/
-rest-assured-all/dependency-reduced-pom.xml
\ No newline at end of file
+rest-assured-all/dependency-reduced-pom.xml
diff --git a/.scalafmt.conf b/.scalafmt.conf
new file mode 100644
index 00000000..6f5f340a
--- /dev/null
+++ b/.scalafmt.conf
@@ -0,0 +1,22 @@
+version = "3.7.15"
+runner.dialect = scala3
+maxColumn = 120
+align.preset = most
+align.multiline = false
+continuationIndent.defnSite = 2
+assumeStandardLibraryStripMargin = true
+docstrings.style = Asterisk
+docstrings.wrapMaxColumn = 80
+lineEndings = preserve
+includeCurlyBraceInSelectChains = false
+danglingParentheses.preset = true
+optIn.annotationNewlines = true
+newlines.alwaysBeforeMultilineDef = false
+rewrite.rules = [RedundantBraces]
+
+rewrite.redundantBraces.generalExpressions = false
+rewriteTokens = {
+  "⇒": "=>"
+  "→": "->"
+  "←": "<-"
+}
diff --git a/README.md b/README.md
index f8addf7f..23eb792e 100644
--- a/README.md
+++ b/README.md
@@ -11,9 +11,9 @@ languages into the Java domain.
 
 
 ## News
+* 2023-12-08: REST Assured 5.4.0 is released with several bug fixes and a [Kotlin Extension Module for Spring WebTest](https://github.com/rest-assured/rest-assured/wiki/Kotlin#kotlin-extension-module-for-spring-webtest). See [change log](https://raw.githubusercontent.com/rest-assured/rest-assured/master/changelog.txt) for more details.
 * 2023-09-08: REST Assured 5.3.2 is released with several bug fixes, better Spring MockMvc Support, better support for newer versions of Spring Security etc. See [change log](https://raw.githubusercontent.com/rest-assured/rest-assured/master/changelog.txt) for more details.
 * 2023-06-16: REST Assured 5.3.1 is released with several bug fixes and dependency upgrades. See [change log](https://raw.githubusercontent.com/rest-assured/rest-assured/master/changelog.txt) for more details.
-* 2022-11-18: REST Assured 5.3.0 is released. It adds [CSRF header support](https://github.com/rest-assured/rest-assured/wiki/Usage#csrf-header-token) and a much improved [CSRF support](https://github.com/rest-assured/rest-assured/wiki/Usage#csrf) in general. It also brings the [Spring MockMvc Module](https://github.com/rest-assured/rest-assured/wiki/Spring#spring-mock-mvc-module) up-to-date with changes in Spring Framework 6 and Spring Boot 3, as well as various other bug fixes and improvements. See [changelog](https://raw.githubusercontent.com/rest-assured/rest-assured/master/changelog.txt) for more details.
 
 [Older News](https://github.com/rest-assured/rest-assured/wiki/OldNews)
 
@@ -79,11 +79,11 @@ REST Assured supports any HTTP method but has explicit support for *POST*, *GET*
 
 * [Getting started](https://github.com/rest-assured/rest-assured/wiki/GettingStarted)
 * [Usage Guide](https://github.com/rest-assured/rest-assured/wiki/Usage) (click [here](https://github.com/rest-assured/rest-assured/wiki/Usage_Legacy) for legacy documentation)
-* [Javadoc](http://www.javadoc.io/doc/io.rest-assured/rest-assured/5.3.2)
-* [Rest Assured Javadoc](http://static.javadoc.io/io.rest-assured/rest-assured/5.3.2/io/restassured/RestAssured.html)
-* [Rest AssuredMockMvc Javadoc](http://static.javadoc.io/io.rest-assured/spring-mock-mvc/5.3.2/io/restassured/module/mockmvc/RestAssuredMockMvc.html)
-* [XmlPath Javadoc](http://static.javadoc.io/io.rest-assured/xml-path/5.3.2/io/restassured/path/xml/XmlPath.html)
-* [JsonPath Javadoc](http://static.javadoc.io/io.rest-assured/json-path/5.3.2/io/restassured/path/json/JsonPath.html)
+* [Javadoc](http://www.javadoc.io/doc/io.rest-assured/rest-assured/5.4.0)
+* [Rest Assured Javadoc](http://static.javadoc.io/io.rest-assured/rest-assured/5.4.0/io/restassured/RestAssured.html)
+* [Rest AssuredMockMvc Javadoc](http://static.javadoc.io/io.rest-assured/spring-mock-mvc/5.4.0/io/restassured/module/mockmvc/RestAssuredMockMvc.html)
+* [XmlPath Javadoc](http://static.javadoc.io/io.rest-assured/xml-path/5.4.0/io/restassured/path/xml/XmlPath.html)
+* [JsonPath Javadoc](http://static.javadoc.io/io.rest-assured/json-path/5.4.0/io/restassured/path/json/JsonPath.html)
 * [Release Notes](https://github.com/rest-assured/rest-assured/wiki/ReleaseNotes)
 * [FAQ](https://github.com/rest-assured/rest-assured/wiki/FAQ)
 
diff --git a/changelog.txt b/changelog.txt
index f0049119..df0a1e3b 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,8 +1,33 @@
 Changelog next version
 ----------------------
+* Removing custom validation of pathParams in the mock-mvc module and instead rely on the Spring implementation(issue 1782) (thanks to taeyeon-Kim for pull request)
+* Fixing "Error java.lang.NoSuchMethodError for HttpMethod.resolve()" in mock-mvc module (issue 1760) (thanks to d0vi for pull request)
+* Fix #1707: SVG file upload - fatal error :1:1: content is not allowed in prolog (#1777) (thanks to Byounghee kim for pull request)
+* Fix #1773: Remove check for response HTTP status code. (thanks to macmon for pull request)
+* Introducing the "scala-extensions" module for Scala 3 (#1770). This means that you can write tests like this in Scala 3:
+
+    @Test
+    def `extraction with rest assured scala extensions`: Unit =
+        val message: String = Given(req =>
+            req.port(7000)
+            req.header("Header", "Header")
+            req.body("hello")
+        )
+        .When(
+            _.put("/the/path")
+        )
+        .Extract(
+            _.path("message")
+        )
+    assertThat(message).isEqualTo("Hello World")
+  (thanks to Carlos Eduardo for pull request)
+* Remove deprecated Content-Transfer-Encoding from multipart post headers (#1762) (thanks to Michal Trna for pull request)
+* Fixed pathParams double encoding in mock-mvd module (#1756) (thanks to Dmitry Kaukov for pull request)
+
+Changelog 5.4.0 (2023-12-08)
+----------------------------
 * Properly parse primitive JSON values (thanks to Jörg Eichhorn for pull request)
-* Upgraded Groovy from 4.0.10 to 4.0.14
-* Fix issue #1713 - endless loop in partiallyApplyPathParams (thanks to Oleksandr Kulychok for pull request)
+* Upgraded Groovy from 4.0.10 to 4.0.16
 * Introduce spring-web-test-client-kotlin-extensions (#1731) (thanks for TheDevLuffy for pull request). This means that if you depend on: `org.restassured:spring-web-test-client-kotlin-extensions:<version>` you can write code like this for Spring WebTest client:
    val id: Int =
    Given {
diff --git a/dist/dist-json-path/pom.xml b/dist/dist-json-path/pom.xml
index b88853cd..0c6a9d00 100644
--- a/dist/dist-json-path/pom.xml
+++ b/dist/dist-json-path/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>dist</artifactId>
         <groupId>io.rest-assured</groupId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/dist/dist-json-schema-validator/pom.xml b/dist/dist-json-schema-validator/pom.xml
index 8899b614..202e6538 100644
--- a/dist/dist-json-schema-validator/pom.xml
+++ b/dist/dist-json-schema-validator/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>dist</artifactId>
         <groupId>io.rest-assured</groupId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/dist/dist-kotlin-extensions/pom.xml b/dist/dist-kotlin-extensions/pom.xml
index 689cf4ab..7f2752b1 100644
--- a/dist/dist-kotlin-extensions/pom.xml
+++ b/dist/dist-kotlin-extensions/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>dist</artifactId>
         <groupId>io.rest-assured</groupId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/dist/dist-rest-assured/pom.xml b/dist/dist-rest-assured/pom.xml
index 7b307122..7db56033 100644
--- a/dist/dist-rest-assured/pom.xml
+++ b/dist/dist-rest-assured/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>dist</artifactId>
         <groupId>io.rest-assured</groupId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/dist/dist-scala-support/pom.xml b/dist/dist-scala-support/pom.xml
index 3289b85b..ffbf4ca9 100644
--- a/dist/dist-scala-support/pom.xml
+++ b/dist/dist-scala-support/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>dist</artifactId>
         <groupId>io.rest-assured</groupId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/dist/dist-spring-mock-mvc/pom.xml b/dist/dist-spring-mock-mvc/pom.xml
index df84ce0d..9964c320 100644
--- a/dist/dist-spring-mock-mvc/pom.xml
+++ b/dist/dist-spring-mock-mvc/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>dist</artifactId>
         <groupId>io.rest-assured</groupId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/dist/dist-xml-path/pom.xml b/dist/dist-xml-path/pom.xml
index 6109fde5..e62d0fc0 100644
--- a/dist/dist-xml-path/pom.xml
+++ b/dist/dist-xml-path/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>dist</artifactId>
         <groupId>io.rest-assured</groupId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/dist/pom.xml b/dist/pom.xml
index dd5d073f..8fa017ea 100644
--- a/dist/pom.xml
+++ b/dist/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>rest-assured-parent</artifactId>
         <groupId>io.rest-assured</groupId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/examples/kotlin-example/pom.xml b/examples/kotlin-example/pom.xml
index 1d03dae8..2eeb3263 100644
--- a/examples/kotlin-example/pom.xml
+++ b/examples/kotlin-example/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <groupId>io.rest-assured.examples</groupId>
         <artifactId>example-parent</artifactId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -78,13 +78,13 @@
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>rest-assured</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>kotlin-extensions</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git a/examples/pom.xml b/examples/pom.xml
index 972ff008..840c7a0b 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>rest-assured-parent</artifactId>
         <groupId>io.rest-assured</groupId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <groupId>io.rest-assured.examples</groupId>
diff --git a/examples/scala-example/pom.xml b/examples/scala-example/pom.xml
index 2f75b5cf..ac1fc99c 100644
--- a/examples/scala-example/pom.xml
+++ b/examples/scala-example/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <groupId>io.rest-assured.examples</groupId>
         <artifactId>example-parent</artifactId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -76,13 +76,13 @@
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>rest-assured</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>scala-support</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git a/examples/scala-mock-mvc-example/pom.xml b/examples/scala-mock-mvc-example/pom.xml
index ef9cc1ea..510fc9aa 100644
--- a/examples/scala-mock-mvc-example/pom.xml
+++ b/examples/scala-mock-mvc-example/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <groupId>io.rest-assured.examples</groupId>
         <artifactId>example-parent</artifactId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -77,13 +77,13 @@
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>spring-mock-mvc</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>scala-support</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git a/examples/scalatra-example/pom.xml b/examples/scalatra-example/pom.xml
index d588cfc6..afc1993f 100644
--- a/examples/scalatra-example/pom.xml
+++ b/examples/scalatra-example/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <groupId>io.rest-assured.examples</groupId>
         <artifactId>example-parent</artifactId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/examples/scalatra-webapp/pom.xml b/examples/scalatra-webapp/pom.xml
index 87ef99e9..3bffca74 100644
--- a/examples/scalatra-webapp/pom.xml
+++ b/examples/scalatra-webapp/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <groupId>io.rest-assured.examples</groupId>
         <artifactId>example-parent</artifactId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -38,7 +38,7 @@
         <dependency>
             <groupId>io.rest-assured.examples</groupId>
             <artifactId>scalatra-example</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>javax.servlet</groupId>
diff --git a/examples/spring-mvc-webapp/pom.xml b/examples/spring-mvc-webapp/pom.xml
index a3fa08b8..773c382a 100644
--- a/examples/spring-mvc-webapp/pom.xml
+++ b/examples/spring-mvc-webapp/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <groupId>io.rest-assured.examples</groupId>
         <artifactId>example-parent</artifactId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -54,7 +54,7 @@
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>spring-mock-mvc</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git a/json-path/pom.xml b/json-path/pom.xml
index 627d0933..fb4879f4 100644
--- a/json-path/pom.xml
+++ b/json-path/pom.xml
@@ -20,14 +20,14 @@
     <parent>
         <groupId>io.rest-assured</groupId>
         <artifactId>rest-assured-parent</artifactId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <groupId>io.rest-assured</groupId>
     <artifactId>json-path</artifactId>
     <packaging>bundle</packaging>
-    <version>5.3.3-SNAPSHOT</version>
+    <version>5.4.1-SNAPSHOT</version>
     <name>json-path</name>
-    <url>http://maven.apache.org</url>
+    <url>https://rest-assured.io/</url>
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
@@ -35,8 +35,8 @@
     <build>
         <plugins>
             <plugin>
-                <groupId>org.codehaus.gmaven</groupId>
-                <artifactId>gmaven-plugin</artifactId>
+                <groupId>org.codehaus.gmavenplus</groupId>
+                <artifactId>gmavenplus-plugin</artifactId>
             </plugin>
             <plugin>
                 <groupId>org.apache.felix</groupId>
@@ -116,7 +116,7 @@
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>rest-assured-common</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
         </dependency>
 
         <!-- Test -->
diff --git a/modules/json-schema-validator/pom.xml b/modules/json-schema-validator/pom.xml
index e9dbc259..3c516fbb 100644
--- a/modules/json-schema-validator/pom.xml
+++ b/modules/json-schema-validator/pom.xml
@@ -20,12 +20,12 @@
     <parent>
         <groupId>io.rest-assured</groupId>
         <artifactId>modules</artifactId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <artifactId>json-schema-validator</artifactId>
-    <version>5.3.3-SNAPSHOT</version>
+    <version>5.4.1-SNAPSHOT</version>
     <name>json-schema-validator</name>
-    <url>http://maven.apache.org</url>
+    <url>https://rest-assured.io/</url>
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
diff --git a/modules/kotlin-extensions/pom.xml b/modules/kotlin-extensions/pom.xml
index 246ff318..8f347a9d 100644
--- a/modules/kotlin-extensions/pom.xml
+++ b/modules/kotlin-extensions/pom.xml
@@ -20,12 +20,12 @@
     <parent>
         <groupId>io.rest-assured</groupId>
         <artifactId>modules</artifactId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <artifactId>kotlin-extensions</artifactId>
-    <version>5.3.3-SNAPSHOT</version>
+    <version>5.4.1-SNAPSHOT</version>
     <name>kotlin-extensions</name>
-    <url>http://maven.apache.org</url>
+    <url>https://rest-assured.io/</url>
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
@@ -38,7 +38,7 @@
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>rest-assured</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
         </dependency>
 
         <!-- Test -->
@@ -128,4 +128,4 @@
             </plugin>
         </plugins>
     </build>
-</project>
\ No newline at end of file
+</project>
diff --git a/modules/pom.xml b/modules/pom.xml
index 1c178345..8b79a9ef 100644
--- a/modules/pom.xml
+++ b/modules/pom.xml
@@ -15,11 +15,12 @@
   ~ limitations under the License.
   -->
 
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <parent>
         <artifactId>rest-assured-parent</artifactId>
         <groupId>io.rest-assured</groupId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>modules</artifactId>
@@ -29,6 +30,7 @@
         <module>json-schema-validator</module>
         <module>spring-mock-mvc</module>
         <module>scala-support</module>
+        <module>scala-extensions</module>
         <module>spring-web-test-client</module>
         <module>spring-commons</module>
         <module>kotlin-extensions</module>
diff --git a/modules/scala-extensions/pom.xml b/modules/scala-extensions/pom.xml
new file mode 100644
index 00000000..6dc5edf7
--- /dev/null
+++ b/modules/scala-extensions/pom.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0"?>
+<!--
+~ Copyright 2024 the original author or 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
+~
+~        http://www.apache.org/licenses/LICENSE-2.0
+~
+~ Unless required by applicable law or agreed to in writing, software
+~ distributed under the License is distributed on an "AS IS" BASIS,
+~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~ See the License for the specific language governing permissions and
+~ limitations under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>io.rest-assured</groupId>
+        <artifactId>modules</artifactId>
+        <version>5.4.1-SNAPSHOT</version>
+    </parent>
+    <artifactId>scala-extensions</artifactId>
+    <version>5.4.1-SNAPSHOT</version>
+    <name>scala-extensions</name>
+    <url>http://maven.apache.org</url>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <scala-maven-plugin.version>4.8.1</scala-maven-plugin.version>
+        <scala.version>3.3.1</scala.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.scala-lang</groupId>
+            <artifactId>scala3-library_3</artifactId>
+            <version>${scala.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.rest-assured</groupId>
+            <artifactId>rest-assured</artifactId>
+            <version>5.4.1-SNAPSHOT</version>
+        </dependency>
+
+        <!-- Test -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <profiles>
+        <profile>
+            <id>release</id>
+            <build>
+                <plugins>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+    <build>
+        <sourceDirectory>src/main/scala</sourceDirectory>
+        <testSourceDirectory>src/test/scala</testSourceDirectory>
+        <plugins>
+            <plugin>
+                <groupId>net.alchim31.maven</groupId>
+                <artifactId>scala-maven-plugin</artifactId>
+                <version>${scala-maven-plugin.version}</version>
+                <executions>
+                    <execution>
+                        <?m2e ignore?>
+                        <id>scala-compile-first</id>
+                        <phase>process-resources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                            <goal>compile</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <?m2e ignore?>
+                        <id>scala-test-compile</id>
+                        <phase>process-test-resources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                            <goal>testCompile</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <scalaVersion>${scala.version}</scalaVersion>
+                    <args>
+                        <arg>-feature</arg>
+                        <arg>-deprecation</arg>
+                        <arg>-Ysemanticdb</arg>
+                    </args>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/modules/scala-extensions/src/main/scala/io/restassured/module/scala/extensions/RestAssuredScalaExtensions.scala b/modules/scala-extensions/src/main/scala/io/restassured/module/scala/extensions/RestAssuredScalaExtensions.scala
new file mode 100644
index 00000000..f710b121
--- /dev/null
+++ b/modules/scala-extensions/src/main/scala/io/restassured/module/scala/extensions/RestAssuredScalaExtensions.scala
@@ -0,0 +1,179 @@
+package io.restassured.module.scala.extensions
+
+import scala.reflect.ClassTag
+import scala.util.chaining.*
+
+import io.restassured.RestAssured.`given`
+import io.restassured.internal.{ResponseSpecificationImpl, ValidatableResponseImpl}
+import io.restassured.response.{ExtractableResponse, Response, ValidatableResponse}
+import io.restassured.specification.RequestSpecification
+
+// Main wrappers
+
+/**
+ * A wrapper around [given] that starts building the request part of the test.
+ * E.g.
+ * {{{
+ * Given(_.params("firstName", "John"))
+ *  .When(_.post("/greetXML"))
+ *  .Then(res =>
+ *    res.statusCode(200)
+ *    res.body("greeting.firstName", equalTo("John"))
+ * )
+ * }}}
+ * will send a POST request to "/greetXML" with request parameters
+ * `firstName=John` and `lastName=Doe` and expect that the response body
+ * containing JSON or XML firstName equal to John.
+ *
+ * @return
+ *   A request specification.
+ *
+ * @see
+ *   io.restassured.RestAssured.given
+ */
+def Given(block: RequestSpecification => RequestSpecification): RequestSpecification =
+  `given`().pipe(block)
+
+/**
+ * A wrapper around [given] that starts building the request part of the test.
+ * This is an overloaded version of [Given] that does not take any arguments.
+ * E.g.
+ * {{{
+ * Given()
+ *  .When(_.post("/greetXML"))
+ *  .Then(_.statusCode(200))
+ * }}}
+ * will send a POST request to "/greetXML" request parameters and expect that
+ * the statusCode 200.
+ *
+ * @return
+ *   A request specification.
+ *
+ * @see
+ *   io.restassured.RestAssured.given
+ */
+def Given(): RequestSpecification =
+  `given`()
+
+extension (spec: RequestSpecification)
+  /**
+   * A wrapper around [io.restassured.RestAssured.when] to start building the
+   * DSL expression by sending a request without any parameters or headers etc.
+   * E.g.
+   * {{{
+   * Given()
+   *   .When(_.get("/x"))
+   *   .Then(_.body("x.y.z1", equalTo("Z1")))
+   * }}}
+   * Note that if you need to add parameters, headers, cookies or other request
+   * properties use the [[Given()]] method.
+   *
+   * @see
+   *   io.restassured.RestAssured.when
+   * @return
+   *   A request sender interface that let's you call resources on the server
+   */
+  infix def When(block: RequestSpecification => Response): Response =
+    spec.`when`().pipe(block)
+
+extension (resp: Response)
+  /**
+   * A wrapper around [then] that lets you validate the response. This method
+   * returns a [[ValidatableResponse]] that lets you chain validation methods or
+   * extract values from the response with the [[Extract]] method. Usage
+   * example:
+   * {{{
+   * Given(_.params("firstName", "John")
+   *  .When(_.post("/greetXML"))
+   *  .Then(_.body("greeting.firstName", equalTo("John")))
+   * }}}
+   *
+   * @return
+   *   A validatable response
+   */
+  infix def Then(block: ValidatableResponse => ValidatableResponse): ValidatableResponse =
+    resp
+      .`then`()
+      .tap(doIfValidatableResponseImpl(resp => resp.forceDisableEagerAssert()))
+      .pipe(block)
+      .tap(doIfValidatableResponseImpl(resp => resp.forceValidateResponse()))
+
+  /**
+   * A wrapper around [then] that lets you validate the response. This method is
+   * an overloaded version of [Then] that returns Unit so it's automatically
+   * picked-up by test frameworks like JUnit which expect tests to return Unit.
+   * Usage example:
+   * {{{
+   * Given(_.params("firstName", "John")
+   *  .When(_.post("/greetXML"))
+   *  .ThenAssert(_.body("greeting.firstName", equalTo("John")))
+   * }}}
+   *
+   * @return
+   *   A validatable response
+   */
+  infix def ThenAssert(block: ValidatableResponse => ValidatableResponse): Unit =
+    resp.Then(block)
+end extension
+
+extension [T](resp: Response)
+  /**
+   * A wrapper around [ExtractableResponse] that lets you validate the response.
+   * Usage example:
+   * {{{
+   * val firstName: String = Given(_.params("firstName", "John")
+   *  .When(_.post("/greetXML"))
+   *  .Then(_.body("greeting.firstName", equalTo("John")))
+   *  .Extract(_.path("greeting.firstName"))
+   * }}}
+   * The above code will send a POST request to "/greetXML" with request
+   * parameters `firstName=John` and `lastName=Doe` and expect that the response
+   * body containing JSON or XML firstName equal to John. The response is then
+   * validated and the firstName is extracted from the response. The extracted
+   * firstName is then returned. The type of the extracted value is needs to be
+   * specified as a type parameter.
+   *
+   * @return
+   *   The extracted value
+   */
+  infix def Extract(
+    block: ExtractableResponse[Response] => T
+  )(using
+    ClassTag[T]
+  ): T =
+    resp.`then`().extract().pipe(block)
+
+extension [T](resp: ValidatableResponse)
+  /**
+   * A wrapper around [ValidatableResponse] that lets you validate the response.
+   * Usage example:
+   * {{{
+   * val firstName: String = Given(_.params("firstName", "John")
+   *  .When(_.post("/greetXML"))
+   *  .Then(_.body("greeting.firstName", equalTo("John")))
+   *  .Extract(_.path("greeting.firstName"))
+   * }}}
+   * The above code will send a POST request to "/greetXML" with request
+   * parameters `firstName=John` and `lastName=Doe` and expect that the response
+   * body containing JSON or XML firstName equal to John. The response is then
+   * validated and the firstName is extracted from the response. The extracted
+   * firstName is then returned. The type of the extracted value is needs to be
+   * specified as a type parameter.
+   *
+   * @return
+   *   The extracted value
+   */
+  infix def Extract(
+    block: ExtractableResponse[Response] => T
+  )(using
+    ClassTag[T]
+  ): T =
+    resp.extract().pipe(block)
+
+// End main wrappers
+
+private def doIfValidatableResponseImpl(fn: ResponseSpecificationImpl => Unit): ValidatableResponse => Unit =
+  resp =>
+    resp match
+      case resp: ValidatableResponseImpl => fn(resp.responseSpec)
+      case _                             => ()
diff --git a/modules/scala-support/pom.xml b/modules/scala-support/pom.xml
index 548d77c2..5a363df4 100644
--- a/modules/scala-support/pom.xml
+++ b/modules/scala-support/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <groupId>io.rest-assured</groupId>
         <artifactId>modules</artifactId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -79,7 +79,7 @@
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>rest-assured</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>junit</groupId>
diff --git a/modules/spring-commons/pom.xml b/modules/spring-commons/pom.xml
index e07aa784..32e833f0 100644
--- a/modules/spring-commons/pom.xml
+++ b/modules/spring-commons/pom.xml
@@ -19,12 +19,12 @@
     <parent>
         <groupId>io.rest-assured</groupId>
         <artifactId>modules</artifactId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <artifactId>spring-commons</artifactId>
-    <version>5.3.3-SNAPSHOT</version>
+    <version>5.4.1-SNAPSHOT</version>
     <name>spring-commons</name>
-    <url>http://maven.apache.org</url>
+    <url>https://rest-assured.io/</url>
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <spring.version>5.0.9.RELEASE</spring.version>
@@ -34,7 +34,7 @@
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>rest-assured</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
         </dependency>
     </dependencies>
-</project>
\ No newline at end of file
+</project>
diff --git a/modules/spring-mock-mvc-kotlin-extensions/pom.xml b/modules/spring-mock-mvc-kotlin-extensions/pom.xml
index 228ff9a5..748501c1 100644
--- a/modules/spring-mock-mvc-kotlin-extensions/pom.xml
+++ b/modules/spring-mock-mvc-kotlin-extensions/pom.xml
@@ -20,13 +20,13 @@
     <parent>
         <artifactId>modules</artifactId>
         <groupId>io.rest-assured</groupId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
 
     <artifactId>spring-mock-mvc-kotlin-extensions</artifactId>
-    <version>5.3.3-SNAPSHOT</version>
+    <version>5.4.1-SNAPSHOT</version>
     <name>spring-mock-mvc-kotlin-extensions</name>
-    <url>http://maven.apache.org</url>
+    <url>https://rest-assured.io/</url>
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
@@ -39,7 +39,7 @@
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>spring-mock-mvc</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>javax.servlet</groupId>
diff --git a/modules/spring-mock-mvc/pom.xml b/modules/spring-mock-mvc/pom.xml
index 068324b7..ee52fed2 100644
--- a/modules/spring-mock-mvc/pom.xml
+++ b/modules/spring-mock-mvc/pom.xml
@@ -20,12 +20,12 @@
     <parent>
         <groupId>io.rest-assured</groupId>
         <artifactId>modules</artifactId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <artifactId>spring-mock-mvc</artifactId>
-    <version>5.3.3-SNAPSHOT</version>
+    <version>5.4.1-SNAPSHOT</version>
     <name>spring-mock-mvc</name>
-    <url>http://maven.apache.org</url>
+    <url>https://rest-assured.io/</url>
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <spring.version>5.1.13.RELEASE</spring.version>
@@ -36,7 +36,7 @@
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>rest-assured</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
             <exclusions>
                 <exclusion>
                     <!-- Spring provides its own JCL implementation -->
@@ -48,7 +48,7 @@
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>spring-commons</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
diff --git a/modules/spring-mock-mvc/src/main/java/io/restassured/module/mockmvc/internal/MockMvcRequestSenderImpl.java b/modules/spring-mock-mvc/src/main/java/io/restassured/module/mockmvc/internal/MockMvcRequestSenderImpl.java
index dbbd0916..285a9d17 100644
--- a/modules/spring-mock-mvc/src/main/java/io/restassured/module/mockmvc/internal/MockMvcRequestSenderImpl.java
+++ b/modules/spring-mock-mvc/src/main/java/io/restassured/module/mockmvc/internal/MockMvcRequestSenderImpl.java
@@ -217,7 +217,7 @@ class MockMvcRequestSenderImpl implements MockMvcRequestSender, MockMvcRequestAs
             } catch(IllegalArgumentException e) {
             	// Do nothing as only found on MockCookie
             }
-            
+
             try {
                 ZonedDateTime expires = invokeMethod(servletCookie, "getExpires");
                 if(expires != null) {
@@ -322,20 +322,6 @@ class MockMvcRequestSenderImpl implements MockMvcRequestSender, MockMvcRequestAs
         return builder.toString();
     }
 
-    private void validateUnnamedPathParams(final Object[] unnamedPathParams) {
-        Arrays.stream(unnamedPathParams).filter(param -> !(param instanceof String))
-                .findAny().ifPresent(param -> {
-                    throw new IllegalArgumentException("Only Strings allowed in path parameters.");
-                });
-    }
-
-    private void validateNamedPathParams(final Map<String, Object> namedPathParams) {
-        namedPathParams.entrySet().stream().filter(e -> !(e.getValue() instanceof String))
-                .findAny().ifPresent(param -> {
-                    throw new IllegalArgumentException("Only Strings allowed in path parameters.");
-                });
-    }
-
     private MockMvcResponse sendRequest(HttpMethod method, String path, Object[] unnamedPathParams) {
         notNull(path, "Path");
         verifyNoBodyAndMultipartTogether();
@@ -413,9 +399,6 @@ class MockMvcRequestSenderImpl implements MockMvcRequestSender, MockMvcRequestAs
             final String baseUri,
             final Object[] unnamedPathParams
     ) {
-        validateUnnamedPathParams(unnamedPathParams);
-        validateNamedPathParams(namedPathParams);
-
         final Matcher pathParamMatcher = PATH_PARAM_PATTERN.matcher(baseUri);
         if (!pathParamMatcher.find()) {
             return;
@@ -442,7 +425,7 @@ class MockMvcRequestSenderImpl implements MockMvcRequestSender, MockMvcRequestAs
         do {
             final String paramName = pathParamMatcher.group(1);
             getPathParamValueFunction.apply(paramName).ifPresent(paramValue ->
-                    uriVariables.put(paramName, UriUtils.encode((String) paramValue, Charsets.UTF_8))
+                    uriVariables.put(paramName, paramValue)
             );
         } while (pathParamMatcher.find());
 
@@ -852,10 +835,10 @@ class MockMvcRequestSenderImpl implements MockMvcRequestSender, MockMvcRequestAs
 
     private HttpMethod toValidHttpMethod(String method) {
         String httpMethodAsString = notNull(trimToNull(method), "HTTP Method");
-        HttpMethod httpMethod = HttpMethod.resolve(httpMethodAsString.toUpperCase());
-        if (httpMethod == null) {
+        try {
+            return HttpMethod.valueOf(httpMethodAsString.toUpperCase());
+        } catch (IllegalArgumentException e) {
             throw new IllegalArgumentException("HTTP method '" + method + "' is not supported by MockMvc");
         }
-        return httpMethod;
     }
 }
diff --git a/pom.xml b/pom.xml
index ab7f64dc..da960a2f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,7 +16,8 @@
   ~ limitations under the License.
   -->
 
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.sonatype.oss</groupId>
@@ -26,7 +27,7 @@
     <groupId>io.rest-assured</groupId>
     <artifactId>rest-assured-parent</artifactId>
     <packaging>pom</packaging>
-    <version>5.3.3-SNAPSHOT</version>
+    <version>5.4.1-SNAPSHOT</version>
     <url>https://rest-assured.io/</url>
     <name>REST Assured Parent POM</name>
     <description>Java DSL for easy testing of REST services</description>
@@ -38,7 +39,7 @@
     <licenses>
         <license>
             <name>Apache 2.0</name>
-            <url>http://www.apache.org/licenses/LICENSE-2.0.html</url>
+            <url>https://www.apache.org/licenses/LICENSE-2.0.html</url>
             <distribution>repo</distribution>
         </license>
     </licenses>
@@ -47,7 +48,7 @@
             <name>Johan Haleby</name>
             <id>johan.haleby</id>
             <organization>Jayway</organization>
-            <organizationUrl>http://www.jayway.com</organizationUrl>
+            <organizationUrl>https://www.jayway.com</organizationUrl>
             <email>johan.haleby at gmail.com</email>
             <timezone>+1</timezone>
             <roles>
@@ -58,9 +59,9 @@
     <properties>
         <scm.branch>master</scm.branch>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <groovy.version>4.0.14</groovy.version>
+        <groovy.version>4.0.16</groovy.version>
         <groovy.range>[4.0,5.0)</groovy.range>
-        <gmaven.version>1.5</gmaven.version>
+        <gmavenplus.version>3.0.2</gmavenplus.version>
         <hamcrest.version>2.2</hamcrest.version>
         <jackson1.version>1.9.11</jackson1.version>
         <jackson2.version>2.14.3</jackson2.version>
@@ -70,6 +71,7 @@
         <maven-javadoc.version>2.9.1</maven-javadoc.version>
         <surefire.version>2.22.0</surefire.version>
         <kotlin.version>1.9.21</kotlin.version>
+        <scala.version>3.3.1</scala.version>
         <assertj-core.version>3.16.1</assertj-core.version>
         <scribe.version>2.5.3</scribe.version>
         <sundrio.version>0.93.0</sundrio.version>
@@ -77,14 +79,14 @@
         <dokka.version>1.9.10</dokka.version>
     </properties>
     <scm>
-        <url>http://github.com/rest-assured/rest-assured/tree/${scm.branch}</url>
+        <url>https://github.com/rest-assured/rest-assured/tree/${scm.branch}</url>
         <connection>scm:git:git://github.com/rest-assured/rest-assured.git</connection>
         <developerConnection>scm:git:ssh://git@github.com/rest-assured/rest-assured.git</developerConnection>
     </scm>
     <mailingLists>
         <mailingList>
             <name>rest-assured mailing-list</name>
-            <archive>http://groups.google.com/group/rest-assured/topics</archive>
+            <archive>https://groups.google.com/group/rest-assured/topics</archive>
         </mailingList>
     </mailingLists>
     <modules>
@@ -126,43 +128,6 @@
                     <artifactId>maven-bundle-plugin</artifactId>
                     <version>5.1.4</version>
                 </plugin>
-                <plugin>
-                    <groupId>org.codehaus.gmaven</groupId>
-                    <artifactId>gmaven-plugin</artifactId>
-                    <version>${gmaven.version}</version>
-                    <configuration>
-                        <providerSelection>2.0</providerSelection>
-                        <source />
-                    </configuration>
-                    <dependencies>
-                        <dependency>
-                            <groupId>org.codehaus.gmaven.runtime</groupId>
-                            <artifactId>gmaven-runtime-2.0</artifactId>
-                            <version>${gmaven.version}</version>
-                            <exclusions>
-                                <exclusion>
-                                    <groupId>org.apache.groovy</groupId>
-                                    <artifactId>groovy-all</artifactId>
-                                </exclusion>
-                            </exclusions>
-                        </dependency>
-                        <dependency>
-                            <groupId>org.apache.groovy</groupId>
-                            <artifactId>groovy</artifactId>
-                            <version>${groovy.version}</version>
-                        </dependency>
-                    </dependencies>
-                    <executions>
-                        <execution>
-                            <goals>
-                                <goal>generateStubs</goal>
-                                <goal>compile</goal>
-                                <goal>generateTestStubs</goal>
-                                <goal>testCompile</goal>
-                            </goals>
-                        </execution>
-                    </executions>
-                </plugin>
                 <plugin>
                     <groupId>org.basepom.maven</groupId>
                     <artifactId>duplicate-finder-maven-plugin</artifactId>
@@ -212,6 +177,25 @@
             </plugins>
         </pluginManagement>
         <plugins>
+            <plugin>
+                <groupId>org.codehaus.gmavenplus</groupId>
+                <artifactId>gmavenplus-plugin</artifactId>
+                <version>${gmavenplus.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>addSources</goal>
+                            <goal>addTestSources</goal>
+                            <goal>generateStubs</goal>
+                            <goal>compile</goal>
+                            <goal>generateTestStubs</goal>
+                            <goal>compileTests</goal>
+                            <goal>removeStubs</goal>
+                            <goal>removeTestStubs</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
@@ -471,6 +455,11 @@
                 <artifactId>kotlin-stdlib-jdk8</artifactId>
                 <version>${kotlin.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.scala-lang</groupId>
+                <artifactId>scala3-interfaces</artifactId>
+                <version>${scala.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.assertj</groupId>
                 <artifactId>assertj-core</artifactId>
diff --git a/rest-assured-all/pom.xml b/rest-assured-all/pom.xml
index aa84011b..4da48991 100644
--- a/rest-assured-all/pom.xml
+++ b/rest-assured-all/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>rest-assured-parent</artifactId>
         <groupId>io.rest-assured</groupId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/rest-assured-common/pom.xml b/rest-assured-common/pom.xml
index 84974a75..239d6269 100644
--- a/rest-assured-common/pom.xml
+++ b/rest-assured-common/pom.xml
@@ -20,14 +20,14 @@
     <parent>
         <groupId>io.rest-assured</groupId>
         <artifactId>rest-assured-parent</artifactId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <groupId>io.rest-assured</groupId>
     <artifactId>rest-assured-common</artifactId>
     <packaging>bundle</packaging>
-    <version>5.3.3-SNAPSHOT</version>
+    <version>5.4.1-SNAPSHOT</version>
     <name>rest-assured-common</name>
-    <url>http://maven.apache.org</url>
+    <url>https://rest-assured.io/</url>
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
@@ -36,8 +36,8 @@
     <build>
         <plugins>
             <plugin>
-                <groupId>org.codehaus.gmaven</groupId>
-                <artifactId>gmaven-plugin</artifactId>
+                <groupId>org.codehaus.gmavenplus</groupId>
+                <artifactId>gmavenplus-plugin</artifactId>
             </plugin>
             <plugin>
                 <groupId>org.apache.felix</groupId>
diff --git a/rest-assured/pom.xml b/rest-assured/pom.xml
index 7c6e6b75..05b3d9ab 100644
--- a/rest-assured/pom.xml
+++ b/rest-assured/pom.xml
@@ -22,23 +22,23 @@
     <parent>
         <groupId>io.rest-assured</groupId>
         <artifactId>rest-assured-parent</artifactId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
 
     <groupId>io.rest-assured</groupId>
     <artifactId>rest-assured</artifactId>
-    <version>5.3.3-SNAPSHOT</version>
+    <version>5.4.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
     <name>REST Assured</name>
     <description>Java DSL for easy testing of REST services</description>
-    <url>http://code.google.com/p/rest-assured</url>
+    <url>https://rest-assured.io/</url>
 
     <build>
         <plugins>
             <plugin>
-                <groupId>org.codehaus.gmaven</groupId>
-                <artifactId>gmaven-plugin</artifactId>
+                <groupId>org.codehaus.gmavenplus</groupId>
+                <artifactId>gmavenplus-plugin</artifactId>
             </plugin>
             <plugin>
                 <groupId>org.apache.felix</groupId>
@@ -126,12 +126,12 @@
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>json-path</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>xml-path</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
         </dependency>
         <!-- Optional dependencies -->
         <dependency>
diff --git a/rest-assured/src/main/groovy/io/restassured/internal/RequestSpecificationImpl.groovy b/rest-assured/src/main/groovy/io/restassured/internal/RequestSpecificationImpl.groovy
index 218cc5a3..877d1da6 100644
--- a/rest-assured/src/main/groovy/io/restassured/internal/RequestSpecificationImpl.groovy
+++ b/rest-assured/src/main/groovy/io/restassured/internal/RequestSpecificationImpl.groovy
@@ -1423,7 +1423,7 @@ class RequestSpecificationImpl implements FilterableRequestSpecification, Groovy
     }
 
     def multipartMode = httpClientConfig().httpMultipartMode()
-    // For "defaultCharset" to be taken into account we need to
+    // For "defaultCharset" to be taken into account we need to 
 
     http.encoders.putAt ct, { contentType, content ->
       RestAssuredMultiPartEntity entity = new RestAssuredMultiPartEntity(subType, charsetToUse, multipartMode, boundaryToUse)
@@ -1432,15 +1432,15 @@ class RequestSpecificationImpl implements FilterableRequestSpecification, Groovy
         def body = it.contentBody
         def controlName = it.controlName
         def headers = it.headers
-        if (headers.isEmpty()) {
-          entity.addPart(controlName, body)
-        } else {
-          def builder = FormBodyPartBuilder.create(controlName, body)
-          headers.each { name, value ->
-            builder.addField(name, value)
-          }
-          entity.addPart(builder.build())
+        def builder = FormBodyPartBuilder.create(controlName, body)
+        headers.each { name, value ->
+          builder.addField(name, value)
         }
+        def part = builder.build()
+        // note: as of org.apache.httpcomponents:httpmime:4.5.13 FormBodyPartBuilder adds `Content-Transfer-Encoding` header to
+        // each part, causing issues for sides that follow https://datatracker.ietf.org/doc/html/rfc7578#section-4.7
+        part.getHeader().removeFields("Content-Transfer-Encoding")
+        entity.addPart(part)
       }
 
       entity
@@ -1754,8 +1754,7 @@ class RequestSpecificationImpl implements FilterableRequestSpecification, Groovy
     def pathParamFiller = { String separator, boolean performEncode, String acc, String subresource ->
       def indexOfStartBracket
       def indexOfEndBracket = 0
-      while ((indexOfStartBracket = subresource.indexOf(TEMPLATE_START, indexOfEndBracket)) >= 0
-              && indexOfEndBracket >= 0) {
+      while ((indexOfStartBracket = subresource.indexOf(TEMPLATE_START, indexOfEndBracket)) >= 0) {
         indexOfEndBracket = subresource.indexOf(TEMPLATE_END, indexOfStartBracket)
         // 3 means "{" and "}" and at least one character
         if (indexOfStartBracket >= 0 && indexOfEndBracket >= 0 && subresource.length() >= 3) {
diff --git a/rest-assured/src/main/groovy/io/restassured/internal/support/Prettifier.groovy b/rest-assured/src/main/groovy/io/restassured/internal/support/Prettifier.groovy
index 3dcb47a3..d3114ad4 100644
--- a/rest-assured/src/main/groovy/io/restassured/internal/support/Prettifier.groovy
+++ b/rest-assured/src/main/groovy/io/restassured/internal/support/Prettifier.groovy
@@ -52,7 +52,19 @@ class Prettifier {
     prettify(responseAsString, parser)
   }
 
-  String prettify(String body, Parser parser) {
+  String prettify(Object content, Parser parser) {
+    if (content == null) {
+      return "";
+    }
+
+    if (content instanceof File) {
+      return prettifyBy(new String(content.readBytes()), parser)
+    }
+
+    return prettifyBy(content.toString(), parser);
+  }
+
+  private String prettifyBy(String body, Parser parser) {
     String prettifiedBody
     try {
       switch (parser) {
diff --git a/rest-assured/src/main/java/io/restassured/builder/ResponseBuilder.java b/rest-assured/src/main/java/io/restassured/builder/ResponseBuilder.java
index cf54e70f..5f8287e6 100644
--- a/rest-assured/src/main/java/io/restassured/builder/ResponseBuilder.java
+++ b/rest-assured/src/main/java/io/restassured/builder/ResponseBuilder.java
@@ -210,10 +210,6 @@ public class ResponseBuilder {
     public Response build() {
         final int statusCode = restAssuredResponse.statusCode();
 
-        if (statusCode < 100 || statusCode >= 600) {
-            throw new IllegalArgumentException(format("Status code must be greater than 100 and less than 600, was %d.", statusCode));
-        }
-
         if (StringUtils.isBlank(restAssuredResponse.statusLine())) {
             restAssuredResponse.setStatusLine(restAssuredResponse.statusCode());
         }
diff --git a/rest-assured/src/main/java/io/restassured/config/LogConfig.java b/rest-assured/src/main/java/io/restassured/config/LogConfig.java
index 3be805f0..8d45c144 100644
--- a/rest-assured/src/main/java/io/restassured/config/LogConfig.java
+++ b/rest-assured/src/main/java/io/restassured/config/LogConfig.java
@@ -145,7 +145,7 @@ public class LogConfig implements Config {
     }
 
     /**
-     * Specify a whether or not to enable pretty printing by default.
+     * Specify whether or not to enable pretty printing by default.
      *
      * @param shouldEnable <code>true</code> if pretty-printing should be enabled, <code>false</code> otherwise.
      * @return A new LogConfig instance
diff --git a/rest-assured/src/main/java/io/restassured/filter/FilterContext.java b/rest-assured/src/main/java/io/restassured/filter/FilterContext.java
index 5003512e..55aa4c20 100644
--- a/rest-assured/src/main/java/io/restassured/filter/FilterContext.java
+++ b/rest-assured/src/main/java/io/restassured/filter/FilterContext.java
@@ -27,7 +27,7 @@ import io.restassured.specification.RequestSender;
 public interface FilterContext {
 
     /**
-     * Add a value that may be used be subsequent filters.
+     * Add a value that may be used by subsequent filters.
      *
      * @param name  The name of the value
      * @param value The value itself
diff --git a/rest-assured/src/main/java/io/restassured/internal/print/RequestPrinter.java b/rest-assured/src/main/java/io/restassured/internal/print/RequestPrinter.java
index 04ec1ce7..82c00afe 100644
--- a/rest-assured/src/main/java/io/restassured/internal/print/RequestPrinter.java
+++ b/rest-assured/src/main/java/io/restassured/internal/print/RequestPrinter.java
@@ -233,7 +233,7 @@ public class RequestPrinter {
                     appendFourTabs(builder.append(SystemUtils.LINE_SEPARATOR)).append("<inputstream>");
                 } else {
                     Parser parser = Parser.fromContentType(multiPart.getMimeType());
-                    String prettified = new Prettifier().prettify(multiPart.getContent().toString(), parser);
+                    String prettified = new Prettifier().prettify(multiPart.getContent(), parser);
                     String prettifiedIndented = StringUtils.replace(prettified, SystemUtils.LINE_SEPARATOR, SystemUtils.LINE_SEPARATOR + TAB + TAB + TAB + TAB);
                     appendFourTabs(builder.append(SystemUtils.LINE_SEPARATOR)).append(prettifiedIndented);
                 }
diff --git a/rest-assured/src/main/java/io/restassured/specification/AuthenticationSpecification.java b/rest-assured/src/main/java/io/restassured/specification/AuthenticationSpecification.java
index 48b4c926..70bc13e1 100644
--- a/rest-assured/src/main/java/io/restassured/specification/AuthenticationSpecification.java
+++ b/rest-assured/src/main/java/io/restassured/specification/AuthenticationSpecification.java
@@ -99,7 +99,7 @@ public interface AuthenticationSpecification {
     RequestSpecification certificate(String certURL, String password, CertificateAuthSettings certificateAuthSettings);
 
     /**
-     * OAuth2 sign the request. Note that this currently does not wait for a WWW-Authenticate challenge before sending the the OAuth header
+     * OAuth2 sign the request. Note that this currently does not wait for a WWW-Authenticate challenge before sending the OAuth header
      * (so currently it's the same as preemptive oauth2 authentication. The reason why it's located here is to be backward compatible).
      * This assumes you've already generated an accessToken for the site you're targeting. The access token will be put in a header.
      *
@@ -109,7 +109,7 @@ public interface AuthenticationSpecification {
     RequestSpecification oauth2(String accessToken);
 
     /**
-     * OAuth2 sign the request. Note that this currently does not wait for a WWW-Authenticate challenge before sending the the OAuth header.
+     * OAuth2 sign the request. Note that this currently does not wait for a WWW-Authenticate challenge before sending the OAuth header.
      * This assumes you've already generated an accessToken for the site you're targeting.
      *
      * @param accessToken The access token
@@ -120,7 +120,7 @@ public interface AuthenticationSpecification {
 
     /**
      * Excerpt from the HttpBuilder docs:<br>
-     * OAuth sign the request. Note that this currently does not wait for a WWW-Authenticate challenge before sending the the OAuth header.
+     * OAuth sign the request. Note that this currently does not wait for a WWW-Authenticate challenge before sending the OAuth header.
      * All requests to all domains will be signed for this instance.
      * This assumes you've already generated an accessToken and secretToken for the site you're targeting.
      * For more information on how to achieve this, see the <a href='https://github.com/fernandezpablo85/scribe-java/wiki/Getting-Started'>Scribe documentation</a>.</p>
@@ -135,7 +135,7 @@ public interface AuthenticationSpecification {
 
     /**
      * Excerpt from the HttpBuilder docs:<br>
-     * OAuth sign the request. Note that this currently does not wait for a WWW-Authenticate challenge before sending the the OAuth header.
+     * OAuth sign the request. Note that this currently does not wait for a WWW-Authenticate challenge before sending the OAuth header.
      * All requests to all domains will be signed for this instance.
      * This assumes you've already generated an accessToken and secretToken for the site you're targeting.
      * For more information on how to achieve this, see the <a href='https://github.com/fernandezpablo85/scribe-java/wiki/Getting-Started'>Scribe documentation</a>.</p>
diff --git a/rest-assured/src/main/java/io/restassured/specification/FilterableRequestSpecification.java b/rest-assured/src/main/java/io/restassured/specification/FilterableRequestSpecification.java
index 9d237d1f..9d4b21ae 100644
--- a/rest-assured/src/main/java/io/restassured/specification/FilterableRequestSpecification.java
+++ b/rest-assured/src/main/java/io/restassured/specification/FilterableRequestSpecification.java
@@ -60,7 +60,7 @@ public interface FilterableRequestSpecification extends QueryableRequestSpecific
     FilterableRequestSpecification removePathParam(String parameterName);
 
     /**
-     * Remove a named path parameter from the request. It will remove both named and unnamed path parameters.
+     * Remove a named path parameter from the request.
      *
      * @param parameterName The parameter key
      * @return The {@link FilterableRequestSpecification} without the parameter
@@ -124,7 +124,7 @@ public interface FilterableRequestSpecification extends QueryableRequestSpecific
     FilterableRequestSpecification removeCookie(Cookie cookie);
 
     /**
-     * Replace a header with the new value. If the headerName doesn't exist the will be added.
+     * Replace a header with the new value. If the headerName doesn't exist it will be added.
      *
      * @param headerName The header name to replace
      * @return The {@link FilterableRequestSpecification} with the replaced header
diff --git a/rest-assured/src/main/java/io/restassured/specification/RequestSpecification.java b/rest-assured/src/main/java/io/restassured/specification/RequestSpecification.java
index 830e5493..3ed8eb83 100644
--- a/rest-assured/src/main/java/io/restassured/specification/RequestSpecification.java
+++ b/rest-assured/src/main/java/io/restassured/specification/RequestSpecification.java
@@ -1102,8 +1102,8 @@ public interface RequestSpecification extends RequestSender {
      * <pre>
      *     given().
      *              csrf("/users").
-     *              formParm("firstName", "John")
-     *              formParm("lastName", "Doe")
+     *              formParm("firstName", "John").
+     *              formParm("lastName", "Doe").
      *     when().
      *              post("/users").
      *     then().
diff --git a/rest-assured/src/main/java/io/restassured/specification/ResponseSpecification.java b/rest-assured/src/main/java/io/restassured/specification/ResponseSpecification.java
index 58e43dec..6c41566e 100644
--- a/rest-assured/src/main/java/io/restassured/specification/ResponseSpecification.java
+++ b/rest-assured/src/main/java/io/restassured/specification/ResponseSpecification.java
@@ -542,7 +542,7 @@ public interface ResponseSpecification {
      *          body("w.something2", is(..)).
      * </pre>
      * <p/>
-     * This is the same as calling <code>rootPath("")</code> but less verbose and the it communicates intent better.
+     * This is the same as calling <code>rootPath("")</code> but less verbose and it communicates intent better.
      *
      * @see #rootPath(String)
      */
@@ -658,7 +658,7 @@ public interface ResponseSpecification {
      *          body("lastName", is(..)).
      * </pre>
      * <p/>
-     * you can use a append root and do:
+     * you can use a detach root and do:
      * <pre>
      * when().
      *          get(..);
diff --git a/xml-path/pom.xml b/xml-path/pom.xml
index a809d0ed..7d179a7f 100644
--- a/xml-path/pom.xml
+++ b/xml-path/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>rest-assured-parent</artifactId>
         <groupId>io.rest-assured</groupId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -29,8 +29,8 @@
     <build>
         <plugins>
             <plugin>
-                <groupId>org.codehaus.gmaven</groupId>
-                <artifactId>gmaven-plugin</artifactId>
+                <groupId>org.codehaus.gmavenplus</groupId>
+                <artifactId>gmavenplus-plugin</artifactId>
             </plugin>
             <plugin>
                 <groupId>org.apache.felix</groupId>
@@ -70,7 +70,7 @@
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>rest-assured-common</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>


Test patch:
diff --git a/dist/dist-spring-web-test-client/pom.xml b/dist/dist-spring-web-test-client/pom.xml
index 8faaf142..8f2b3a4d 100644
--- a/dist/dist-spring-web-test-client/pom.xml
+++ b/dist/dist-spring-web-test-client/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>dist</artifactId>
         <groupId>io.rest-assured</groupId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/examples/rest-assured-itest-java-osgi/pom.xml b/examples/rest-assured-itest-java-osgi/pom.xml
index d3222207..d1f5493a 100644
--- a/examples/rest-assured-itest-java-osgi/pom.xml
+++ b/examples/rest-assured-itest-java-osgi/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <groupId>io.rest-assured.examples</groupId>
         <artifactId>example-parent</artifactId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/examples/rest-assured-itest-java/pom.xml b/examples/rest-assured-itest-java/pom.xml
index adbb5d77..86baa2df 100644
--- a/examples/rest-assured-itest-java/pom.xml
+++ b/examples/rest-assured-itest-java/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <groupId>io.rest-assured.examples</groupId>
         <artifactId>example-parent</artifactId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -50,23 +50,23 @@
         <dependency>
             <groupId>io.rest-assured.examples</groupId>
             <artifactId>scalatra-webapp</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
             <type>war</type>
         </dependency>
         <dependency>
             <groupId>io.rest-assured.examples</groupId>
             <artifactId>scalatra-example</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>rest-assured</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>json-schema-validator</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>org.eclipse.jetty</groupId>
diff --git a/modules/scala-extensions/src/test/scala/io/restassured/module/scala/extensions/RestAssuredScalaExtensionsTest.scala b/modules/scala-extensions/src/test/scala/io/restassured/module/scala/extensions/RestAssuredScalaExtensionsTest.scala
new file mode 100644
index 00000000..e49b6a22
--- /dev/null
+++ b/modules/scala-extensions/src/test/scala/io/restassured/module/scala/extensions/RestAssuredScalaExtensionsTest.scala
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2024 the original author or 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
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.restassured.module.scala.extensions
+
+import io.restassured.RestAssured
+import io.restassured.builder.ResponseBuilder
+import io.restassured.filter.Filter
+import io.restassured.http.ContentType.JSON
+import org.assertj.core.api.Assertions.assertThat
+import org.hamcrest.Matchers.*
+import org.junit.Before
+import org.junit.Test
+
+class RestAssuredScalaExtensionsTest:
+
+  @Before
+  def `rest assured is configured`: Unit =
+    RestAssured.filters { (_, _, _) =>
+      new ResponseBuilder()
+        .setStatusCode(200)
+        .setContentType(JSON)
+        .setBody("""{ "message" : "Hello World"}""")
+        .build()
+    }
+
+  @Test
+  def `rest assured is reset after each test`: Unit =
+    RestAssured.reset()
+
+  @Test
+  def `basic rest assured scala extensions are compilable`: Unit =
+    Given(req =>
+      req.port(7000)
+      req.header("Header", "Header")
+      req.body("hello")
+    )
+      .When(
+        _.put("/the/path")
+      )
+      .Then(res =>
+        res.statusCode(200)
+        res.body("message", equalTo("Hello World"))
+      )
+
+  @Test
+  def `extraction with rest assured scala extensions`: Unit =
+    val message: String = Given(req =>
+      req.port(7000)
+      req.header("Header", "Header")
+      req.body("hello")
+    )
+      .When(
+        _.put("/the/path")
+      )
+      .Extract(
+        _.path("message")
+      )
+    assertThat(message).isEqualTo("Hello World")
+
+  @Test
+  def `validation with rest assured scala extensions using ThenAssert returning Unit`: Unit =
+    val result = Given(req =>
+      req.port(7000)
+      req.header("Header", "Header")
+      req.body("hello")
+    )
+      .When(
+        _.put("/the/path")
+      )
+      .ThenAssert(res =>
+        res.statusCode(200)
+        res.body("message", equalTo("Hello World"))
+      )
+    assertThat(result).isEqualTo(())
+
+  @Test
+  def `extraction after 'then', when path is not used in 'Then',  with rest assured scala extensions`: Unit =
+    val message: String = Given(req =>
+      req.port(7000)
+      req.header("Header", "Header")
+      req.body("hello")
+      req.filter((_, _, _) =>
+        new ResponseBuilder()
+          .setStatusCode(200)
+          .setContentType(JSON)
+          .setBody("""{ "message" : "Hello World"}""")
+          .build()
+      )
+    )
+      .When(
+        _.put("/the/path")
+      )
+      .Then(
+        _.statusCode(200)
+      )
+      .Extract(
+        _.path("message")
+      )
+    assertThat(message).isEqualTo("Hello World")
+
+  @Test
+  def `extraction after 'then', when path is used in 'Then',  with rest assured scala extensions`: Unit =
+    val message: String = Given(req =>
+      req.port(7000)
+      req.header("Header", "Header")
+      req.body("hello")
+      req.filter((_, _, _) =>
+        new ResponseBuilder()
+          .setStatusCode(200)
+          .setContentType(JSON)
+          .setBody("""{ "message" : "Hello World"}""")
+          .build()
+      )
+    )
+      .When(
+        _.put("/the/path")
+      )
+      .Then(res =>
+        res.statusCode(200)
+        res.body("message", not(emptyOrNullString()))
+      )
+      .Extract(
+        _.path("message")
+      )
+    assertThat(message).isEqualTo("Hello World")
+
+  @Test
+  def `all expectations error messages are included in the error message`: Unit =
+    try {
+      Given(req =>
+        req.port(7000)
+        req.header("Header", "Header")
+        req.body("hello")
+      )
+        .When(
+          _.put("/the/path")
+        )
+        .Then(res =>
+          res.statusCode(400)
+          res.body("message", equalTo("Another World"))
+          res.body("message", equalTo("Brave new world"))
+        )
+    } catch {
+      case e: AssertionError =>
+        assertThat(e).hasMessage("""3 expectations failed.
+                                   |Expected status code <400> but was <200>.
+                                   |
+                                   |JSON path message doesn't match.
+                                   |Expected: Another World
+                                   |  Actual: Hello World
+                                   |
+                                   |JSON path message doesn't match.
+                                   |Expected: Brave new world
+                                   |  Actual: Hello World
+                                   |""".stripMargin)
+    }
diff --git a/modules/spring-mock-mvc/src/test/java/io/restassured/module/mockmvc/GetTest.java b/modules/spring-mock-mvc/src/test/java/io/restassured/module/mockmvc/GetTest.java
index ee73e32a..01dc6544 100644
--- a/modules/spring-mock-mvc/src/test/java/io/restassured/module/mockmvc/GetTest.java
+++ b/modules/spring-mock-mvc/src/test/java/io/restassured/module/mockmvc/GetTest.java
@@ -28,9 +28,9 @@ public class GetTest {
         RestAssuredMockMvc.given().
                 standaloneSetup(new GreetingController()).
         when().
-                get("/greeting?name={name}", "Johan").
+                get("/greeting?name={name}", "Johan@test.com").
         then().
                 body("id", equalTo(1)).
-                body("content", equalTo("Hello, Johan!"));
+                body("content", equalTo("Hello, Johan@test.com!"));
     }
 }
diff --git a/modules/spring-mock-mvc/src/test/java/io/restassured/module/mockmvc/MockMvcMultipartTest.java b/modules/spring-mock-mvc/src/test/java/io/restassured/module/mockmvc/MockMvcMultipartTest.java
index c46afdb3..834b707a 100644
--- a/modules/spring-mock-mvc/src/test/java/io/restassured/module/mockmvc/MockMvcMultipartTest.java
+++ b/modules/spring-mock-mvc/src/test/java/io/restassured/module/mockmvc/MockMvcMultipartTest.java
@@ -18,6 +18,10 @@ package io.restassured.module.mockmvc;
 
 import io.restassured.module.mockmvc.http.MultipartController;
 import org.junit.Test;
+import org.springframework.http.MediaType;
+import org.springframework.util.ResourceUtils;
+
+import java.io.File;
 
 import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.hamcrest.Matchers.equalTo;
@@ -41,4 +45,43 @@ public class MockMvcMultipartTest {
                 .body("name", equalTo("file"));
     }
 
+
+    @Test
+    public void can_use_multipart_with_jsonFile() throws Exception{
+        File xml = ResourceUtils.getFile("classpath:multipart.xml");
+
+        RestAssuredMockMvc.given()
+                .standaloneSetup(new MultipartController())
+                .contentType(MediaType.MULTIPART_FORM_DATA)
+                .multiPart("file", xml, MediaType.APPLICATION_XML_VALUE)
+                .log().all()
+                .when()
+                .post("/files/{type}", (Object[]) "type".split("\\|"))
+                .then()
+                .log().all()
+                .time(lessThan(3L), SECONDS)
+                .expect(status().is2xxSuccessful())
+                .body("type", equalTo("type"))
+                .body("name", equalTo("file"));
+    }
+
+    @Test
+    public void can_use_multipart_with_xmlJson() throws Exception{
+        File json = ResourceUtils.getFile("classpath:multipart.json");
+
+        RestAssuredMockMvc.given()
+                .standaloneSetup(new MultipartController())
+                .contentType(MediaType.MULTIPART_FORM_DATA)
+                .multiPart("file", json, MediaType.APPLICATION_JSON_VALUE)
+                .log().all()
+                .when()
+                .post("/files/{type}", (Object[]) "type".split("\\|"))
+                .then()
+                .log().all()
+                .time(lessThan(3L), SECONDS)
+                .expect(status().is2xxSuccessful())
+                .body("type", equalTo("type"))
+                .body("name", equalTo("file"));
+    }
+
 }
diff --git a/modules/spring-mock-mvc/src/test/resources/multipart.json b/modules/spring-mock-mvc/src/test/resources/multipart.json
new file mode 100644
index 00000000..28bb92f2
--- /dev/null
+++ b/modules/spring-mock-mvc/src/test/resources/multipart.json
@@ -0,0 +1,14 @@
+{
+  "catalog": {
+    "book": [
+      {
+        "id": "bk101",
+        "author": "Gambardella, Matthew",
+        "title": "XML Developer's Guide",
+        "genre": "Computer",
+        "price": 44.95,
+        "publish_date": "2000-10-01"
+      }
+    ]
+  }
+}
diff --git a/modules/spring-mock-mvc/src/test/resources/multipart.xml b/modules/spring-mock-mvc/src/test/resources/multipart.xml
new file mode 100644
index 00000000..3129b306
--- /dev/null
+++ b/modules/spring-mock-mvc/src/test/resources/multipart.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<catalog>
+    <book id="bk101">
+        <author>Gambardella, Matthew</author>
+        <title>XML Developer's Guide</title>
+        <genre>Computer</genre>
+        <price>44.95</price>
+        <publish_date>2000-10-01</publish_date>
+    </book>
+</catalog>
diff --git a/modules/spring-web-test-client-kotlin-extensions/pom.xml b/modules/spring-web-test-client-kotlin-extensions/pom.xml
index f74db97c..eaa6d8b4 100644
--- a/modules/spring-web-test-client-kotlin-extensions/pom.xml
+++ b/modules/spring-web-test-client-kotlin-extensions/pom.xml
@@ -20,14 +20,15 @@
     <parent>
         <groupId>io.rest-assured</groupId>
         <artifactId>modules</artifactId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <artifactId>spring-web-test-client-kotlin-extensions</artifactId>
-    <version>5.3.3-SNAPSHOT</version>
+    <version>5.4.1-SNAPSHOT</version>
     <name>spring-web-test-client-kotlin-extensions</name>
-    <url>http://maven.apache.org</url>
+    <url>https://rest-assured.io/</url>
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <spring.version>5.1.13.RELEASE</spring.version>
     </properties>
 
     <dependencies>
@@ -38,7 +39,7 @@
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>spring-web-test-client</artifactId>
-            <version>5.3.3-SNAPSHOT</version>
+            <version>5.4.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>javax.servlet</groupId>
@@ -52,6 +53,12 @@
             <version>9.1.0</version>
             <scope>optional</scope>
         </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-webflux</artifactId>
+            <version>${spring.version}</version>
+            <optional>true</optional>
+        </dependency>
         <dependency>
             <groupId>com.fasterxml.jackson.module</groupId>
             <artifactId>jackson-module-kotlin</artifactId>
@@ -70,6 +77,12 @@
             <artifactId>assertj-core</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-test</artifactId>
+            <version>${spring.version}</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <profiles>
diff --git a/modules/spring-web-test-client/pom.xml b/modules/spring-web-test-client/pom.xml
index 2d345230..a205a8f5 100644
--- a/modules/spring-web-test-client/pom.xml
+++ b/modules/spring-web-test-client/pom.xml
@@ -20,12 +20,12 @@
     <parent>
         <groupId>io.rest-assured</groupId>
         <artifactId>modules</artifactId>
-        <version>5.3.3-SNAPSHOT</version>
+        <version>5.4.1-SNAPSHOT</version>
     </parent>
     <artifactId>spring-web-test-client</artifactId>
-    <version>5.3.3-SNAPSHOT</version>
+    <version>5.4.1-SNAPSHOT</version>
     <name>spring-web-test-client</name>
-    <url>http://maven.apache.org</url>
+    <url>https://rest-assured.io/</url>
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <spring.version>5.1.13.RELEASE</spring.version>
@@ -158,4 +158,4 @@
             <scope>test</scope>
         </dependency>
     </dependencies>
-</project>
\ No newline at end of file
+</project>
diff --git a/modules/spring-web-test-client/src/main/java/io/restassured/module/webtestclient/internal/WebTestClientRequestSenderImpl.java b/modules/spring-web-test-client/src/main/java/io/restassured/module/webtestclient/internal/WebTestClientRequestSenderImpl.java
index 2ed1f84b..b9c3bc1b 100644
--- a/modules/spring-web-test-client/src/main/java/io/restassured/module/webtestclient/internal/WebTestClientRequestSenderImpl.java
+++ b/modules/spring-web-test-client/src/main/java/io/restassured/module/webtestclient/internal/WebTestClientRequestSenderImpl.java
@@ -145,11 +145,11 @@ public class WebTestClientRequestSenderImpl implements WebTestClientRequestSende
 
 	private HttpMethod toValidHttpMethod(String method) {
 		String httpMethodAsString = notNull(trimToNull(method), "HTTP Method");
-		HttpMethod httpMethod = HttpMethod.resolve(httpMethodAsString.toUpperCase());
-		if (httpMethod == null) {
-			throw new IllegalArgumentException("HTTP method '" + method + "' is not supported by WebTestClient");
+		try {
+			return HttpMethod.valueOf(httpMethodAsString.toUpperCase());
+		} catch (IllegalArgumentException e) {
+			throw new IllegalArgumentException(String.format("HTTP method '%s' is not supported by WebTestClient", method));
 		}
-		return httpMethod;
 	}
 
 	@Override
@@ -503,20 +503,6 @@ public class WebTestClientRequestSenderImpl implements WebTestClientRequestSende
 		return uriContainerBuilder.uri(uriWithoutPathParams).build();
 	}
 
-	private void validateUnnamedPathParams(final Object[] unnamedPathParams) {
-		Arrays.stream(unnamedPathParams).filter(param -> !(param instanceof String))
-				.findAny().ifPresent(param -> {
-			throw new IllegalArgumentException("Only Strings allowed in path parameters.");
-		});
-	}
-
-	private void validateNamedPathParams(final Map<String, Object> namedPathParams) {
-		namedPathParams.entrySet().stream().filter(e -> !(e.getValue() instanceof String))
-				.findAny().ifPresent(param -> {
-					throw new IllegalArgumentException("Only Strings allowed in path parameters.");
-				});
-	}
-
 	private void verifyNoBodyAndMultipartTogether() {
 		if (requestBody != null && !multiParts.isEmpty()) {
 			throw new IllegalStateException("You cannot specify a request body and a multi-part body in the same request." +
@@ -581,9 +567,6 @@ public class WebTestClientRequestSenderImpl implements WebTestClientRequestSende
 			final String baseUri,
 			final Object[] unnamedPathParams
 	) {
-		validateUnnamedPathParams(unnamedPathParams);
-		validateNamedPathParams(namedPathParams);
-
 		final Matcher pathParamMatcher = PATH_PARAM_PATTERN.matcher(baseUri);
 		if (!pathParamMatcher.find()) {
 			return;
diff --git a/rest-assured/src/test/groovy/io/restassured/SpecificationMergerTest.groovy b/rest-assured/src/test/groovy/io/restassured/SpecificationMergerTest.groovy
index c59be769..dff8a6b8 100644
--- a/rest-assured/src/test/groovy/io/restassured/SpecificationMergerTest.groovy
+++ b/rest-assured/src/test/groovy/io/restassured/SpecificationMergerTest.groovy
@@ -92,7 +92,7 @@ class SpecificationMergerTest {
 
     SpecificationMerger.merge(merge, with)
 
-    assertEquals 1, merge.filters.size
+    assertEquals 1, merge.filters.size()
   }
 
   @Test
@@ -152,7 +152,7 @@ class SpecificationMergerTest {
 
     SpecificationMerger.merge(merge, with)
 
-    assertTrue merge.multiParts.size == 2
+    assertTrue merge.multiParts.size() == 2
   }
 
 
diff --git a/rest-assured/src/test/java/io/restassured/internal/support/PrettifierTest.java b/rest-assured/src/test/java/io/restassured/internal/support/PrettifierTest.java
new file mode 100644
index 00000000..aa7408d2
--- /dev/null
+++ b/rest-assured/src/test/java/io/restassured/internal/support/PrettifierTest.java
@@ -0,0 +1,106 @@
+package io.restassured.internal.support;
+
+import io.restassured.parsing.Parser;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class PrettifierTest {
+
+    private File jsonFile;
+    private File xmlFile;
+    private final String resultJson = "{\n" +
+            "    \"catalog\": {\n" +
+            "        \"book\": [\n" +
+            "            {\n" +
+            "                \"id\": \"bk101\",\n" +
+            "                \"author\": \"Gambardella, Matthew\",\n" +
+            "                \"title\": \"XML Developer's Guide\",\n" +
+            "                \"genre\": \"Computer\",\n" +
+            "                \"price\": 44.95,\n" +
+            "                \"publish_date\": \"2000-10-01\"\n" +
+            "            }\n" +
+            "        ]\n" +
+            "    }\n" +
+            "}";
+
+    private final String resultXml = "<catalog>\n" +
+            "  <book id=\"bk101\">\n" +
+            "    <author>Gambardella, Matthew</author>\n" +
+            "    <title>XML Developer's Guide</title>\n" +
+            "    <genre>Computer</genre>\n" +
+            "    <price>44.95</price>\n" +
+            "    <publish_date>2000-10-01</publish_date>\n" +
+            "  </book>\n" +
+            "</catalog>";
+
+
+    @Before
+    public void
+    setup() throws IOException {
+        jsonFile = getFile("multipart.json");
+        xmlFile = getFile("multipart.xml");
+    }
+
+    @Test
+    public void
+    jsonPrettify() {
+        String prettify = new Prettifier().prettify(jsonFile, Parser.JSON);
+
+        assertEquals(prettify, resultJson);
+    }
+
+    @Test
+    public void
+    xml_prettify() {
+        String prettify = new Prettifier().prettify(xmlFile, Parser.XML);
+
+        assertEquals(prettify, resultXml);
+    }
+
+    @Test
+    public void
+    json_prettify() {
+        String prettify = new Prettifier().prettify(jsonFile, Parser.JSON);
+
+        assertEquals(prettify, resultJson);
+    }
+
+    @Test
+    public void
+    empty_data() {
+        String prettify = new Prettifier().prettify("", Parser.XML);
+
+        assertEquals(prettify, "");
+    }
+
+    @Test
+    public void
+    json_string_data() throws IOException {
+        String jsonData = new String(Files.readAllBytes(Paths.get(jsonFile.getPath())));
+
+        String prettify = new Prettifier().prettify(jsonData, Parser.JSON);
+
+        assertEquals(prettify, resultJson);
+    }
+
+    @Test
+    public void
+    xml_string_data() throws IOException {
+        String xmlData = new String(Files.readAllBytes(Paths.get(xmlFile.getPath())));
+
+        String prettify = new Prettifier().prettify(xmlData, Parser.XML);
+
+        assertEquals(prettify, resultXml);
+    }
+
+    private File getFile(String path) throws IOException {
+        return new File(getClass().getClassLoader().getResource(path).getFile());
+    }
+}
diff --git a/rest-assured/src/test/resources/multipart.json b/rest-assured/src/test/resources/multipart.json
new file mode 100644
index 00000000..28bb92f2
--- /dev/null
+++ b/rest-assured/src/test/resources/multipart.json
@@ -0,0 +1,14 @@
+{
+  "catalog": {
+    "book": [
+      {
+        "id": "bk101",
+        "author": "Gambardella, Matthew",
+        "title": "XML Developer's Guide",
+        "genre": "Computer",
+        "price": 44.95,
+        "publish_date": "2000-10-01"
+      }
+    ]
+  }
+}
diff --git a/rest-assured/src/test/resources/multipart.xml b/rest-assured/src/test/resources/multipart.xml
new file mode 100644
index 00000000..3129b306
--- /dev/null
+++ b/rest-assured/src/test/resources/multipart.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<catalog>
+    <book id="bk101">
+        <author>Gambardella, Matthew</author>
+        <title>XML Developer's Guide</title>
+        <genre>Computer</genre>
+        <price>44.95</price>
+        <publish_date>2000-10-01</publish_date>
+    </book>
+</catalog>