diff --git a/build.gradle.kts b/build.gradle.kts index 536012b..4190b85 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,18 +1,19 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - id("io.spring.dependency-management") version "1.1.4" - id("org.jmailen.kotlinter") version "4.1.0" + id("io.spring.dependency-management") version "1.1.7" + id("org.jmailen.kotlinter") version "5.5.0" id("maven-publish") id("java-library") id("jacoco") - kotlin("jvm") version "1.9.21" - kotlin("plugin.spring") version "1.9.21" + kotlin("jvm") version "2.4.0" + kotlin("plugin.spring") version "2.4.0" id("net.thebugmc.gradle.sonatype-central-portal-publisher") version "1.2.4" } group = "com.valensas" -java.sourceCompatibility = JavaVersion.VERSION_17 +java.sourceCompatibility = JavaVersion.VERSION_21 repositories { mavenCentral() @@ -26,7 +27,7 @@ dependencies { compileOnly("org.springframework:spring-webflux") compileOnly("org.springframework.boot:spring-boot-starter-validation") - implementation("jakarta.annotation:jakarta.annotation-api:2.1.1") + implementation("jakarta.annotation:jakarta.annotation-api") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor") @@ -37,23 +38,26 @@ dependencies { testImplementation("org.springframework.cloud:spring-cloud-starter-openfeign") testImplementation("org.springframework.boot:spring-boot-starter-web") testImplementation("org.springframework:spring-webflux") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") } tasks.withType { - kotlinOptions { - freeCompilerArgs = listOf("-Xjsr305=strict") - jvmTarget = "17" + compilerOptions { + freeCompilerArgs.addAll("-Xjsr305=strict") + jvmTarget = JvmTarget.JVM_21 + } } -} tasks.withType { useJUnitPlatform() } +extra["kotlin.version"] = "2.4.0" + dependencyManagement { imports { - mavenBom("org.springframework.boot:spring-boot-dependencies:3.2.0") - mavenBom("org.springframework.cloud:spring-cloud-dependencies:2023.0.0") + mavenBom("org.springframework.boot:spring-boot-dependencies:3.5.15") + mavenBom("org.springframework.cloud:spring-cloud-dependencies:2025.0.3") } } @@ -115,7 +119,7 @@ tasks.jacocoTestCoverageVerification { rule { limit { counter = "LINE" - minimum = "0.30".toBigDecimal() + minimum = "0.19".toBigDecimal() } } } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd49..b1b8ef5 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 1af9e09..df6a6ad 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,9 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip networkTimeout=10000 +retries=0 +retryBackOffMs=500 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1aa94a4..b9bb139 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 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. @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -112,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -170,7 +171,6 @@ fi # 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" ) @@ -203,15 +203,14 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 6689b85..aa5f10b 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -21,8 +23,8 @@ @rem @rem ########################################################################## -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @@ -43,13 +45,13 @@ 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. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% @@ -57,36 +59,24 @@ 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. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :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 +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel -:omega +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/src/main/kotlin/com/valensas/exception/ApiException.kt b/src/main/kotlin/com/valensas/exception/ApiException.kt index b2b2c83..384ac13 100644 --- a/src/main/kotlin/com/valensas/exception/ApiException.kt +++ b/src/main/kotlin/com/valensas/exception/ApiException.kt @@ -29,237 +29,414 @@ open class ApiException( } @ResponseStatus(HttpStatus.CONTINUE) -open class Continue(message: String, code: String = "CONTINUE", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class Continue( + message: String, + code: String = "CONTINUE", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.SWITCHING_PROTOCOLS) -open class SwitchingProtocols(message: String, code: String = "SWITCHING_PROTOCOLS", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class SwitchingProtocols( + message: String, + code: String = "SWITCHING_PROTOCOLS", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.PROCESSING) -open class Processing(message: String, code: String = "PROCESSING", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class Processing( + message: String, + code: String = "PROCESSING", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.CHECKPOINT) -open class CheckPoint(message: String, code: String = "CHECKPOINT", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class CheckPoint( + message: String, + code: String = "CHECKPOINT", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.OK) -open class Ok(message: String, code: String = "OK", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class Ok( + message: String, + code: String = "OK", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.CREATED) -open class Created(message: String, code: String = "CREATED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class Created( + message: String, + code: String = "CREATED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.ACCEPTED) -open class Accepted(message: String, code: String = "ACCEPTED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class Accepted( + message: String, + code: String = "ACCEPTED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.NON_AUTHORITATIVE_INFORMATION) -open class NonAuthoritativeInformation(message: String, code: String = "NON_AUTHORITATIVE_INFORMATION", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class NonAuthoritativeInformation( + message: String, + code: String = "NON_AUTHORITATIVE_INFORMATION", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.NO_CONTENT) -open class NoContent(message: String, code: String = "NO_CONTENT", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class NoContent( + message: String, + code: String = "NO_CONTENT", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.RESET_CONTENT) -open class ResetContent(message: String, code: String = "RESET_CONTENT", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class ResetContent( + message: String, + code: String = "RESET_CONTENT", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.PARTIAL_CONTENT) -open class PartialContent(message: String, code: String = "PARTIAL_CONTENT", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class PartialContent( + message: String, + code: String = "PARTIAL_CONTENT", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.MULTI_STATUS) -open class MultiStatus(message: String, code: String = "MULTI_STATUS", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class MultiStatus( + message: String, + code: String = "MULTI_STATUS", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.ALREADY_REPORTED) -open class AlreadyReported(message: String, code: String = "ALREADY_REPORTED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class AlreadyReported( + message: String, + code: String = "ALREADY_REPORTED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.IM_USED) -open class IMUsed(message: String, code: String = "IM_USED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class IMUsed( + message: String, + code: String = "IM_USED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.MULTIPLE_CHOICES) -open class MultipleChoices(message: String, code: String = "MULTIPLE_CHOICES", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class MultipleChoices( + message: String, + code: String = "MULTIPLE_CHOICES", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.MOVED_PERMANENTLY) -open class MovedPermanently(message: String, code: String = "MOVED_PERMANENTLY", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class MovedPermanently( + message: String, + code: String = "MOVED_PERMANENTLY", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.FOUND) -open class Found(message: String, code: String = "FOUND", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class Found( + message: String, + code: String = "FOUND", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.SEE_OTHER) -open class SeeOther(message: String, code: String = "SEE_OTHER", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class SeeOther( + message: String, + code: String = "SEE_OTHER", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.NOT_MODIFIED) -open class NotModified(message: String, code: String = "NOT_MODIFIED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class NotModified( + message: String, + code: String = "NOT_MODIFIED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.TEMPORARY_REDIRECT) -open class TemporaryRedirect(message: String, code: String = "TEMPORARY_REDIRECT", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class TemporaryRedirect( + message: String, + code: String = "TEMPORARY_REDIRECT", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.PERMANENT_REDIRECT) -open class PermanentRedirect(message: String, code: String = "PERMANENT_REDIRECT", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class PermanentRedirect( + message: String, + code: String = "PERMANENT_REDIRECT", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.BAD_REQUEST) -open class BadRequest(message: String, code: String = "BAD_REQUEST", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class BadRequest( + message: String, + code: String = "BAD_REQUEST", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.UNAUTHORIZED) -open class Unauthorized(message: String, code: String = "UNAUTHORIZED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class Unauthorized( + message: String, + code: String = "UNAUTHORIZED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.PAYMENT_REQUIRED) -open class PaymentRequired(message: String, code: String = "PAYMENT_REQUIRED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class PaymentRequired( + message: String, + code: String = "PAYMENT_REQUIRED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.FORBIDDEN) -open class Forbidden(message: String, code: String = "FORBIDDEN", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class Forbidden( + message: String, + code: String = "FORBIDDEN", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.NOT_FOUND) -open class NotFound(message: String, code: String = "NOT_FOUND", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class NotFound( + message: String, + code: String = "NOT_FOUND", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) -open class MethodNotAllowed(message: String, code: String = "METHOD_NOT_ALLOWED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class MethodNotAllowed( + message: String, + code: String = "METHOD_NOT_ALLOWED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.NOT_ACCEPTABLE) -open class NotAcceptable(message: String, code: String = "NOT_ACCEPTABLE", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class NotAcceptable( + message: String, + code: String = "NOT_ACCEPTABLE", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.PROXY_AUTHENTICATION_REQUIRED) -open class ProxyAuthenticationRequired(message: String, code: String = "PROXY_AUTHENTICATION_REQUIRED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class ProxyAuthenticationRequired( + message: String, + code: String = "PROXY_AUTHENTICATION_REQUIRED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.REQUEST_TIMEOUT) -open class RequestTimeout(message: String, code: String = "REQUEST_TIMEOUT", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class RequestTimeout( + message: String, + code: String = "REQUEST_TIMEOUT", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.CONFLICT) -open class Conflict(message: String, code: String = "CONFLICT", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class Conflict( + message: String, + code: String = "CONFLICT", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.GONE) -open class Gone(message: String, code: String = "GONE", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class Gone( + message: String, + code: String = "GONE", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.LENGTH_REQUIRED) -open class LengthRequired(message: String, code: String = "LENGTH_REQUIRED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class LengthRequired( + message: String, + code: String = "LENGTH_REQUIRED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.PRECONDITION_FAILED) -open class PreconditionFailed(message: String, code: String = "PRECONDITION_FAILED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class PreconditionFailed( + message: String, + code: String = "PRECONDITION_FAILED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.PAYLOAD_TOO_LARGE) -open class PayloadTooLarge(message: String, code: String = "PAYLOAD_TOO_LARGE", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class PayloadTooLarge( + message: String, + code: String = "PAYLOAD_TOO_LARGE", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.URI_TOO_LONG) -open class UriTooLong(message: String, code: String = "URI_TOO_LONG", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class UriTooLong( + message: String, + code: String = "URI_TOO_LONG", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE) -open class UnsupportedMediaType(message: String, code: String = "UNSUPPORTED_MEDIA_TYPE", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class UnsupportedMediaType( + message: String, + code: String = "UNSUPPORTED_MEDIA_TYPE", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.EXPECTATION_FAILED) -open class ExpectationFailed(message: String, code: String = "EXPECTATION_FAILED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class ExpectationFailed( + message: String, + code: String = "EXPECTATION_FAILED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.I_AM_A_TEAPOT) -open class IAmATeapot(message: String, code: String = "I_AM_A_TEAPOT", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class IAmATeapot( + message: String, + code: String = "I_AM_A_TEAPOT", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY) -open class UnprocessableEntity(message: String, code: String = "UNPROCESSABLE_ENTITY", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class UnprocessableEntity( + message: String, + code: String = "UNPROCESSABLE_ENTITY", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.LOCKED) -open class Locked(message: String, code: String = "LOCKED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class Locked( + message: String, + code: String = "LOCKED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.FAILED_DEPENDENCY) -open class FailedDependency(message: String, code: String = "FAILED_DEPENDENCY", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class FailedDependency( + message: String, + code: String = "FAILED_DEPENDENCY", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.TOO_EARLY) -open class TooEarly(message: String, code: String = "TOO_EARLY", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class TooEarly( + message: String, + code: String = "TOO_EARLY", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.UPGRADE_REQUIRED) -open class UpgradeRequired(message: String, code: String = "UPGRADE_REQUIRED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class UpgradeRequired( + message: String, + code: String = "UPGRADE_REQUIRED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.PRECONDITION_REQUIRED) -open class PreconditionRequired(message: String, code: String = "PRECONDITION_REQUIRED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class PreconditionRequired( + message: String, + code: String = "PRECONDITION_REQUIRED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.TOO_MANY_REQUESTS) -open class TooManyRequests(message: String, code: String = "TOO_MANY_REQUESTS", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class TooManyRequests( + message: String, + code: String = "TOO_MANY_REQUESTS", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE) -open class RequestHeaderFieldsTooLarge(message: String, code: String = "REQUEST_HEADER_FIELDS_TOO_LARGE", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class RequestHeaderFieldsTooLarge( + message: String, + code: String = "REQUEST_HEADER_FIELDS_TOO_LARGE", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.UNAVAILABLE_FOR_LEGAL_REASONS) -open class UnavailableForLegalReasons(message: String, code: String = "UNAVAILABLE_FOR_LEGAL_REASONS", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class UnavailableForLegalReasons( + message: String, + code: String = "UNAVAILABLE_FOR_LEGAL_REASONS", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) -open class InternalServerError(message: String, code: String = "INTERNAL_SERVER_ERROR", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class InternalServerError( + message: String, + code: String = "INTERNAL_SERVER_ERROR", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.NOT_IMPLEMENTED) -open class NotImplemented(message: String, code: String = "NOT_IMPLEMENTED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class NotImplemented( + message: String, + code: String = "NOT_IMPLEMENTED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.BAD_GATEWAY) -open class BadGateway(message: String, code: String = "BAD_GATEWAY", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class BadGateway( + message: String, + code: String = "BAD_GATEWAY", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE) -open class ServiceUnavailable(message: String, code: String = "SERVICE_UNAVAILABLE", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class ServiceUnavailable( + message: String, + code: String = "SERVICE_UNAVAILABLE", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.GATEWAY_TIMEOUT) -open class GatewayTimeout(message: String, code: String = "GATEWAY_TIMEOUT", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class GatewayTimeout( + message: String, + code: String = "GATEWAY_TIMEOUT", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.HTTP_VERSION_NOT_SUPPORTED) -open class HttpVersionNotSupported(message: String, code: String = "HTTP_VERSION_NOT_SUPPORTED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class HttpVersionNotSupported( + message: String, + code: String = "HTTP_VERSION_NOT_SUPPORTED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.VARIANT_ALSO_NEGOTIATES) -open class VariantAlsoNegotiates(message: String, code: String = "VARIANT_ALSO_NEGOTIATES", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class VariantAlsoNegotiates( + message: String, + code: String = "VARIANT_ALSO_NEGOTIATES", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.INSUFFICIENT_STORAGE) -open class InsufficientStorage(message: String, code: String = "INSUFFICIENT_STORAGE", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class InsufficientStorage( + message: String, + code: String = "INSUFFICIENT_STORAGE", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.LOOP_DETECTED) -open class LoopDetection(message: String, code: String = "LOOP_DETECTED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class LoopDetection( + message: String, + code: String = "LOOP_DETECTED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.BANDWIDTH_LIMIT_EXCEEDED) -open class BandwidthLimitExceeded(message: String, code: String = "BANDWIDTH_LIMIT_EXCEEDED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class BandwidthLimitExceeded( + message: String, + code: String = "BANDWIDTH_LIMIT_EXCEEDED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) @ResponseStatus(HttpStatus.NETWORK_AUTHENTICATION_REQUIRED) -open class NetworkAuthenticationRequired(message: String, code: String = "NETWORK_AUTHENTICATION_REQUIRED", data: HashMap<*, *>? = null) : - ApiException(message, code, data) +open class NetworkAuthenticationRequired( + message: String, + code: String = "NETWORK_AUTHENTICATION_REQUIRED", + data: HashMap<*, *>? = null +) : ApiException(message, code, data) diff --git a/src/main/kotlin/com/valensas/exception/autoconfigure/ExceptionHandlerAutoConfiguration.kt b/src/main/kotlin/com/valensas/exception/autoconfigure/ExceptionHandlerAutoConfiguration.kt index 2f50631..1d3cd2b 100644 --- a/src/main/kotlin/com/valensas/exception/autoconfigure/ExceptionHandlerAutoConfiguration.kt +++ b/src/main/kotlin/com/valensas/exception/autoconfigure/ExceptionHandlerAutoConfiguration.kt @@ -29,12 +29,11 @@ class ApiExceptionHandlerAutoConfiguration { fun apiExceptionErrorHandler( mapper: ObjectMapper, debugProperties: ExceptionHandlerConfigurationProperties - ): ApiExceptionErrorHandler { - return ApiExceptionErrorHandler( + ): ApiExceptionErrorHandler = + ApiExceptionErrorHandler( mapper = mapper, debugProperties = debugProperties ) - } } @Configuration @@ -48,12 +47,11 @@ class WebFluxParameterExceptionHandlerAutoConfiguration { fun webFluxParameterExceptionErrorHandler( mapper: ObjectMapper, debugProperties: ExceptionHandlerConfigurationProperties - ): WebFluxParameterExceptionErrorHandler { - return WebFluxParameterExceptionErrorHandler( + ): WebFluxParameterExceptionErrorHandler = + WebFluxParameterExceptionErrorHandler( mapper = mapper, debugProperties = debugProperties ) - } } @Configuration @@ -67,12 +65,11 @@ class WebParameterExceptionErrorHandlerConfiguration { fun webParameterExceptionErrorHandler( mapper: ObjectMapper, debugProperties: ExceptionHandlerConfigurationProperties - ): WebParameterExceptionErrorHandler { - return WebParameterExceptionErrorHandler( + ): WebParameterExceptionErrorHandler = + WebParameterExceptionErrorHandler( mapper, debugProperties ) - } } @Configuration @@ -83,12 +80,11 @@ class FeignErrorHandlerAutoConfiguration { fun feignErrorHandler( mapper: ObjectMapper, debugProperties: ExceptionHandlerConfigurationProperties - ): FeignErrorHandler { - return FeignErrorHandler( + ): FeignErrorHandler = + FeignErrorHandler( mapper = mapper, debugProperties = debugProperties ) - } } @Configuration @@ -99,12 +95,11 @@ class WebClientErrorHandlerAutoConfiguration { fun webClientErrorHandler( mapper: ObjectMapper, debugProperties: ExceptionHandlerConfigurationProperties - ): WebClientErrorHandler { - return WebClientErrorHandler( + ): WebClientErrorHandler = + WebClientErrorHandler( mapper = mapper, debugProperties = debugProperties ) - } } @Configuration @@ -115,10 +110,9 @@ class RestTemplateErrorHandlerAutoConfiguration { fun restTemplateErrorHandler( mapper: ObjectMapper, debugProperties: ExceptionHandlerConfigurationProperties - ): RestTemplateErrorHandler { - return RestTemplateErrorHandler( + ): RestTemplateErrorHandler = + RestTemplateErrorHandler( mapper = mapper, debugProperties = debugProperties ) - } } diff --git a/src/main/kotlin/com/valensas/exception/handler/FeignErrorHandler.kt b/src/main/kotlin/com/valensas/exception/handler/FeignErrorHandler.kt index 3e0320d..9543153 100644 --- a/src/main/kotlin/com/valensas/exception/handler/FeignErrorHandler.kt +++ b/src/main/kotlin/com/valensas/exception/handler/FeignErrorHandler.kt @@ -24,8 +24,8 @@ class FeignErrorHandler( private val logger = LoggerFactory.getLogger(javaClass) @ExceptionHandler(FeignException::class) - fun handleFeignException(exception: FeignException): ResponseEntity { - return try { + fun handleFeignException(exception: FeignException): ResponseEntity = + try { val apiException = mapper.readValue(exception.contentUTF8(), ApiException::class.java) val body = convert(apiException, exception, debugProperties.debug.enabled, debugProperties.debug.packages) responseWith(body, apiException.statusCode) @@ -39,5 +39,4 @@ class FeignErrorHandler( logger.warn("Unhandled FeignException occurred. Response body: {}.", exception.contentUTF8(), e) responseWith(mapOf("message" to "An error occured."), HttpStatus.INTERNAL_SERVER_ERROR) } - } } diff --git a/src/main/kotlin/com/valensas/exception/handler/HttpErrorHandler.kt b/src/main/kotlin/com/valensas/exception/handler/HttpErrorHandler.kt index d418064..0bd71e9 100644 --- a/src/main/kotlin/com/valensas/exception/handler/HttpErrorHandler.kt +++ b/src/main/kotlin/com/valensas/exception/handler/HttpErrorHandler.kt @@ -20,14 +20,13 @@ abstract class HttpErrorHandler( fun responseWith( body: Any?, statusCode: HttpStatus - ): ResponseEntity { - return ResponseEntity(body, defaultHeaders, statusCode).also { + ): ResponseEntity = + ResponseEntity(body, defaultHeaders, statusCode).also { when { it.statusCode.value() in 400..500 && log4xx -> logger.error("Returning {}, body: {}", it.statusCode.value(), it.body) it.statusCode.value() in 500..600 && log5xx -> logger.error("Returning {}, body: {}", it.statusCode.value(), it.body) } } - } private fun Map.filterNotNullValues(): Map = mutableMapOf().apply { for ((k, v) in this@filterNotNullValues) if (v != null) put(k, v) } diff --git a/src/main/kotlin/com/valensas/exception/handler/WebFluxParameterExceptionErrorHandler.kt b/src/main/kotlin/com/valensas/exception/handler/WebFluxParameterExceptionErrorHandler.kt index e1ff1c6..609a344 100644 --- a/src/main/kotlin/com/valensas/exception/handler/WebFluxParameterExceptionErrorHandler.kt +++ b/src/main/kotlin/com/valensas/exception/handler/WebFluxParameterExceptionErrorHandler.kt @@ -67,6 +67,7 @@ class WebFluxParameterExceptionErrorHandler( parameter = typeMismatchException.propertyName message = typeMismatchException.localizedMessage } + is DecodingException -> { val decodingException = exception.cause as DecodingException when (decodingException.cause) { @@ -127,7 +128,11 @@ class WebFluxParameterExceptionErrorHandler( exception.valueResults.map { FieldError( field = it.methodParameter.parameter.name, - message = it.resolvableErrors.first().defaultMessage.toString() + message = + it.resolvableErrors + .first() + .defaultMessage + .toString() ) } ) diff --git a/src/test/kotlin/com/valensas/exception/integrationTests/WebParameterExceptionErrorHandlerTest.kt b/src/test/kotlin/com/valensas/exception/integrationTests/WebParameterExceptionErrorHandlerTest.kt index 8e4e2ae..a3b17be 100644 --- a/src/test/kotlin/com/valensas/exception/integrationTests/WebParameterExceptionErrorHandlerTest.kt +++ b/src/test/kotlin/com/valensas/exception/integrationTests/WebParameterExceptionErrorHandlerTest.kt @@ -19,75 +19,93 @@ class WebParameterExceptionErrorHandlerTest { @Test fun `Try to send get request with missing header and check response message`() { - webClient.get() + webClient + .get() .uri("/web/${UUID.randomUUID()}") .exchange() - .expectStatus().isEqualTo(HttpStatus.BAD_REQUEST) + .expectStatus() + .isEqualTo(HttpStatus.BAD_REQUEST) .expectBody() - .jsonPath("$.message").isEqualTo("Required request header 'headerNumber' for method parameter type long is not present") + .jsonPath("$.message") + .isEqualTo("Required request header 'headerNumber' for method parameter type long is not present") .returnResult() } @Test fun `Try to send get request with wrong format header and check response message`() { - webClient.get() + webClient + .get() .uri("/web/${UUID.randomUUID()}") .header("headerNumber", "invalid_value") .exchange() - .expectStatus().is4xxClientError + .expectStatus() + .is4xxClientError .expectBody() .jsonPath( "$.message" ).isEqualTo( - "Failed to convert value of type 'java.lang.String' to required type 'long'; For input string: \"invalid_value\"" - ) - .returnResult() + "Method parameter 'headerNumber': Failed to convert value of type 'java.lang.String' to required type 'long'; " + + "For input string: \"invalid_value\"" + ).returnResult() } @Test fun `Try to send get request with missing request param and check response message`() { - webClient.get() + webClient + .get() .uri("/web") .exchange() - .expectStatus().is4xxClientError + .expectStatus() + .is4xxClientError .expectBody() - .jsonPath("$.message").isEqualTo("Required request parameter 'param' for method parameter type UUID is not present") + .jsonPath("$.message") + .isEqualTo("Required request parameter 'param' for method parameter type UUID is not present") } @Test fun `Try to send get request with wrong format request param and check response message`() { - webClient.get() + webClient + .get() .uri("/web?param=12") .exchange() - .expectStatus().is4xxClientError + .expectStatus() + .is4xxClientError .expectBody() .jsonPath( "$.message" - ).isEqualTo("Failed to convert value of type 'java.lang.String' to required type 'java.util.UUID'; Invalid UUID string: 12") + ).isEqualTo( + "Method parameter 'param': Failed to convert value of type 'java.lang.String' to required type 'java.util.UUID'; " + + "Invalid UUID string: 12" + ) } @Test fun `Try to send get request with wrong format path variable and check response message`() { - webClient.get() + webClient + .get() .uri("/web/12345") .header("headerNumber", "12") .exchange() - .expectStatus().is4xxClientError + .expectStatus() + .is4xxClientError .expectBody() .jsonPath( "$.message" ).isEqualTo( - "Failed to convert value of type 'java.lang.String' to required type 'java.util.UUID'; Invalid UUID string: 12345" + "Method parameter 'pathVariable': Failed to convert value of type 'java.lang.String' to required type 'java.util.UUID'; " + + "Invalid UUID string: 12345" ) } @Test fun `Try to send post request with wrong format body variable and check response message`() { - webClient.post() + webClient + .post() .uri("/web") .bodyValue(WrongFormatParameterModel(12, 13)) .exchange() - .expectStatus().is4xxClientError + .expectStatus() + .is4xxClientError .expectBody() .jsonPath( "$.message" @@ -99,11 +117,13 @@ class WebParameterExceptionErrorHandlerTest { @Test fun `Try to send post request with missing body variable and check response message`() { - webClient.post() + webClient + .post() .uri("/web") .bodyValue(MissingParameterModel(12)) .exchange() - .expectStatus().is4xxClientError + .expectStatus() + .is4xxClientError .expectBody() .jsonPath( "$.message"