diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 4191c889..e0dc5001 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "3.0.0"
+ ".": "3.1.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index 6d0a83a8..6b776b6f 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 47
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/imagekit-inc%2Fimagekit-c7f578172392bde58bbb72be2a25b9e917529cd07550358c645ce155debf2418.yml
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/imagekit-inc/imagekit-362d0336e8f52ab1beb7d9602a3665dbb0277700e8dc01ef4f96fc7651699349.yml
openapi_spec_hash: f0d797a17b1e8e81707517700cd44b13
-config_hash: da0c89d794fefcf600a4ddfc78553c2a
+config_hash: 94f48fd13b7d41b8b6a203a3a8cee9ed
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e128eed8..2f5a89eb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,31 @@
# Changelog
+## 3.1.0 (2026-05-06)
+
+Full Changelog: [v3.0.0...v3.1.0](https://github.com/imagekit-developer/imagekit-java/compare/v3.0.0...v3.1.0)
+
+### Features
+
+* **client:** improve logging ([a62b5e3](https://github.com/imagekit-developer/imagekit-java/commit/a62b5e30077bab50d3a9764daa7c520df18914bb))
+* **client:** more robust error parsing ([8e42517](https://github.com/imagekit-developer/imagekit-java/commit/8e4251712d721a17b9caa4f1ad04e9c2c06822a0))
+* **client:** support proxy authentication ([60effd3](https://github.com/imagekit-developer/imagekit-java/commit/60effd33a60b70e3f44e9180927e3a63a93ee00d))
+* support setting headers via env ([c31a472](https://github.com/imagekit-developer/imagekit-java/commit/c31a472fd2674c2e339d16024cb47bf246994a38))
+
+
+### Performance Improvements
+
+* **client:** create one json mapper ([92128db](https://github.com/imagekit-developer/imagekit-java/commit/92128db5fbd82870290b9c1b5003115dd7c04469))
+
+
+### Chores
+
+* remove duplicated dokka setup ([a1a0ece](https://github.com/imagekit-developer/imagekit-java/commit/a1a0ece2a2e02b2dc10b6bee8d043170e3cd9681))
+
+
+### Documentation
+
+* clarify forwards compat behavior ([d5ec8cf](https://github.com/imagekit-developer/imagekit-java/commit/d5ec8cffa3ebac99d70f70f7b6c4fadbe042a5be))
+
## 3.0.0 (2026-04-21)
Full Changelog: [v0.0.1...v3.0.0](https://github.com/imagekit-developer/imagekit-java/compare/v0.0.1...v3.0.0)
diff --git a/README.md b/README.md
index 69642eee..c5b76c9e 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,8 @@
-[](https://central.sonatype.com/artifact/io.imagekit/image-kit-java/3.0.0)
-[](https://javadoc.io/doc/io.imagekit/image-kit-java/3.0.0)
+[](https://central.sonatype.com/artifact/io.imagekit/image-kit-java/3.1.0)
+[](https://javadoc.io/doc/io.imagekit/image-kit-java/3.1.0)
@@ -11,7 +11,7 @@ The ImageKit Java SDK is a comprehensive library designed to simplify the integr
-The REST API documentation can be found on [imagekit.io](https://imagekit.io/docs/api-reference). Javadocs are available on [javadoc.io](https://javadoc.io/doc/io.imagekit/image-kit-java/3.0.0).
+The REST API documentation can be found on [imagekit.io](https://imagekit.io/docs/api-reference). Javadocs are available on [javadoc.io](https://javadoc.io/doc/io.imagekit/image-kit-java/3.1.0).
@@ -46,7 +46,7 @@ The REST API documentation can be found on [imagekit.io](https://imagekit.io/doc
### Gradle
```kotlin
-implementation("io.imagekit:image-kit-java:3.0.0")
+implementation("io.imagekit:image-kit-java:3.1.0")
```
### Maven
@@ -55,7 +55,7 @@ implementation("io.imagekit:image-kit-java:3.0.0")
io.imagekit
image-kit-java
- 3.0.0
+ 3.1.0
```
@@ -615,8 +615,6 @@ The SDK throws custom unchecked exception types:
## Logging
-The SDK uses the standard [OkHttp logging interceptor](https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor).
-
Enable logging by setting the `IMAGE_KIT_LOG` environment variable to `info`:
```sh
@@ -629,6 +627,19 @@ Or to `debug` for more verbose logging:
export IMAGE_KIT_LOG=debug
```
+Or configure the client manually using the `logLevel` method:
+
+```java
+import io.imagekit.client.ImageKitClient;
+import io.imagekit.client.okhttp.ImageKitOkHttpClient;
+import io.imagekit.core.LogLevel;
+
+ImageKitClient client = ImageKitOkHttpClient.builder()
+ .fromEnv()
+ .logLevel(LogLevel.INFO)
+ .build();
+```
+
## ProGuard and R8
Although the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `image-kit-java-core` is published with a [configuration file](image-kit-java-core/src/main/resources/META-INF/proguard/image-kit-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage).
@@ -723,6 +734,21 @@ ImageKitClient client = ImageKitOkHttpClient.builder()
.build();
```
+If the proxy responds with `407 Proxy Authentication Required`, supply credentials by also configuring `proxyAuthenticator`:
+
+```java
+import io.imagekit.client.ImageKitClient;
+import io.imagekit.client.okhttp.ImageKitOkHttpClient;
+import io.imagekit.core.http.ProxyAuthenticator;
+
+ImageKitClient client = ImageKitOkHttpClient.builder()
+ .fromEnv()
+ .proxy(...)
+ // Or a custom implementation of `ProxyAuthenticator`.
+ .proxyAuthenticator(ProxyAuthenticator.basic("username", "password"))
+ .build();
+```
+
### Connection pooling
To customize the underlying OkHttp connection pool, configure the client using the `maxIdleConnections` and `keepAliveDuration` methods:
@@ -961,7 +987,9 @@ In rare cases, the API may return a response that doesn't match the expected typ
By default, the SDK will not throw an exception in this case. It will throw [`ImageKitInvalidDataException`](image-kit-java-core/src/main/kotlin/io/imagekit/errors/ImageKitInvalidDataException.kt) only if you directly access the property.
-If you would prefer to check that the response is completely well-typed upfront, then either call `validate()`:
+Validating the response is _not_ forwards compatible with new types from the API for existing fields.
+
+If you would still prefer to check that the response is completely well-typed upfront, then either call `validate()`:
```java
import io.imagekit.models.files.FileUploadResponse;
diff --git a/build.gradle.kts b/build.gradle.kts
index 411f291f..a2875ce6 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -8,7 +8,7 @@ repositories {
allprojects {
group = "io.imagekit"
- version = "3.0.0" // x-release-please-version
+ version = "3.1.0" // x-release-please-version
}
subprojects {
@@ -21,7 +21,6 @@ subprojects {
group = "Verification"
description = "Verifies all source files are formatted."
}
- apply(plugin = "org.jetbrains.dokka")
}
subprojects {
diff --git a/image-kit-java-client-okhttp/build.gradle.kts b/image-kit-java-client-okhttp/build.gradle.kts
index 51259131..6f641e80 100644
--- a/image-kit-java-client-okhttp/build.gradle.kts
+++ b/image-kit-java-client-okhttp/build.gradle.kts
@@ -7,7 +7,6 @@ dependencies {
api(project(":image-kit-java-core"))
implementation("com.squareup.okhttp3:okhttp:4.12.0")
- implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
testImplementation(kotlin("test"))
testImplementation("org.assertj:assertj-core:3.27.7")
diff --git a/image-kit-java-client-okhttp/src/main/kotlin/io/imagekit/client/okhttp/ImageKitOkHttpClient.kt b/image-kit-java-client-okhttp/src/main/kotlin/io/imagekit/client/okhttp/ImageKitOkHttpClient.kt
index 7f2325e8..8b8caae8 100644
--- a/image-kit-java-client-okhttp/src/main/kotlin/io/imagekit/client/okhttp/ImageKitOkHttpClient.kt
+++ b/image-kit-java-client-okhttp/src/main/kotlin/io/imagekit/client/okhttp/ImageKitOkHttpClient.kt
@@ -6,10 +6,12 @@ import com.fasterxml.jackson.databind.json.JsonMapper
import io.imagekit.client.ImageKitClient
import io.imagekit.client.ImageKitClientImpl
import io.imagekit.core.ClientOptions
+import io.imagekit.core.LogLevel
import io.imagekit.core.Sleeper
import io.imagekit.core.Timeout
import io.imagekit.core.http.Headers
import io.imagekit.core.http.HttpClient
+import io.imagekit.core.http.ProxyAuthenticator
import io.imagekit.core.http.QueryParams
import io.imagekit.core.jsonMapper
import java.net.Proxy
@@ -47,6 +49,7 @@ class ImageKitOkHttpClient private constructor() {
private var clientOptions: ClientOptions.Builder = ClientOptions.builder()
private var dispatcherExecutorService: ExecutorService? = null
private var proxy: Proxy? = null
+ private var proxyAuthenticator: ProxyAuthenticator? = null
private var maxIdleConnections: Int? = null
private var keepAliveDuration: Duration? = null
private var sslSocketFactory: SSLSocketFactory? = null
@@ -77,6 +80,20 @@ class ImageKitOkHttpClient private constructor() {
/** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */
fun proxy(proxy: Optional) = proxy(proxy.getOrNull())
+ /**
+ * Provides credentials when an HTTP proxy responds with `407 Proxy Authentication
+ * Required`.
+ */
+ fun proxyAuthenticator(proxyAuthenticator: ProxyAuthenticator?) = apply {
+ this.proxyAuthenticator = proxyAuthenticator
+ }
+
+ /**
+ * Alias for calling [Builder.proxyAuthenticator] with `proxyAuthenticator.orElse(null)`.
+ */
+ fun proxyAuthenticator(proxyAuthenticator: Optional) =
+ proxyAuthenticator(proxyAuthenticator.getOrNull())
+
/**
* The maximum number of idle connections kept by the underlying OkHttp connection pool.
*
@@ -217,6 +234,9 @@ class ImageKitOkHttpClient private constructor() {
/**
* Whether to call `validate` on every response before returning it.
*
+ * Setting this to `true` is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
* Defaults to false, which means the shape of the response will not be validated upfront.
* Instead, validation will only occur for the parts of the response that are accessed.
*/
@@ -258,6 +278,15 @@ class ImageKitOkHttpClient private constructor() {
*/
fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) }
+ /**
+ * The level at which to log request and response information.
+ *
+ * [fromEnv] will set the level from environment variables. See [LogLevel.fromEnv].
+ *
+ * Defaults to [LogLevel.fromEnv].
+ */
+ fun logLevel(logLevel: LogLevel) = apply { clientOptions.logLevel(logLevel) }
+
/**
* Your ImageKit private API key (starts with `private_`). You can find this in the
* [ImageKit dashboard](https://imagekit.io/dashboard/developer/api-keys).
@@ -388,6 +417,7 @@ class ImageKitOkHttpClient private constructor() {
OkHttpClient.builder()
.timeout(clientOptions.timeout())
.proxy(proxy)
+ .proxyAuthenticator(proxyAuthenticator)
.maxIdleConnections(maxIdleConnections)
.keepAliveDuration(keepAliveDuration)
.dispatcherExecutorService(dispatcherExecutorService)
diff --git a/image-kit-java-client-okhttp/src/main/kotlin/io/imagekit/client/okhttp/ImageKitOkHttpClientAsync.kt b/image-kit-java-client-okhttp/src/main/kotlin/io/imagekit/client/okhttp/ImageKitOkHttpClientAsync.kt
index c0af9fc1..575c8dca 100644
--- a/image-kit-java-client-okhttp/src/main/kotlin/io/imagekit/client/okhttp/ImageKitOkHttpClientAsync.kt
+++ b/image-kit-java-client-okhttp/src/main/kotlin/io/imagekit/client/okhttp/ImageKitOkHttpClientAsync.kt
@@ -6,10 +6,12 @@ import com.fasterxml.jackson.databind.json.JsonMapper
import io.imagekit.client.ImageKitClientAsync
import io.imagekit.client.ImageKitClientAsyncImpl
import io.imagekit.core.ClientOptions
+import io.imagekit.core.LogLevel
import io.imagekit.core.Sleeper
import io.imagekit.core.Timeout
import io.imagekit.core.http.Headers
import io.imagekit.core.http.HttpClient
+import io.imagekit.core.http.ProxyAuthenticator
import io.imagekit.core.http.QueryParams
import io.imagekit.core.jsonMapper
import java.net.Proxy
@@ -47,6 +49,7 @@ class ImageKitOkHttpClientAsync private constructor() {
private var clientOptions: ClientOptions.Builder = ClientOptions.builder()
private var dispatcherExecutorService: ExecutorService? = null
private var proxy: Proxy? = null
+ private var proxyAuthenticator: ProxyAuthenticator? = null
private var maxIdleConnections: Int? = null
private var keepAliveDuration: Duration? = null
private var sslSocketFactory: SSLSocketFactory? = null
@@ -77,6 +80,20 @@ class ImageKitOkHttpClientAsync private constructor() {
/** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */
fun proxy(proxy: Optional) = proxy(proxy.getOrNull())
+ /**
+ * Provides credentials when an HTTP proxy responds with `407 Proxy Authentication
+ * Required`.
+ */
+ fun proxyAuthenticator(proxyAuthenticator: ProxyAuthenticator?) = apply {
+ this.proxyAuthenticator = proxyAuthenticator
+ }
+
+ /**
+ * Alias for calling [Builder.proxyAuthenticator] with `proxyAuthenticator.orElse(null)`.
+ */
+ fun proxyAuthenticator(proxyAuthenticator: Optional) =
+ proxyAuthenticator(proxyAuthenticator.getOrNull())
+
/**
* The maximum number of idle connections kept by the underlying OkHttp connection pool.
*
@@ -217,6 +234,9 @@ class ImageKitOkHttpClientAsync private constructor() {
/**
* Whether to call `validate` on every response before returning it.
*
+ * Setting this to `true` is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
* Defaults to false, which means the shape of the response will not be validated upfront.
* Instead, validation will only occur for the parts of the response that are accessed.
*/
@@ -258,6 +278,15 @@ class ImageKitOkHttpClientAsync private constructor() {
*/
fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) }
+ /**
+ * The level at which to log request and response information.
+ *
+ * [fromEnv] will set the level from environment variables. See [LogLevel.fromEnv].
+ *
+ * Defaults to [LogLevel.fromEnv].
+ */
+ fun logLevel(logLevel: LogLevel) = apply { clientOptions.logLevel(logLevel) }
+
/**
* Your ImageKit private API key (starts with `private_`). You can find this in the
* [ImageKit dashboard](https://imagekit.io/dashboard/developer/api-keys).
@@ -388,6 +417,7 @@ class ImageKitOkHttpClientAsync private constructor() {
OkHttpClient.builder()
.timeout(clientOptions.timeout())
.proxy(proxy)
+ .proxyAuthenticator(proxyAuthenticator)
.maxIdleConnections(maxIdleConnections)
.keepAliveDuration(keepAliveDuration)
.dispatcherExecutorService(dispatcherExecutorService)
diff --git a/image-kit-java-client-okhttp/src/main/kotlin/io/imagekit/client/okhttp/OkHttpClient.kt b/image-kit-java-client-okhttp/src/main/kotlin/io/imagekit/client/okhttp/OkHttpClient.kt
index 4a6fed28..b18f7178 100644
--- a/image-kit-java-client-okhttp/src/main/kotlin/io/imagekit/client/okhttp/OkHttpClient.kt
+++ b/image-kit-java-client-okhttp/src/main/kotlin/io/imagekit/client/okhttp/OkHttpClient.kt
@@ -8,9 +8,11 @@ import io.imagekit.core.http.HttpMethod
import io.imagekit.core.http.HttpRequest
import io.imagekit.core.http.HttpRequestBody
import io.imagekit.core.http.HttpResponse
+import io.imagekit.core.http.ProxyAuthenticator
import io.imagekit.errors.ImageKitIoException
import java.io.IOException
import java.io.InputStream
+import java.io.OutputStream
import java.net.Proxy
import java.time.Duration
import java.util.concurrent.CancellationException
@@ -20,10 +22,12 @@ import java.util.concurrent.TimeUnit
import javax.net.ssl.HostnameVerifier
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.X509TrustManager
+import kotlin.jvm.optionals.getOrNull
import okhttp3.Call
import okhttp3.Callback
import okhttp3.ConnectionPool
import okhttp3.Dispatcher
+import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaType
@@ -31,8 +35,9 @@ import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
-import okhttp3.logging.HttpLoggingInterceptor
import okio.BufferedSink
+import okio.buffer
+import okio.sink
class OkHttpClient
internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClient) : HttpClient {
@@ -41,7 +46,7 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie
val call = newCall(request, requestOptions)
return try {
- call.execute().toResponse()
+ call.execute().toHttpResponse()
} catch (e: IOException) {
throw ImageKitIoException("Request failed", e)
} finally {
@@ -59,7 +64,7 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie
call.enqueue(
object : Callback {
override fun onResponse(call: Call, response: Response) {
- future.complete(response.toResponse())
+ future.complete(response.toHttpResponse())
}
override fun onFailure(call: Call, e: IOException) {
@@ -87,18 +92,6 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie
private fun newCall(request: HttpRequest, requestOptions: RequestOptions): Call {
val clientBuilder = okHttpClient.newBuilder()
- val logLevel =
- when (System.getenv("IMAGE_KIT_LOG")?.lowercase()) {
- "info" -> HttpLoggingInterceptor.Level.BASIC
- "debug" -> HttpLoggingInterceptor.Level.BODY
- else -> null
- }
- if (logLevel != null) {
- clientBuilder.addNetworkInterceptor(
- HttpLoggingInterceptor().setLevel(logLevel).apply { redactHeader("Authorization") }
- )
- }
-
requestOptions.timeout?.let {
clientBuilder
.connectTimeout(it.connect())
@@ -111,89 +104,6 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie
return client.newCall(request.toRequest(client))
}
- private fun HttpRequest.toRequest(client: okhttp3.OkHttpClient): Request {
- var body: RequestBody? = body?.toRequestBody()
- if (body == null && requiresBody(method)) {
- body = "".toRequestBody()
- }
-
- val builder = Request.Builder().url(toUrl()).method(method.name, body)
- headers.names().forEach { name ->
- headers.values(name).forEach { builder.addHeader(name, it) }
- }
-
- if (
- !headers.names().contains("X-Stainless-Read-Timeout") && client.readTimeoutMillis != 0
- ) {
- builder.addHeader(
- "X-Stainless-Read-Timeout",
- Duration.ofMillis(client.readTimeoutMillis.toLong()).seconds.toString(),
- )
- }
- if (!headers.names().contains("X-Stainless-Timeout") && client.callTimeoutMillis != 0) {
- builder.addHeader(
- "X-Stainless-Timeout",
- Duration.ofMillis(client.callTimeoutMillis.toLong()).seconds.toString(),
- )
- }
-
- return builder.build()
- }
-
- /** `OkHttpClient` always requires a request body for some methods. */
- private fun requiresBody(method: HttpMethod): Boolean =
- when (method) {
- HttpMethod.POST,
- HttpMethod.PUT,
- HttpMethod.PATCH -> true
- else -> false
- }
-
- private fun HttpRequest.toUrl(): String {
- val builder = baseUrl.toHttpUrl().newBuilder()
- pathSegments.forEach(builder::addPathSegment)
- queryParams.keys().forEach { key ->
- queryParams.values(key).forEach { builder.addQueryParameter(key, it) }
- }
-
- return builder.toString()
- }
-
- private fun HttpRequestBody.toRequestBody(): RequestBody {
- val mediaType = contentType()?.toMediaType()
- val length = contentLength()
-
- return object : RequestBody() {
- override fun contentType(): MediaType? = mediaType
-
- override fun contentLength(): Long = length
-
- override fun isOneShot(): Boolean = !repeatable()
-
- override fun writeTo(sink: BufferedSink) = writeTo(sink.outputStream())
- }
- }
-
- private fun Response.toResponse(): HttpResponse {
- val headers = headers.toHeaders()
-
- return object : HttpResponse {
- override fun statusCode(): Int = code
-
- override fun headers(): Headers = headers
-
- override fun body(): InputStream = body!!.byteStream()
-
- override fun close() = body!!.close()
- }
- }
-
- private fun okhttp3.Headers.toHeaders(): Headers {
- val headersBuilder = Headers.builder()
- forEach { (name, value) -> headersBuilder.put(name, value) }
- return headersBuilder.build()
- }
-
companion object {
@JvmStatic fun builder() = Builder()
}
@@ -202,6 +112,7 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie
private var timeout: Timeout = Timeout.default()
private var proxy: Proxy? = null
+ private var proxyAuthenticator: ProxyAuthenticator? = null
private var maxIdleConnections: Int? = null
private var keepAliveDuration: Duration? = null
private var dispatcherExecutorService: ExecutorService? = null
@@ -215,6 +126,10 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie
fun proxy(proxy: Proxy?) = apply { this.proxy = proxy }
+ fun proxyAuthenticator(proxyAuthenticator: ProxyAuthenticator?) = apply {
+ this.proxyAuthenticator = proxyAuthenticator
+ }
+
/**
* Sets the maximum number of idle connections kept by the underlying [ConnectionPool].
*
@@ -264,6 +179,19 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie
.callTimeout(timeout.request())
.proxy(proxy)
.apply {
+ proxyAuthenticator?.let { auth ->
+ proxyAuthenticator { route, response ->
+ auth
+ .authenticate(
+ route?.proxy ?: Proxy.NO_PROXY,
+ response.request.toHttpRequest(),
+ response.toHttpResponse(),
+ )
+ .getOrNull()
+ ?.toRequest(client = null)
+ }
+ }
+
dispatcherExecutorService?.let { dispatcher(Dispatcher(it)) }
val maxIdleConnections = maxIdleConnections
@@ -303,3 +231,126 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie
)
}
}
+
+private fun HttpRequest.toRequest(client: okhttp3.OkHttpClient?): Request {
+ var body: RequestBody? = body?.toRequestBody()
+ if (body == null && requiresBody(method)) {
+ body = "".toRequestBody()
+ }
+
+ val builder = Request.Builder().url(toUrl()).method(method.name, body)
+ headers.names().forEach { name -> headers.values(name).forEach { builder.addHeader(name, it) } }
+
+ if (client != null) {
+ if (
+ !headers.names().contains("X-Stainless-Read-Timeout") && client.readTimeoutMillis != 0
+ ) {
+ builder.addHeader(
+ "X-Stainless-Read-Timeout",
+ Duration.ofMillis(client.readTimeoutMillis.toLong()).seconds.toString(),
+ )
+ }
+ if (!headers.names().contains("X-Stainless-Timeout") && client.callTimeoutMillis != 0) {
+ builder.addHeader(
+ "X-Stainless-Timeout",
+ Duration.ofMillis(client.callTimeoutMillis.toLong()).seconds.toString(),
+ )
+ }
+ }
+
+ return builder.build()
+}
+
+/** `OkHttpClient` always requires a request body for some methods. */
+private fun requiresBody(method: HttpMethod): Boolean =
+ when (method) {
+ HttpMethod.POST,
+ HttpMethod.PUT,
+ HttpMethod.PATCH -> true
+ else -> false
+ }
+
+private fun HttpRequest.toUrl(): String {
+ val builder = baseUrl.toHttpUrl().newBuilder()
+ pathSegments.forEach(builder::addPathSegment)
+ queryParams.keys().forEach { key ->
+ queryParams.values(key).forEach { builder.addQueryParameter(key, it) }
+ }
+
+ return builder.toString()
+}
+
+private fun HttpRequestBody.toRequestBody(): RequestBody {
+ val mediaType = contentType()?.toMediaType()
+ val length = contentLength()
+
+ return object : RequestBody() {
+ override fun contentType(): MediaType? = mediaType
+
+ override fun contentLength(): Long = length
+
+ override fun isOneShot(): Boolean = !repeatable()
+
+ override fun writeTo(sink: BufferedSink) = writeTo(sink.outputStream())
+ }
+}
+
+private fun Request.toHttpRequest(): HttpRequest {
+ val builder = HttpRequest.builder().method(HttpMethod.valueOf(method)).baseUrl(url.toBaseUrl())
+ url.pathSegments.forEach(builder::addPathSegment)
+ url.queryParameterNames.forEach { name ->
+ url.queryParameterValues(name).filterNotNull().forEach { builder.putQueryParam(name, it) }
+ }
+ headers.forEach { (name, value) -> builder.putHeader(name, value) }
+ body?.let { builder.body(it.toHttpRequestBody()) }
+ return builder.build()
+}
+
+private fun HttpUrl.toBaseUrl(): String = buildString {
+ append(scheme).append("://").append(host)
+ if (port != HttpUrl.defaultPort(scheme)) {
+ append(":").append(port)
+ }
+}
+
+private fun RequestBody.toHttpRequestBody(): HttpRequestBody {
+ val mediaType = contentType()?.toString()
+ val length = contentLength()
+ val isOneShot = isOneShot()
+ val source = this
+ return object : HttpRequestBody {
+ override fun contentType(): String? = mediaType
+
+ override fun contentLength(): Long = length
+
+ override fun repeatable(): Boolean = !isOneShot
+
+ override fun writeTo(outputStream: OutputStream) {
+ val sink = outputStream.sink().buffer()
+ source.writeTo(sink)
+ sink.flush()
+ }
+
+ override fun close() {}
+ }
+}
+
+private fun Response.toHttpResponse(): HttpResponse {
+ val headers = headers.toHeaders()
+
+ return object : HttpResponse {
+ override fun statusCode(): Int = code
+
+ override fun headers(): Headers = headers
+
+ override fun body(): InputStream = body!!.byteStream()
+
+ override fun close() = body!!.close()
+ }
+}
+
+private fun okhttp3.Headers.toHeaders(): Headers {
+ val headersBuilder = Headers.builder()
+ forEach { (name, value) -> headersBuilder.put(name, value) }
+ return headersBuilder.build()
+}
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/core/ClientOptions.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/core/ClientOptions.kt
index 0cee88bc..ec7df69e 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/core/ClientOptions.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/core/ClientOptions.kt
@@ -5,6 +5,7 @@ package io.imagekit.core
import com.fasterxml.jackson.databind.json.JsonMapper
import io.imagekit.core.http.Headers
import io.imagekit.core.http.HttpClient
+import io.imagekit.core.http.LoggingHttpClient
import io.imagekit.core.http.PhantomReachableClosingHttpClient
import io.imagekit.core.http.QueryParams
import io.imagekit.core.http.RetryingHttpClient
@@ -67,6 +68,9 @@ private constructor(
/**
* Whether to call `validate` on every response before returning it.
*
+ * Setting this to `true` is _not_ forwards compatible with new types from the API for existing
+ * fields.
+ *
* Defaults to false, which means the shape of the response will not be validated upfront.
* Instead, validation will only occur for the parts of the response that are accessed.
*/
@@ -94,6 +98,14 @@ private constructor(
* Defaults to 2.
*/
@get:JvmName("maxRetries") val maxRetries: Int,
+ /**
+ * The level at which to log request and response information.
+ *
+ * [fromEnv] will set the level from environment variables. See [LogLevel.fromEnv].
+ *
+ * Defaults to [LogLevel.fromEnv].
+ */
+ @get:JvmName("logLevel") val logLevel: LogLevel,
/**
* Your ImageKit private API key (starts with `private_`). You can find this in the
* [ImageKit dashboard](https://imagekit.io/dashboard/developer/api-keys).
@@ -172,6 +184,7 @@ private constructor(
private var responseValidation: Boolean = false
private var timeout: Timeout = Timeout.default()
private var maxRetries: Int = 2
+ private var logLevel: LogLevel = LogLevel.fromEnv()
private var privateKey: String? = null
private var password: String? = "do_not_set"
private var webhookSecret: String? = null
@@ -189,6 +202,7 @@ private constructor(
responseValidation = clientOptions.responseValidation
timeout = clientOptions.timeout
maxRetries = clientOptions.maxRetries
+ logLevel = clientOptions.logLevel
privateKey = clientOptions.privateKey
password = clientOptions.password
webhookSecret = clientOptions.webhookSecret
@@ -257,6 +271,9 @@ private constructor(
/**
* Whether to call `validate` on every response before returning it.
*
+ * Setting this to `true` is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
* Defaults to false, which means the shape of the response will not be validated upfront.
* Instead, validation will only occur for the parts of the response that are accessed.
*/
@@ -298,6 +315,15 @@ private constructor(
*/
fun maxRetries(maxRetries: Int) = apply { this.maxRetries = maxRetries }
+ /**
+ * The level at which to log request and response information.
+ *
+ * [fromEnv] will set the level from environment variables. See [LogLevel.fromEnv].
+ *
+ * Defaults to [LogLevel.fromEnv].
+ */
+ fun logLevel(logLevel: LogLevel) = apply { this.logLevel = logLevel }
+
/**
* Your ImageKit private API key (starts with `private_`). You can find this in the
* [ImageKit dashboard](https://imagekit.io/dashboard/developer/api-keys).
@@ -424,6 +450,7 @@ private constructor(
* System properties take precedence over environment variables.
*/
fun fromEnv() = apply {
+ logLevel(LogLevel.fromEnv())
(System.getProperty("imagekit.baseUrl") ?: System.getenv("IMAGE_KIT_BASE_URL"))?.let {
baseUrl(it)
}
@@ -436,6 +463,14 @@ private constructor(
(System.getProperty("imagekit.imagekitWebhookSecret")
?: System.getenv("IMAGEKIT_WEBHOOK_SECRET"))
?.let { webhookSecret(it) }
+ System.getenv("IMAGE_KIT_CUSTOM_HEADERS")?.let { customHeadersEnv ->
+ for (line in customHeadersEnv.split("\n")) {
+ val colon = line.indexOf(':')
+ if (colon >= 0) {
+ putHeader(line.substring(0, colon).trim(), line.substring(colon + 1).trim())
+ }
+ }
+ }
}
/**
@@ -483,7 +518,13 @@ private constructor(
return ClientOptions(
httpClient,
RetryingHttpClient.builder()
- .httpClient(httpClient)
+ .httpClient(
+ LoggingHttpClient.builder()
+ .httpClient(httpClient)
+ .clock(clock)
+ .level(logLevel)
+ .build()
+ )
.sleeper(sleeper)
.clock(clock)
.maxRetries(maxRetries)
@@ -498,6 +539,7 @@ private constructor(
responseValidation,
timeout,
maxRetries,
+ logLevel,
privateKey,
password,
webhookSecret,
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/core/LogLevel.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/core/LogLevel.kt
new file mode 100644
index 00000000..48a93636
--- /dev/null
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/core/LogLevel.kt
@@ -0,0 +1,33 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package io.imagekit.core
+
+/** The level at which to log request and response information. */
+enum class LogLevel {
+ /** No logging. */
+ OFF,
+ /** Minimal request and response summary logs. No headers or bodies are logged. */
+ INFO,
+ /** [INFO] logs plus details about request failures. */
+ ERROR,
+ /**
+ * Full request and response logs. Sensitive headers are redacted, but sensitive data in request
+ * and response bodies may still be visible.
+ */
+ DEBUG;
+
+ /** Returns whether this level is at or higher than the given [level]. */
+ fun shouldLog(level: LogLevel): Boolean = ordinal >= level.ordinal
+
+ companion object {
+
+ /** Returns a [LogLevel] based on the `IMAGE_KIT_LOG` environment variable. */
+ fun fromEnv() =
+ when (System.getenv("IMAGE_KIT_LOG")?.lowercase()) {
+ "info" -> INFO
+ "error" -> ERROR
+ "debug" -> DEBUG
+ else -> OFF
+ }
+ }
+}
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/core/ObjectMappers.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/core/ObjectMappers.kt
index 8c7bf11c..fab56ddf 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/core/ObjectMappers.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/core/ObjectMappers.kt
@@ -29,7 +29,9 @@ import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoField
-fun jsonMapper(): JsonMapper =
+fun jsonMapper(): JsonMapper = JSON_MAPPER
+
+private val JSON_MAPPER: JsonMapper =
JsonMapper.builder()
.addModule(kotlinModule())
.addModule(Jdk8Module())
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/core/RequestOptions.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/core/RequestOptions.kt
index ec271554..65c183e9 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/core/RequestOptions.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/core/RequestOptions.kt
@@ -33,6 +33,15 @@ class RequestOptions private constructor(val responseValidation: Boolean?, val t
private var responseValidation: Boolean? = null
private var timeout: Timeout? = null
+ /**
+ * Whether to call `validate` on the response before returning it.
+ *
+ * Setting this to `true` is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * Defaults to false, which means the shape of the response will not be validated upfront.
+ * Instead, validation will only occur for the parts of the response that are accessed.
+ */
fun responseValidation(responseValidation: Boolean) = apply {
this.responseValidation = responseValidation
}
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/core/Utils.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/core/Utils.kt
index a847bd3c..80a24c57 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/core/Utils.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/core/Utils.kt
@@ -5,6 +5,7 @@ package io.imagekit.core
import io.imagekit.errors.ImageKitInvalidDataException
import java.util.Collections
import java.util.SortedMap
+import java.util.SortedSet
import java.util.concurrent.CompletableFuture
import java.util.concurrent.locks.Lock
@@ -16,6 +17,11 @@ internal fun T?.getOrThrow(name: String): T =
internal fun List.toImmutable(): List =
if (isEmpty()) Collections.emptyList() else Collections.unmodifiableList(toList())
+@JvmSynthetic
+internal fun > SortedSet.toImmutable(): SortedSet =
+ if (isEmpty()) Collections.emptySortedSet()
+ else Collections.unmodifiableSortedSet(toSortedSet(comparator() ?: Comparator.naturalOrder()))
+
@JvmSynthetic
internal fun Map.toImmutable(): Map =
if (isEmpty()) immutableEmptyMap() else Collections.unmodifiableMap(toMap())
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/core/http/LoggingHttpClient.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/core/http/LoggingHttpClient.kt
new file mode 100644
index 00000000..d06fdf77
--- /dev/null
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/core/http/LoggingHttpClient.kt
@@ -0,0 +1,627 @@
+// File generated from our OpenAPI spec by Stainless.
+
+package io.imagekit.core.http
+
+import io.imagekit.core.LogLevel
+import io.imagekit.core.RequestOptions
+import io.imagekit.core.checkRequired
+import io.imagekit.core.toImmutable
+import java.io.ByteArrayOutputStream
+import java.io.InputStream
+import java.io.OutputStream
+import java.nio.ByteBuffer
+import java.nio.charset.CharacterCodingException
+import java.nio.charset.Charset
+import java.nio.charset.CharsetDecoder
+import java.nio.charset.CodingErrorAction
+import java.nio.charset.StandardCharsets
+import java.time.Clock
+import java.time.Duration
+import java.time.OffsetDateTime
+import java.util.SortedSet
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.CompletionException
+import kotlin.time.toKotlinDuration
+
+/** A wrapper [HttpClient] around [httpClient] that logs request and response information. */
+class LoggingHttpClient
+private constructor(
+ /** The underlying [HttpClient] for making requests. */
+ @get:JvmName("httpClient") val httpClient: HttpClient,
+ /**
+ * Sensitive headers to redact from logs.
+ *
+ * Defaults to `Set.of("Authorization")`.
+ */
+ @get:JvmName("redactedHeaders") val redactedHeaders: SortedSet,
+ /**
+ * The clock to use for measuring request and response durations.
+ *
+ * This is primarily useful for using a fake clock in tests.
+ *
+ * Defaults to [Clock.systemUTC].
+ */
+ @get:JvmName("clock") val clock: Clock,
+ /**
+ * The log level to use.
+ *
+ * Pass [LogLevel.fromEnv] to read from environment variables.
+ */
+ @get:JvmName("level") val level: LogLevel,
+) : HttpClient {
+
+ override fun execute(request: HttpRequest, requestOptions: RequestOptions): HttpResponse {
+ val loggingRequest = logRequest(request)
+
+ val before = OffsetDateTime.now(clock)
+ val response =
+ try {
+ httpClient.execute(loggingRequest, requestOptions)
+ } catch (e: Throwable) {
+ logFailure(e, Duration.between(before, OffsetDateTime.now(clock)))
+ throw e
+ }
+
+ val took = Duration.between(before, OffsetDateTime.now(clock))
+ return logResponse(response, took)
+ }
+
+ override fun executeAsync(
+ request: HttpRequest,
+ requestOptions: RequestOptions,
+ ): CompletableFuture {
+ val loggingRequest = logRequest(request)
+
+ val before = OffsetDateTime.now(clock)
+ val future =
+ try {
+ httpClient.executeAsync(loggingRequest, requestOptions)
+ } catch (e: Throwable) {
+ logFailure(e, Duration.between(before, OffsetDateTime.now(clock)))
+ throw e
+ }
+ return future.handle { response, error ->
+ val took = Duration.between(before, OffsetDateTime.now(clock))
+ if (error != null) {
+ logFailure(unwrapCompletionException(error), took)
+ throw error
+ }
+ logResponse(response, took)
+ }
+ }
+
+ private fun logRequest(request: HttpRequest): HttpRequest {
+ if (!level.shouldLog(LogLevel.INFO)) {
+ return request
+ }
+
+ System.err.println(
+ buildString {
+ append("--> ${request.method} ${request.url()}")
+ request.body?.let {
+ val length = it.contentLength()
+ append(if (length >= 0) " ($length-byte body)" else " (unknown-length body)")
+ }
+ }
+ )
+
+ if (!level.shouldLog(LogLevel.DEBUG)) {
+ return request
+ }
+
+ logHeaders(request.headers)
+
+ if (request.body == null) {
+ System.err.println("--> END ${request.method}")
+ System.err.println()
+ return request
+ }
+
+ return request
+ .toBuilder()
+ .body(LoggingHttpRequestBody(request.method, request.body))
+ .build()
+ }
+
+ private fun logResponse(response: HttpResponse, took: Duration): HttpResponse {
+ if (!level.shouldLog(LogLevel.INFO)) {
+ return response
+ }
+
+ val contentLength = response.headers().values("Content-Length").firstOrNull()?.toIntOrNull()
+ System.err.println(
+ "<-- ${response.statusCode()} (${
+ buildString {
+ append(took.format())
+ contentLength?.let { append(", $contentLength-byte body") }
+ }
+ })"
+ )
+
+ if (!level.shouldLog(LogLevel.DEBUG)) {
+ return response
+ }
+
+ logHeaders(response.headers())
+ return LoggingHttpResponse(response)
+ }
+
+ private fun logFailure(error: Throwable, took: Duration) {
+ if (!level.shouldLog(LogLevel.ERROR)) {
+ return
+ }
+
+ System.err.println(
+ buildString {
+ append("<-- !! ${error.javaClass.simpleName}")
+ error.message?.let { append(": $it") }
+ append(" (${took.format()})")
+ }
+ )
+ }
+
+ private fun unwrapCompletionException(error: Throwable): Throwable =
+ if (error is CompletionException && error.cause != null) error.cause!! else error
+
+ private fun logHeaders(headers: Headers) =
+ headers.names().forEach { name ->
+ headers.values(name).forEach { value ->
+ System.err.println("$name: ${if (redactedHeaders.contains(name)) "██" else value}")
+ }
+ }
+
+ override fun close() = httpClient.close()
+
+ fun toBuilder() = Builder().from(this)
+
+ companion object {
+
+ /**
+ * Returns a mutable builder for constructing an instance of [LoggingHttpClient].
+ *
+ * The following fields are required:
+ * ```java
+ * .httpClient()
+ * .level()
+ * ```
+ */
+ @JvmStatic fun builder() = Builder()
+ }
+
+ /** A builder for [LoggingHttpClient]. */
+ class Builder internal constructor() {
+
+ private var httpClient: HttpClient? = null
+ private var redactedHeaders: Set = setOf("Authorization")
+ private var clock: Clock = Clock.systemUTC()
+ private var level: LogLevel? = null
+
+ @JvmSynthetic
+ internal fun from(loggingHttpClient: LoggingHttpClient) = apply {
+ httpClient = loggingHttpClient.httpClient
+ redactedHeaders = loggingHttpClient.redactedHeaders
+ clock = loggingHttpClient.clock
+ level = loggingHttpClient.level
+ }
+
+ /** The underlying [HttpClient] for making requests. */
+ fun httpClient(httpClient: HttpClient) = apply { this.httpClient = httpClient }
+
+ /**
+ * Sensitive headers to redact from logs.
+ *
+ * Defaults to `Set.of("Authorization")`.
+ */
+ fun redactedHeaders(redactedHeaders: Set) = apply {
+ this.redactedHeaders = redactedHeaders
+ }
+
+ /**
+ * The clock to use for measuring request and response durations.
+ *
+ * This is primarily useful for using a fake clock in tests.
+ *
+ * Defaults to [Clock.systemUTC].
+ */
+ fun clock(clock: Clock) = apply { this.clock = clock }
+
+ /**
+ * The log level to use.
+ *
+ * Pass [LogLevel.fromEnv] to read from environment variables.
+ */
+ fun level(level: LogLevel) = apply { this.level = level }
+
+ /**
+ * Returns an immutable instance of [LoggingHttpClient].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ *
+ * The following fields are required:
+ * ```java
+ * .httpClient()
+ * .level()
+ * ```
+ *
+ * @throws IllegalStateException if any required field is unset.
+ */
+ fun build(): LoggingHttpClient =
+ LoggingHttpClient(
+ checkRequired("httpClient", httpClient),
+ redactedHeaders.toSortedSet(String.CASE_INSENSITIVE_ORDER).toImmutable(),
+ clock,
+ checkRequired("level", level),
+ )
+ }
+}
+
+/**
+ * An [HttpRequestBody] wrapper that delegates to [body] while also logging line by line as it's
+ * written.
+ *
+ * The logging occurs in a streaming manner with minimal buffering.
+ */
+private class LoggingHttpRequestBody(
+ private val method: HttpMethod,
+ private val body: HttpRequestBody,
+) : HttpRequestBody {
+
+ private val charset by lazy { parseCharset(body.contentType()) }
+
+ override fun writeTo(outputStream: OutputStream) {
+ val loggingOutputStream = LoggingOutputStream(outputStream, charset)
+ body.writeTo(loggingOutputStream)
+
+ loggingOutputStream.flush()
+ System.err.println("--> END $method (${loggingOutputStream.writeCount()}-byte body)")
+ System.err.println()
+ }
+
+ override fun contentType(): String? = body.contentType()
+
+ override fun contentLength(): Long = body.contentLength()
+
+ override fun repeatable(): Boolean = body.repeatable()
+
+ override fun close() = body.close()
+}
+
+/**
+ * An [OutputStream] wrapper that delegates to [outputStream] while also logging bytes line by line
+ * as it's written to.
+ *
+ * The written content is assumed to be in the given [charset] and the logging occurs in a streaming
+ * manner with minimal buffering.
+ */
+private class LoggingOutputStream(private val outputStream: OutputStream, charset: Charset?) :
+ OutputStream() {
+
+ private val buffer = LoggingBuffer(charset)
+
+ fun writeCount() = buffer.writeCount()
+
+ override fun write(b: Int) {
+ outputStream.write(b)
+ buffer.write(b)
+ }
+
+ override fun write(b: ByteArray, off: Int, len: Int) {
+ outputStream.write(b, off, len)
+ for (i in off until off + len) {
+ buffer.write(b[i].toInt() and 0xFF)
+ }
+ }
+
+ /** Prints any currently buffered content. */
+ override fun flush() {
+ buffer.flush()
+ outputStream.flush()
+ }
+
+ override fun close() = outputStream.close()
+}
+
+/**
+ * An [HttpResponse] wrapper that delegates to [response] while also logging line-by-line as it's
+ * read.
+ *
+ * The logging occurs in a streaming manner with minimal buffering.
+ */
+private class LoggingHttpResponse(private val response: HttpResponse) : HttpResponse {
+
+ private val loggingBody: Lazy = lazy {
+ LoggingInputStream(
+ response.body(),
+ parseCharset(response.headers().values("Content-Type").firstOrNull()),
+ )
+ }
+
+ override fun statusCode(): Int = response.statusCode()
+
+ override fun headers(): Headers = response.headers()
+
+ override fun body(): InputStream = loggingBody.value
+
+ override fun close() {
+ if (loggingBody.isInitialized()) {
+ loggingBody.value.close()
+ }
+ response.close()
+ }
+}
+
+/**
+ * An [InputStream] wrapper that delegates to [inputStream] while also logging bytes line by line as
+ * it's read.
+ *
+ * The contents of [inputStream] are assumed to be in the given [charset] and the logging occurs in
+ * a streaming manner with minimal buffering.
+ */
+private class LoggingInputStream(private val inputStream: InputStream, charset: Charset?) :
+ InputStream() {
+
+ private var isDone = false
+ private val buffer = LoggingBuffer(charset)
+
+ override fun read(): Int {
+ if (isDone) {
+ return -1
+ }
+
+ val b = inputStream.read()
+
+ if (b == -1) {
+ markDone()
+ return b
+ }
+
+ buffer.write(b)
+ return b
+ }
+
+ override fun read(b: ByteArray, off: Int, len: Int): Int {
+ if (isDone) {
+ return -1
+ }
+
+ val bytesRead = inputStream.read(b, off, len)
+
+ if (bytesRead == -1) {
+ markDone()
+ return bytesRead
+ }
+
+ for (i in off until off + bytesRead) {
+ buffer.write(b[i].toInt() and 0xFF)
+ }
+ return bytesRead
+ }
+
+ override fun close() {
+ if (!isDone) {
+ markDone(closedEarly = true)
+ }
+ inputStream.close()
+ }
+
+ private fun markDone(closedEarly: Boolean = false) {
+ isDone = true
+ buffer.flush()
+ val suffix = if (closedEarly) ", closed early" else ""
+ System.err.println("<-- END HTTP (${buffer.writeCount()}-byte body$suffix)")
+ System.err.println()
+ }
+}
+
+/**
+ * A byte buffer that prints line by line, using the given [charset], as bytes are written to it.
+ *
+ * When [charset] is `null`, the buffer performs an upfront check to detect binary content. If
+ * non-whitespace ISO control characters are found in the first [PROBABLY_UTF8_CODE_POINT_LIMIT]
+ * code points, body logging is suppressed entirely.
+ */
+private class LoggingBuffer(charset: Charset?) {
+
+ private val charset = charset ?: StandardCharsets.UTF_8
+
+ private val decoder: CharsetDecoder =
+ this.charset
+ .newDecoder()
+ .onMalformedInput(CodingErrorAction.REPORT)
+ .onUnmappableCharacter(CodingErrorAction.REPORT)
+ private var writeCount = 0
+ private val buffer = ByteArrayOutputStream(128)
+
+ /**
+ * Whether logging has been suppressed because the content doesn't appear to be readable text.
+ *
+ * This is only set when [charset] is `null` and the content fails the [isProbablyUtf8] check.
+ */
+ private var suppressed = false
+
+ /**
+ * Bytes accumulated for the [isProbablyUtf8] check before any lines are printed.
+ *
+ * Once the check passes (or [charset] is non-null), this is set to `null` and bytes flow
+ * directly to [buffer].
+ */
+ private var prefetchBuffer: ByteArrayOutputStream? =
+ if (charset != null) null else ByteArrayOutputStream(128)
+
+ fun writeCount() = writeCount
+
+ fun write(b: Int) {
+ if (writeCount == 0) {
+ // Print a newline before we start printing anything to separate the printed content
+ // from previous content.
+ System.err.println()
+ }
+
+ writeCount++
+
+ if (suppressed) {
+ return
+ }
+
+ val prefetch = prefetchBuffer
+ if (prefetch != null) {
+ prefetch.write(b)
+ // Continue accumulating until we have enough bytes to decide.
+ if (prefetch.size() < PROBABLY_UTF8_BYTE_LIMIT && b != '\n'.code) {
+ return
+ }
+ // We have enough bytes. Check if the content is probably UTF-8.
+ prefetchBuffer = null
+ val bytes = prefetch.toByteArray()
+ if (!isProbablyUtf8(bytes)) {
+ suppressed = true
+ System.err.println("(binary body omitted)")
+ return
+ }
+ // Content looks like UTF-8. Feed the accumulated bytes into the normal buffer.
+ for (byte in bytes) {
+ writeToBuffer(byte.toInt() and 0xFF)
+ }
+ return
+ }
+
+ writeToBuffer(b)
+ }
+
+ private fun writeToBuffer(b: Int) {
+ if (b == '\n'.code) {
+ flush()
+ return
+ }
+
+ buffer.write(b)
+ }
+
+ /** Prints any currently buffered content. */
+ fun flush() {
+ if (suppressed) {
+ return
+ }
+
+ // If we still have a prefetch buffer when flush is called (body was shorter than the
+ // limit), run the check now.
+ val prefetch = prefetchBuffer
+ if (prefetch != null) {
+ prefetchBuffer = null
+ val bytes = prefetch.toByteArray()
+ if (bytes.isEmpty()) {
+ return
+ }
+ if (!isProbablyUtf8(bytes)) {
+ suppressed = true
+ System.err.println("(binary body omitted)")
+ return
+ }
+ for (byte in bytes) {
+ writeToBuffer(byte.toInt() and 0xFF)
+ }
+ }
+
+ if (buffer.size() == 0) {
+ return
+ }
+
+ val line =
+ try {
+ decoder.decode(ByteBuffer.wrap(buffer.toByteArray()))
+ } catch (e: CharacterCodingException) {
+ "(omitted line is not valid $charset)"
+ }
+ buffer.reset()
+ System.err.println(line)
+ }
+}
+
+/** The maximum number of code points to sample when checking if content is probably UTF-8. */
+private const val PROBABLY_UTF8_CODE_POINT_LIMIT = 64
+
+/**
+ * The maximum number of bytes to accumulate before running the [isProbablyUtf8] check. UTF-8 code
+ * points are at most 4 bytes, so this accommodates [PROBABLY_UTF8_CODE_POINT_LIMIT] code points.
+ */
+private const val PROBABLY_UTF8_BYTE_LIMIT = PROBABLY_UTF8_CODE_POINT_LIMIT * 4
+
+/**
+ * Returns `true` if the given [bytes] probably contain human-readable UTF-8 text.
+ *
+ * Decodes up to [PROBABLY_UTF8_CODE_POINT_LIMIT] code points and returns `false` if any
+ * non-whitespace ISO control characters are found, or if the bytes are not valid UTF-8.
+ */
+private fun isProbablyUtf8(bytes: ByteArray): Boolean {
+ try {
+ val decoder =
+ StandardCharsets.UTF_8.newDecoder()
+ .onMalformedInput(CodingErrorAction.REPORT)
+ .onUnmappableCharacter(CodingErrorAction.REPORT)
+ val charBuffer = decoder.decode(ByteBuffer.wrap(bytes))
+ var codePointCount = 0
+ var i = 0
+ while (i < charBuffer.length && codePointCount < PROBABLY_UTF8_CODE_POINT_LIMIT) {
+ val codePoint = Character.codePointAt(charBuffer, i)
+ if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
+ return false
+ }
+ i += Character.charCount(codePoint)
+ codePointCount++
+ }
+ return true
+ } catch (e: CharacterCodingException) {
+ return false
+ }
+}
+
+/** Returns the [Charset] in the given [contentType] string, or `null` if unspecified. */
+private fun parseCharset(contentType: String?): Charset? =
+ contentType
+ ?.split(";")
+ ?.drop(1)
+ ?.map { it.trim() }
+ ?.firstOrNull { it.startsWith("charset=", ignoreCase = true) }
+ ?.substringAfter("=")
+ ?.trim()
+ ?.removeSurrounding("\"")
+ ?.let { runCatching { charset(it) }.getOrNull() }
+
+/** Formats the [Duration] into a string like "1m 40s 467ms". */
+private fun Duration.format(): String =
+ toKotlinDuration().toComponents { days, hours, minutes, seconds, nanoseconds ->
+ buildString {
+ val milliseconds = nanoseconds / 1_000_000
+ if (days > 0) {
+ append("${days}d")
+ }
+ if (hours > 0) {
+ if (isNotEmpty()) {
+ append(" ")
+ }
+ append("${hours}h")
+ }
+ if (minutes > 0) {
+ if (isNotEmpty()) {
+ append(" ")
+ }
+ append("${minutes}m")
+ }
+ if (seconds > 0) {
+ if (isNotEmpty()) {
+ append(" ")
+ }
+ append("${seconds}s")
+ }
+ if (milliseconds > 0) {
+ if (isNotEmpty()) {
+ append(" ")
+ }
+ append("${milliseconds}ms")
+ }
+
+ if (isEmpty()) {
+ append("0s")
+ }
+ }
+ }
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/core/http/ProxyAuthenticator.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/core/http/ProxyAuthenticator.kt
new file mode 100644
index 00000000..32c1c5c5
--- /dev/null
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/core/http/ProxyAuthenticator.kt
@@ -0,0 +1,59 @@
+package io.imagekit.core.http
+
+import java.net.Proxy
+import java.nio.charset.Charset
+import java.nio.charset.StandardCharsets
+import java.util.Base64
+import java.util.Optional
+
+/**
+ * Provides credentials when an HTTP proxy responds with `407 Proxy Authentication Required`.
+ *
+ * Implementations inspect the 407 [response] (typically its `Proxy-Authenticate` header) and return
+ * the request to retry with a `Proxy-Authorization` header set, or [Optional.empty] to abandon
+ * authentication and surface the 407 to the caller.
+ *
+ * Implementations must be thread-safe; they may be invoked concurrently from multiple HTTP calls.
+ */
+fun interface ProxyAuthenticator {
+
+ /**
+ * @param proxy the proxy that produced the challenge, or [Proxy.NO_PROXY] if the route is not
+ * yet established
+ * @param request the request that produced [response]
+ * @param response the 407 challenge response
+ * @return the retry request to send (typically [request] with a `Proxy-Authorization` header
+ * added), or [Optional.empty] to abandon authentication
+ */
+ fun authenticate(
+ proxy: Proxy,
+ request: HttpRequest,
+ response: HttpResponse,
+ ): Optional
+
+ companion object {
+
+ /**
+ * A [ProxyAuthenticator] that uses RFC 7617 Basic authentication with the ISO-8859-1
+ * charset.
+ */
+ @JvmStatic
+ fun basic(username: String, password: String): ProxyAuthenticator =
+ basic(username, password, StandardCharsets.ISO_8859_1)
+
+ /**
+ * A [ProxyAuthenticator] that uses RFC 7617 Basic authentication with the given [charset].
+ */
+ @JvmStatic
+ fun basic(username: String, password: String, charset: Charset): ProxyAuthenticator {
+ val token =
+ Base64.getEncoder().encodeToString("$username:$password".toByteArray(charset))
+ val headerValue = "Basic $token"
+ return ProxyAuthenticator { _, request, _ ->
+ Optional.of(
+ request.toBuilder().putHeader("Proxy-Authorization", headerValue).build()
+ )
+ }
+ }
+ }
+}
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/errors/BadRequestException.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/errors/BadRequestException.kt
index a2d14b65..b578dab8 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/errors/BadRequestException.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/errors/BadRequestException.kt
@@ -5,12 +5,16 @@ package io.imagekit.errors
import io.imagekit.core.JsonValue
import io.imagekit.core.checkRequired
import io.imagekit.core.http.Headers
+import io.imagekit.core.jsonMapper
import java.util.Optional
import kotlin.jvm.optionals.getOrNull
class BadRequestException
private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) :
- ImageKitServiceException("400: $body", cause) {
+ ImageKitServiceException(
+ "400: ${if (body.isMissing()) "Unknown" else jsonMapper().writeValueAsString(body)}",
+ cause,
+ ) {
override fun statusCode(): Int = 400
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/errors/InternalServerException.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/errors/InternalServerException.kt
index a121ff83..bc02fae2 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/errors/InternalServerException.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/errors/InternalServerException.kt
@@ -5,6 +5,7 @@ package io.imagekit.errors
import io.imagekit.core.JsonValue
import io.imagekit.core.checkRequired
import io.imagekit.core.http.Headers
+import io.imagekit.core.jsonMapper
import java.util.Optional
import kotlin.jvm.optionals.getOrNull
@@ -14,7 +15,11 @@ private constructor(
private val headers: Headers,
private val body: JsonValue,
cause: Throwable?,
-) : ImageKitServiceException("$statusCode: $body", cause) {
+) :
+ ImageKitServiceException(
+ "$statusCode: ${if (body.isMissing()) "Unknown" else jsonMapper().writeValueAsString(body)}",
+ cause,
+ ) {
override fun statusCode(): Int = statusCode
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/errors/NotFoundException.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/errors/NotFoundException.kt
index 41721640..5fd12fa9 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/errors/NotFoundException.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/errors/NotFoundException.kt
@@ -5,12 +5,16 @@ package io.imagekit.errors
import io.imagekit.core.JsonValue
import io.imagekit.core.checkRequired
import io.imagekit.core.http.Headers
+import io.imagekit.core.jsonMapper
import java.util.Optional
import kotlin.jvm.optionals.getOrNull
class NotFoundException
private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) :
- ImageKitServiceException("404: $body", cause) {
+ ImageKitServiceException(
+ "404: ${if (body.isMissing()) "Unknown" else jsonMapper().writeValueAsString(body)}",
+ cause,
+ ) {
override fun statusCode(): Int = 404
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/errors/PermissionDeniedException.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/errors/PermissionDeniedException.kt
index 6d1e3e35..39280b60 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/errors/PermissionDeniedException.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/errors/PermissionDeniedException.kt
@@ -5,12 +5,16 @@ package io.imagekit.errors
import io.imagekit.core.JsonValue
import io.imagekit.core.checkRequired
import io.imagekit.core.http.Headers
+import io.imagekit.core.jsonMapper
import java.util.Optional
import kotlin.jvm.optionals.getOrNull
class PermissionDeniedException
private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) :
- ImageKitServiceException("403: $body", cause) {
+ ImageKitServiceException(
+ "403: ${if (body.isMissing()) "Unknown" else jsonMapper().writeValueAsString(body)}",
+ cause,
+ ) {
override fun statusCode(): Int = 403
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/errors/RateLimitException.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/errors/RateLimitException.kt
index 5f369cf4..febee946 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/errors/RateLimitException.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/errors/RateLimitException.kt
@@ -5,12 +5,16 @@ package io.imagekit.errors
import io.imagekit.core.JsonValue
import io.imagekit.core.checkRequired
import io.imagekit.core.http.Headers
+import io.imagekit.core.jsonMapper
import java.util.Optional
import kotlin.jvm.optionals.getOrNull
class RateLimitException
private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) :
- ImageKitServiceException("429: $body", cause) {
+ ImageKitServiceException(
+ "429: ${if (body.isMissing()) "Unknown" else jsonMapper().writeValueAsString(body)}",
+ cause,
+ ) {
override fun statusCode(): Int = 429
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/errors/UnauthorizedException.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/errors/UnauthorizedException.kt
index 13bbfbc6..08b10b6d 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/errors/UnauthorizedException.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/errors/UnauthorizedException.kt
@@ -5,12 +5,16 @@ package io.imagekit.errors
import io.imagekit.core.JsonValue
import io.imagekit.core.checkRequired
import io.imagekit.core.http.Headers
+import io.imagekit.core.jsonMapper
import java.util.Optional
import kotlin.jvm.optionals.getOrNull
class UnauthorizedException
private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) :
- ImageKitServiceException("401: $body", cause) {
+ ImageKitServiceException(
+ "401: ${if (body.isMissing()) "Unknown" else jsonMapper().writeValueAsString(body)}",
+ cause,
+ ) {
override fun statusCode(): Int = 401
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/errors/UnexpectedStatusCodeException.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/errors/UnexpectedStatusCodeException.kt
index 9bc1ddf3..1efd7ae6 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/errors/UnexpectedStatusCodeException.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/errors/UnexpectedStatusCodeException.kt
@@ -5,6 +5,7 @@ package io.imagekit.errors
import io.imagekit.core.JsonValue
import io.imagekit.core.checkRequired
import io.imagekit.core.http.Headers
+import io.imagekit.core.jsonMapper
import java.util.Optional
import kotlin.jvm.optionals.getOrNull
@@ -14,7 +15,11 @@ private constructor(
private val headers: Headers,
private val body: JsonValue,
cause: Throwable?,
-) : ImageKitServiceException("$statusCode: $body", cause) {
+) :
+ ImageKitServiceException(
+ "$statusCode: ${if (body.isMissing()) "Unknown" else jsonMapper().writeValueAsString(body)}",
+ cause,
+ ) {
override fun statusCode(): Int = statusCode
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/errors/UnprocessableEntityException.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/errors/UnprocessableEntityException.kt
index 61554585..ee979042 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/errors/UnprocessableEntityException.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/errors/UnprocessableEntityException.kt
@@ -5,12 +5,16 @@ package io.imagekit.errors
import io.imagekit.core.JsonValue
import io.imagekit.core.checkRequired
import io.imagekit.core.http.Headers
+import io.imagekit.core.jsonMapper
import java.util.Optional
import kotlin.jvm.optionals.getOrNull
class UnprocessableEntityException
private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) :
- ImageKitServiceException("422: $body", cause) {
+ ImageKitServiceException(
+ "422: ${if (body.isMissing()) "Unknown" else jsonMapper().writeValueAsString(body)}",
+ cause,
+ ) {
override fun statusCode(): Int = 422
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/AiTag.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/AiTag.kt
index 7bbe153f..aea4c5fa 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/AiTag.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/AiTag.kt
@@ -179,6 +179,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): AiTag = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/BaseOverlay.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/BaseOverlay.kt
index 6204419e..851e9de2 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/BaseOverlay.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/BaseOverlay.kt
@@ -223,6 +223,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): BaseOverlay = apply {
if (validated) {
return@apply
@@ -373,6 +381,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): LayerMode = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/CustomMetadata.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/CustomMetadata.kt
index 69181dc1..0198066b 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/CustomMetadata.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/CustomMetadata.kt
@@ -69,6 +69,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): CustomMetadata = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/EmbeddedMetadata.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/EmbeddedMetadata.kt
index 9ff9cf92..9257c90e 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/EmbeddedMetadata.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/EmbeddedMetadata.kt
@@ -71,6 +71,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): EmbeddedMetadata = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/ExtensionConfig.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/ExtensionConfig.kt
index 98a263ac..41001c11 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/ExtensionConfig.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/ExtensionConfig.kt
@@ -71,6 +71,35 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API, unless
+ * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of the
+ * SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = extensionConfig.accept(new ExtensionConfig.Visitor>() {
+ * @Override
+ * public Optional visitRemoveBg(RemoveBg removeBg) {
+ * return Optional.of(removeBg.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in [visitor] and
+ * the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
removeBg != null -> visitor.visitRemoveBg(removeBg)
@@ -82,6 +111,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): ExtensionConfig = apply {
if (validated) {
return@apply
@@ -395,6 +432,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): RemoveBg = apply {
if (validated) {
return@apply
@@ -669,6 +715,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing
+ * fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match
+ * its expected type.
+ */
fun validate(): Options = apply {
if (validated) {
return@apply
@@ -935,6 +991,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): AutoTaggingExtension = apply {
if (validated) {
return@apply
@@ -1056,6 +1121,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing
+ * fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match
+ * its expected type.
+ */
fun validate(): Name = apply {
if (validated) {
return@apply
@@ -1310,6 +1385,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): AiTasks = apply {
if (validated) {
return@apply
@@ -1373,6 +1457,36 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given
+ * [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API,
+ * unless [visitor] overrides [Visitor.unknown]. To handle variants not known to this
+ * version of the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = task.accept(new Task.Visitor>() {
+ * @Override
+ * public Optional visitSelectTags(SelectTags selectTags) {
+ * return Optional.of(selectTags.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in
+ * [visitor] and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
selectTags != null -> visitor.visitSelectTags(selectTags)
@@ -1383,6 +1497,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing
+ * fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match
+ * its expected type.
+ */
fun validate(): Task = apply {
if (validated) {
return@apply
@@ -1843,6 +1967,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing
+ * fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't
+ * match its expected type.
+ */
fun validate(): SelectTags = apply {
if (validated) {
return@apply
@@ -2271,6 +2405,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing
+ * fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't
+ * match its expected type.
+ */
fun validate(): SelectMetadata = apply {
if (validated) {
return@apply
@@ -2342,6 +2486,37 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given
+ * [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the
+ * API, unless [visitor] overrides [Visitor.unknown]. To handle variants not
+ * known to this version of the SDK gracefully, consider overriding
+ * [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = vocabulary.accept(new Vocabulary.Visitor>() {
+ * @Override
+ * public Optional visitString(String string) {
+ * return Optional.of(string.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden
+ * in [visitor] and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
string != null -> visitor.visitString(string)
@@ -2352,6 +2527,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected
+ * types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't
+ * match its expected type.
+ */
fun validate(): Vocabulary = apply {
if (validated) {
return@apply
@@ -2807,6 +2992,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing
+ * fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't
+ * match its expected type.
+ */
fun validate(): YesNo = apply {
if (validated) {
return@apply
@@ -3134,6 +3329,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected
+ * types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't
+ * match its expected type.
+ */
fun validate(): OnNo = apply {
if (validated) {
return@apply
@@ -3355,6 +3560,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object
+ * doesn't match its expected type.
+ */
fun validate(): SetMetadata = apply {
if (validated) {
return@apply
@@ -3426,6 +3641,37 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the
+ * given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants
+ * from the API, unless [visitor] overrides [Visitor.unknown]. To handle
+ * variants not known to this version of the SDK gracefully, consider
+ * overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = value.accept(new Value.Visitor>() {
+ * @Override
+ * public Optional visitString(String string) {
+ * return Optional.of(string.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not
+ * overridden in [visitor] and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
string != null -> visitor.visitString(string)
@@ -3437,6 +3683,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API
+ * for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object
+ * doesn't match its expected type.
+ */
fun validate(): Value = apply {
if (validated) {
return@apply
@@ -3642,6 +3898,37 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using
+ * the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new
+ * variants from the API, unless [visitor] overrides
+ * [Visitor.unknown]. To handle variants not known to this version
+ * of the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = metadataValueItem.accept(new MetadataValueItem.Visitor>() {
+ * @Override
+ * public Optional visitString(String string) {
+ * return Optional.of(string.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not
+ * overridden in [visitor] and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
string != null -> visitor.visitString(string)
@@ -3652,6 +3939,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the
+ * API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this
+ * object doesn't match its expected type.
+ */
fun validate(): MetadataValueItem = apply {
if (validated) {
return@apply
@@ -3994,6 +4291,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object
+ * doesn't match its expected type.
+ */
fun validate(): UnsetMetadata = apply {
if (validated) {
return@apply
@@ -4359,6 +4666,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected
+ * types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't
+ * match its expected type.
+ */
fun validate(): OnUnknown = apply {
if (validated) {
return@apply
@@ -4580,6 +4897,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object
+ * doesn't match its expected type.
+ */
fun validate(): SetMetadata = apply {
if (validated) {
return@apply
@@ -4651,6 +4978,37 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the
+ * given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants
+ * from the API, unless [visitor] overrides [Visitor.unknown]. To handle
+ * variants not known to this version of the SDK gracefully, consider
+ * overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = value.accept(new Value.Visitor>() {
+ * @Override
+ * public Optional visitString(String string) {
+ * return Optional.of(string.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not
+ * overridden in [visitor] and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
string != null -> visitor.visitString(string)
@@ -4662,6 +5020,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API
+ * for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object
+ * doesn't match its expected type.
+ */
fun validate(): Value = apply {
if (validated) {
return@apply
@@ -4867,6 +5235,37 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using
+ * the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new
+ * variants from the API, unless [visitor] overrides
+ * [Visitor.unknown]. To handle variants not known to this version
+ * of the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = metadataValueItem.accept(new MetadataValueItem.Visitor>() {
+ * @Override
+ * public Optional visitString(String string) {
+ * return Optional.of(string.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not
+ * overridden in [visitor] and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
string != null -> visitor.visitString(string)
@@ -4877,6 +5276,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the
+ * API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this
+ * object doesn't match its expected type.
+ */
fun validate(): MetadataValueItem = apply {
if (validated) {
return@apply
@@ -5219,6 +5628,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object
+ * doesn't match its expected type.
+ */
fun validate(): UnsetMetadata = apply {
if (validated) {
return@apply
@@ -5582,6 +6001,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected
+ * types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't
+ * match its expected type.
+ */
fun validate(): OnYes = apply {
if (validated) {
return@apply
@@ -5803,6 +6232,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object
+ * doesn't match its expected type.
+ */
fun validate(): SetMetadata = apply {
if (validated) {
return@apply
@@ -5874,6 +6313,37 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the
+ * given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants
+ * from the API, unless [visitor] overrides [Visitor.unknown]. To handle
+ * variants not known to this version of the SDK gracefully, consider
+ * overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = value.accept(new Value.Visitor>() {
+ * @Override
+ * public Optional visitString(String string) {
+ * return Optional.of(string.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not
+ * overridden in [visitor] and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
string != null -> visitor.visitString(string)
@@ -5885,6 +6355,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API
+ * for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object
+ * doesn't match its expected type.
+ */
fun validate(): Value = apply {
if (validated) {
return@apply
@@ -6090,6 +6570,37 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using
+ * the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new
+ * variants from the API, unless [visitor] overrides
+ * [Visitor.unknown]. To handle variants not known to this version
+ * of the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = metadataValueItem.accept(new MetadataValueItem.Visitor>() {
+ * @Override
+ * public Optional visitString(String string) {
+ * return Optional.of(string.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not
+ * overridden in [visitor] and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
string != null -> visitor.visitString(string)
@@ -6100,6 +6611,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the
+ * API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this
+ * object doesn't match its expected type.
+ */
fun validate(): MetadataValueItem = apply {
if (validated) {
return@apply
@@ -6442,6 +6963,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object
+ * doesn't match its expected type.
+ */
fun validate(): UnsetMetadata = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/ExtensionItem.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/ExtensionItem.kt
index 263cb754..aa138b3a 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/ExtensionItem.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/ExtensionItem.kt
@@ -77,6 +77,35 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API, unless
+ * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of the
+ * SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = extensionItem.accept(new ExtensionItem.Visitor>() {
+ * @Override
+ * public Optional visitRemoveBg(RemoveBg removeBg) {
+ * return Optional.of(removeBg.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in [visitor] and
+ * the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
removeBg != null -> visitor.visitRemoveBg(removeBg)
@@ -89,6 +118,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): ExtensionItem = apply {
if (validated) {
return@apply
@@ -421,6 +458,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): RemoveBg = apply {
if (validated) {
return@apply
@@ -695,6 +741,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing
+ * fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match
+ * its expected type.
+ */
fun validate(): Options = apply {
if (validated) {
return@apply
@@ -961,6 +1017,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): AutoTaggingExtension = apply {
if (validated) {
return@apply
@@ -1082,6 +1147,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing
+ * fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match
+ * its expected type.
+ */
fun validate(): Name = apply {
if (validated) {
return@apply
@@ -1336,6 +1411,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): AiTasks = apply {
if (validated) {
return@apply
@@ -1399,6 +1483,36 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given
+ * [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API,
+ * unless [visitor] overrides [Visitor.unknown]. To handle variants not known to this
+ * version of the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = task.accept(new Task.Visitor>() {
+ * @Override
+ * public Optional visitSelectTags(SelectTags selectTags) {
+ * return Optional.of(selectTags.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in
+ * [visitor] and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
selectTags != null -> visitor.visitSelectTags(selectTags)
@@ -1409,6 +1523,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing
+ * fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match
+ * its expected type.
+ */
fun validate(): Task = apply {
if (validated) {
return@apply
@@ -1869,6 +1993,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing
+ * fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't
+ * match its expected type.
+ */
fun validate(): SelectTags = apply {
if (validated) {
return@apply
@@ -2297,6 +2431,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing
+ * fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't
+ * match its expected type.
+ */
fun validate(): SelectMetadata = apply {
if (validated) {
return@apply
@@ -2368,6 +2512,37 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given
+ * [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the
+ * API, unless [visitor] overrides [Visitor.unknown]. To handle variants not
+ * known to this version of the SDK gracefully, consider overriding
+ * [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = vocabulary.accept(new Vocabulary.Visitor>() {
+ * @Override
+ * public Optional visitString(String string) {
+ * return Optional.of(string.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden
+ * in [visitor] and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
string != null -> visitor.visitString(string)
@@ -2378,6 +2553,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected
+ * types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't
+ * match its expected type.
+ */
fun validate(): Vocabulary = apply {
if (validated) {
return@apply
@@ -2833,6 +3018,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing
+ * fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't
+ * match its expected type.
+ */
fun validate(): YesNo = apply {
if (validated) {
return@apply
@@ -3160,6 +3355,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected
+ * types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't
+ * match its expected type.
+ */
fun validate(): OnNo = apply {
if (validated) {
return@apply
@@ -3381,6 +3586,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object
+ * doesn't match its expected type.
+ */
fun validate(): SetMetadata = apply {
if (validated) {
return@apply
@@ -3452,6 +3667,37 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the
+ * given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants
+ * from the API, unless [visitor] overrides [Visitor.unknown]. To handle
+ * variants not known to this version of the SDK gracefully, consider
+ * overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = value.accept(new Value.Visitor>() {
+ * @Override
+ * public Optional visitString(String string) {
+ * return Optional.of(string.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not
+ * overridden in [visitor] and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
string != null -> visitor.visitString(string)
@@ -3463,6 +3709,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API
+ * for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object
+ * doesn't match its expected type.
+ */
fun validate(): Value = apply {
if (validated) {
return@apply
@@ -3668,6 +3924,37 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using
+ * the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new
+ * variants from the API, unless [visitor] overrides
+ * [Visitor.unknown]. To handle variants not known to this version
+ * of the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = metadataValueItem.accept(new MetadataValueItem.Visitor>() {
+ * @Override
+ * public Optional visitString(String string) {
+ * return Optional.of(string.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not
+ * overridden in [visitor] and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
string != null -> visitor.visitString(string)
@@ -3678,6 +3965,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the
+ * API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this
+ * object doesn't match its expected type.
+ */
fun validate(): MetadataValueItem = apply {
if (validated) {
return@apply
@@ -4020,6 +4317,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object
+ * doesn't match its expected type.
+ */
fun validate(): UnsetMetadata = apply {
if (validated) {
return@apply
@@ -4385,6 +4692,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected
+ * types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't
+ * match its expected type.
+ */
fun validate(): OnUnknown = apply {
if (validated) {
return@apply
@@ -4606,6 +4923,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object
+ * doesn't match its expected type.
+ */
fun validate(): SetMetadata = apply {
if (validated) {
return@apply
@@ -4677,6 +5004,37 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the
+ * given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants
+ * from the API, unless [visitor] overrides [Visitor.unknown]. To handle
+ * variants not known to this version of the SDK gracefully, consider
+ * overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = value.accept(new Value.Visitor>() {
+ * @Override
+ * public Optional visitString(String string) {
+ * return Optional.of(string.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not
+ * overridden in [visitor] and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
string != null -> visitor.visitString(string)
@@ -4688,6 +5046,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API
+ * for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object
+ * doesn't match its expected type.
+ */
fun validate(): Value = apply {
if (validated) {
return@apply
@@ -4893,6 +5261,37 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using
+ * the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new
+ * variants from the API, unless [visitor] overrides
+ * [Visitor.unknown]. To handle variants not known to this version
+ * of the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = metadataValueItem.accept(new MetadataValueItem.Visitor>() {
+ * @Override
+ * public Optional visitString(String string) {
+ * return Optional.of(string.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not
+ * overridden in [visitor] and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
string != null -> visitor.visitString(string)
@@ -4903,6 +5302,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the
+ * API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this
+ * object doesn't match its expected type.
+ */
fun validate(): MetadataValueItem = apply {
if (validated) {
return@apply
@@ -5245,6 +5654,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object
+ * doesn't match its expected type.
+ */
fun validate(): UnsetMetadata = apply {
if (validated) {
return@apply
@@ -5608,6 +6027,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected
+ * types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't
+ * match its expected type.
+ */
fun validate(): OnYes = apply {
if (validated) {
return@apply
@@ -5829,6 +6258,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object
+ * doesn't match its expected type.
+ */
fun validate(): SetMetadata = apply {
if (validated) {
return@apply
@@ -5900,6 +6339,37 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the
+ * given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants
+ * from the API, unless [visitor] overrides [Visitor.unknown]. To handle
+ * variants not known to this version of the SDK gracefully, consider
+ * overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = value.accept(new Value.Visitor>() {
+ * @Override
+ * public Optional visitString(String string) {
+ * return Optional.of(string.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not
+ * overridden in [visitor] and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
string != null -> visitor.visitString(string)
@@ -5911,6 +6381,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API
+ * for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object
+ * doesn't match its expected type.
+ */
fun validate(): Value = apply {
if (validated) {
return@apply
@@ -6116,6 +6596,37 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using
+ * the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new
+ * variants from the API, unless [visitor] overrides
+ * [Visitor.unknown]. To handle variants not known to this version
+ * of the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = metadataValueItem.accept(new MetadataValueItem.Visitor>() {
+ * @Override
+ * public Optional visitString(String string) {
+ * return Optional.of(string.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not
+ * overridden in [visitor] and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
string != null -> visitor.visitString(string)
@@ -6126,6 +6637,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the
+ * API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this
+ * object doesn't match its expected type.
+ */
fun validate(): MetadataValueItem = apply {
if (validated) {
return@apply
@@ -6468,6 +6989,16 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their
+ * expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for
+ * existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object
+ * doesn't match its expected type.
+ */
fun validate(): UnsetMetadata = apply {
if (validated) {
return@apply
@@ -6731,6 +7262,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): SavedExtension = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/GetImageAttributesOptions.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/GetImageAttributesOptions.kt
index 713b8faa..790c058f 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/GetImageAttributesOptions.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/GetImageAttributesOptions.kt
@@ -671,6 +671,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): GetImageAttributesOptions = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/ImageOverlay.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/ImageOverlay.kt
index e0c858a3..a06b2211 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/ImageOverlay.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/ImageOverlay.kt
@@ -423,6 +423,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): ImageOverlay = apply {
if (validated) {
return@apply
@@ -570,6 +578,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): Encoding = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/Overlay.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/Overlay.kt
index 4032d5e3..9b06a410 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/Overlay.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/Overlay.kt
@@ -67,6 +67,35 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API, unless
+ * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of the
+ * SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = overlay.accept(new Overlay.Visitor>() {
+ * @Override
+ * public Optional visitText(TextOverlay text) {
+ * return Optional.of(text.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in [visitor] and
+ * the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
text != null -> visitor.visitText(text)
@@ -79,6 +108,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): Overlay = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/OverlayPosition.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/OverlayPosition.kt
index 56e22284..9c76769d 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/OverlayPosition.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/OverlayPosition.kt
@@ -361,6 +361,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): OverlayPosition = apply {
if (validated) {
return@apply
@@ -536,6 +544,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): AnchorPoint = apply {
if (validated) {
return@apply
@@ -710,6 +727,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): Focus = apply {
if (validated) {
return@apply
@@ -777,6 +803,35 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API, unless
+ * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of
+ * the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = x.accept(new X.Visitor>() {
+ * @Override
+ * public Optional visitNumber(Double number) {
+ * return Optional.of(number.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in [visitor]
+ * and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
number != null -> visitor.visitNumber(number)
@@ -786,6 +841,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): X = apply {
if (validated) {
return@apply
@@ -949,6 +1013,35 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API, unless
+ * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of
+ * the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = xCenter.accept(new XCenter.Visitor>() {
+ * @Override
+ * public Optional visitNumber(Double number) {
+ * return Optional.of(number.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in [visitor]
+ * and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
number != null -> visitor.visitNumber(number)
@@ -958,6 +1051,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): XCenter = apply {
if (validated) {
return@apply
@@ -1124,6 +1226,35 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API, unless
+ * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of
+ * the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = y.accept(new Y.Visitor>() {
+ * @Override
+ * public Optional visitNumber(Double number) {
+ * return Optional.of(number.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in [visitor]
+ * and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
number != null -> visitor.visitNumber(number)
@@ -1133,6 +1264,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): Y = apply {
if (validated) {
return@apply
@@ -1296,6 +1436,35 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API, unless
+ * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of
+ * the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = yCenter.accept(new YCenter.Visitor>() {
+ * @Override
+ * public Optional visitNumber(Double number) {
+ * return Optional.of(number.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in [visitor]
+ * and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
number != null -> visitor.visitNumber(number)
@@ -1305,6 +1474,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): YCenter = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/OverlayTiming.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/OverlayTiming.kt
index 9ba19767..3b34d1d6 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/OverlayTiming.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/OverlayTiming.kt
@@ -230,6 +230,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): OverlayTiming = apply {
if (validated) {
return@apply
@@ -289,6 +297,35 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API, unless
+ * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of
+ * the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = duration.accept(new Duration.Visitor>() {
+ * @Override
+ * public Optional visitNumber(Double number) {
+ * return Optional.of(number.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in [visitor]
+ * and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
number != null -> visitor.visitNumber(number)
@@ -298,6 +335,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): Duration = apply {
if (validated) {
return@apply
@@ -465,6 +511,35 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API, unless
+ * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of
+ * the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = end.accept(new End.Visitor>() {
+ * @Override
+ * public Optional visitNumber(Double number) {
+ * return Optional.of(number.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in [visitor]
+ * and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
number != null -> visitor.visitNumber(number)
@@ -474,6 +549,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): End = apply {
if (validated) {
return@apply
@@ -637,6 +721,35 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API, unless
+ * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of
+ * the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = start.accept(new Start.Visitor>() {
+ * @Override
+ * public Optional visitNumber(Double number) {
+ * return Optional.of(number.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in [visitor]
+ * and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
number != null -> visitor.visitNumber(number)
@@ -646,6 +759,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): Start = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/ResponsiveImageAttributes.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/ResponsiveImageAttributes.kt
index f9420a46..90ae4917 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/ResponsiveImageAttributes.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/ResponsiveImageAttributes.kt
@@ -234,6 +234,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): ResponsiveImageAttributes = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/SavedExtension.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/SavedExtension.kt
index 5e81cbca..f460e5dc 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/SavedExtension.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/SavedExtension.kt
@@ -321,6 +321,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): SavedExtension = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/SelectedFieldsSchema.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/SelectedFieldsSchema.kt
index 7baa61a9..cd10e154 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/SelectedFieldsSchema.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/SelectedFieldsSchema.kt
@@ -76,6 +76,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): SelectedFieldsSchema = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/SolidColorOverlay.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/SolidColorOverlay.kt
index 882268a7..6a498276 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/SolidColorOverlay.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/SolidColorOverlay.kt
@@ -382,6 +382,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): SolidColorOverlay = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/SolidColorOverlayTransformation.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/SolidColorOverlayTransformation.kt
index 38657c66..d97593a0 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/SolidColorOverlayTransformation.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/SolidColorOverlayTransformation.kt
@@ -357,6 +357,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): SolidColorOverlayTransformation = apply {
if (validated) {
return@apply
@@ -421,6 +429,35 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API, unless
+ * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of
+ * the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = gradient.accept(new Gradient.Visitor>() {
+ * @Override
+ * public Optional visitTrue(JsonValue true_) {
+ * return Optional.of(true_.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in [visitor]
+ * and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
true_ != null -> visitor.visitTrue(true_)
@@ -430,6 +467,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): Gradient = apply {
if (validated) {
return@apply
@@ -604,6 +650,35 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API, unless
+ * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of
+ * the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = height.accept(new Height.Visitor>() {
+ * @Override
+ * public Optional visitNumber(Double number) {
+ * return Optional.of(number.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in [visitor]
+ * and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
number != null -> visitor.visitNumber(number)
@@ -613,6 +688,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): Height = apply {
if (validated) {
return@apply
@@ -786,6 +870,35 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API, unless
+ * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of
+ * the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = radius.accept(new Radius.Visitor>() {
+ * @Override
+ * public Optional visitNumber(Double number) {
+ * return Optional.of(number.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in [visitor]
+ * and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
number != null -> visitor.visitNumber(number)
@@ -796,6 +909,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): Radius = apply {
if (validated) {
return@apply
@@ -982,6 +1104,35 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API, unless
+ * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of
+ * the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = width.accept(new Width.Visitor>() {
+ * @Override
+ * public Optional visitNumber(Double number) {
+ * return Optional.of(number.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in [visitor]
+ * and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
number != null -> visitor.visitNumber(number)
@@ -991,6 +1142,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): Width = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/SrcOptions.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/SrcOptions.kt
index 08135372..afe64575 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/SrcOptions.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/SrcOptions.kt
@@ -441,6 +441,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): SrcOptions = apply {
if (validated) {
return@apply
@@ -542,6 +550,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): QueryParameters = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/StreamingResolution.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/StreamingResolution.kt
index e179c5fe..ca27cd57 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/StreamingResolution.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/StreamingResolution.kt
@@ -130,6 +130,14 @@ class StreamingResolution @JsonCreator private constructor(private val value: Js
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): StreamingResolution = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/SubtitleOverlay.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/SubtitleOverlay.kt
index d6248053..cc1fb9f5 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/SubtitleOverlay.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/SubtitleOverlay.kt
@@ -417,6 +417,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): SubtitleOverlay = apply {
if (validated) {
return@apply
@@ -564,6 +572,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): Encoding = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/SubtitleOverlayTransformation.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/SubtitleOverlayTransformation.kt
index b3969f17..fce2b9d9 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/SubtitleOverlayTransformation.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/SubtitleOverlayTransformation.kt
@@ -414,6 +414,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): SubtitleOverlayTransformation = apply {
if (validated) {
return@apply
@@ -556,6 +564,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): Typography = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/TextOverlay.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/TextOverlay.kt
index 9fcccac3..34bad4f7 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/TextOverlay.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/TextOverlay.kt
@@ -419,6 +419,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): TextOverlay = apply {
if (validated) {
return@apply
@@ -565,6 +573,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): Encoding = apply {
if (validated) {
return@apply
diff --git a/image-kit-java-core/src/main/kotlin/io/imagekit/models/TextOverlayTransformation.kt b/image-kit-java-core/src/main/kotlin/io/imagekit/models/TextOverlayTransformation.kt
index a1c3479a..9b8f019a 100644
--- a/image-kit-java-core/src/main/kotlin/io/imagekit/models/TextOverlayTransformation.kt
+++ b/image-kit-java-core/src/main/kotlin/io/imagekit/models/TextOverlayTransformation.kt
@@ -652,6 +652,14 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): TextOverlayTransformation = apply {
if (validated) {
return@apply
@@ -807,6 +815,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): Flip = apply {
if (validated) {
return@apply
@@ -872,6 +889,35 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API, unless
+ * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of
+ * the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = fontSize.accept(new FontSize.Visitor>() {
+ * @Override
+ * public Optional visitNumber(Double number) {
+ * return Optional.of(number.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in [visitor]
+ * and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
number != null -> visitor.visitNumber(number)
@@ -881,6 +927,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): FontSize = apply {
if (validated) {
return@apply
@@ -1118,6 +1173,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): InnerAlignment = apply {
if (validated) {
return@apply
@@ -1183,6 +1247,35 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API, unless
+ * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of
+ * the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = lineHeight.accept(new LineHeight.Visitor>() {
+ * @Override
+ * public Optional visitNumber(Double number) {
+ * return Optional.of(number.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in [visitor]
+ * and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
number != null -> visitor.visitNumber(number)
@@ -1192,6 +1285,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): LineHeight = apply {
if (validated) {
return@apply
@@ -1357,6 +1459,35 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API, unless
+ * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of
+ * the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = padding.accept(new Padding.Visitor>() {
+ * @Override
+ * public Optional visitNumber(Double number) {
+ * return Optional.of(number.toString());
+ * }
+ *
+ * // ...
+ *
+ * @Override
+ * public Optional unknown(JsonValue json) {
+ * // Or inspect the `json`.
+ * return Optional.empty();
+ * }
+ * });
+ * ```
+ *
+ * @throws ImageKitInvalidDataException if [Visitor.unknown] is not overridden in [visitor]
+ * and the current variant is unknown.
+ */
fun accept(visitor: Visitor): T =
when {
number != null -> visitor.visitNumber(number)
@@ -1366,6 +1497,15 @@ private constructor(
private var validated: Boolean = false
+ /**
+ * Validates that the types of all values in this object match their expected types
+ * recursively.
+ *
+ * This method is _not_ forwards compatible with new types from the API for existing fields.
+ *
+ * @throws ImageKitInvalidDataException if any value type in this object doesn't match its
+ * expected type.
+ */
fun validate(): Padding = apply {
if (validated) {
return@apply
@@ -1541,6 +1681,35 @@ private constructor(
fun _json(): Optional = Optional.ofNullable(_json)
+ /**
+ * Maps this instance's current variant to a value of type [T] using the given [visitor].
+ *
+ * Note that this method is _not_ forwards compatible with new variants from the API, unless
+ * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of
+ * the SDK gracefully, consider overriding [Visitor.unknown]:
+ * ```java
+ * import io.imagekit.core.JsonValue;
+ * import java.util.Optional;
+ *
+ * Optional result = radius.accept(new Radius.Visitor>() {
+ * @Override
+ * public Optional