diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0837041fe..fd41c586f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -14,7 +14,7 @@ on:
jobs:
lint:
- timeout-minutes: 10
+ timeout-minutes: 15
name: lint
runs-on: ${{ github.repository == 'stainless-sdks/orb-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
@@ -36,8 +36,33 @@ jobs:
- name: Run lints
run: ./scripts/lint
+
+ build:
+ timeout-minutes: 15
+ name: build
+ runs-on: ${{ github.repository == 'stainless-sdks/orb-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
+ if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Java
+ uses: actions/setup-java@v4
+ with:
+ distribution: temurin
+ java-version: |
+ 8
+ 21
+ cache: gradle
+
+ - name: Set up Gradle
+ uses: gradle/actions/setup-gradle@v4
+
+ - name: Build SDK
+ run: ./scripts/build
+
test:
- timeout-minutes: 10
+ timeout-minutes: 15
name: test
runs-on: ${{ github.repository == 'stainless-sdks/orb-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml
index 9875f43ef..eab3bf498 100644
--- a/.github/workflows/publish-sonatype.yml
+++ b/.github/workflows/publish-sonatype.yml
@@ -22,7 +22,7 @@ jobs:
distribution: temurin
java-version: |
8
- 17
+ 21
cache: gradle
- name: Set up Gradle
@@ -33,7 +33,7 @@ jobs:
export -- GPG_SIGNING_KEY_ID
printenv -- GPG_SIGNING_KEY | gpg --batch --passphrase-fd 3 --import 3<<< "$GPG_SIGNING_PASSWORD"
GPG_SIGNING_KEY_ID="$(gpg --with-colons --list-keys | awk -F : -- '/^pub:/ { getline; print "0x" substr($10, length($10) - 7) }')"
- ./gradlew publishAndReleaseToMavenCentral -Dorg.gradle.jvmargs="-Xmx8g" --stacktrace -PmavenCentralUsername="$SONATYPE_USERNAME" -PmavenCentralPassword="$SONATYPE_PASSWORD" --no-configuration-cache
+ ./gradlew publishAndReleaseToMavenCentral --stacktrace -PmavenCentralUsername="$SONATYPE_USERNAME" -PmavenCentralPassword="$SONATYPE_PASSWORD" --no-configuration-cache
env:
SONATYPE_USERNAME: ${{ secrets.ORB_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }}
SONATYPE_PASSWORD: ${{ secrets.ORB_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }}
diff --git a/.gitignore b/.gitignore
index 4e81838d6..b1346e6d1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,6 @@
.gradle
.idea
.kotlin
-build
+build/
codegen.log
kls_database.db
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index c3c95522a..eb4e0dba7 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "1.9.0"
+ ".": "1.10.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index c03739d1c..b3a9d31c0 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 118
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-4f31d46f5ba187fc4d702c9f9f1573dacb891edbd086f935707578d7c4f5fed8.yml
-openapi_spec_hash: 25b1019f20a47b8af665aae5f8fd0025
-config_hash: 5135e9237207028f293049a77428c775
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-59c57f1cbc067a477f6bf673882c28065e01418b86fcff390bba0d4438c58105.yml
+openapi_spec_hash: 4da2681664f766985d1c20df40240cd9
+config_hash: 05c94c0e6dbeab2c9b554c2e0d6371a0
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a326cfbd9..190404edc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,86 @@
# Changelog
+## 1.10.0 (2025-12-17)
+
+Full Changelog: [v1.9.0...v1.10.0](https://github.com/orbcorp/orb-java/compare/v1.9.0...v1.10.0)
+
+### ⚠ BREAKING CHANGES
+
+* **api:** define shared model ConversionRateConfig
+
+### Features
+
+* add retryable exception ([cf6742e](https://github.com/orbcorp/orb-java/commit/cf6742e0ace7ef26c53fdf1c6ead9f742a326094))
+* **api:** api update ([66b024c](https://github.com/orbcorp/orb-java/commit/66b024cd9d56108719ffedb0ef91b94178dd5149))
+* **api:** api update ([f14a0b8](https://github.com/orbcorp/orb-java/commit/f14a0b818473f9fe09e299e43c72992dc99cf628))
+* **api:** api update ([a321e4c](https://github.com/orbcorp/orb-java/commit/a321e4cb1023069885ecc43f02f35a1ca580d51a))
+* **api:** api update ([16c09ab](https://github.com/orbcorp/orb-java/commit/16c09abc0bd756cb2c7c65b5dd987ed135d95fc6))
+* **api:** api update ([42a3bf2](https://github.com/orbcorp/orb-java/commit/42a3bf2b3f92450fea64d1fd308c8aef4f705dc4))
+* **api:** api update ([8d40c66](https://github.com/orbcorp/orb-java/commit/8d40c665b040c93811cb04523986254db90251c1))
+* **api:** api update ([340aeb5](https://github.com/orbcorp/orb-java/commit/340aeb58fff2c96c29b18055963db7e6186fc098))
+* **api:** api update ([8c81c68](https://github.com/orbcorp/orb-java/commit/8c81c68e0cc2ec1de0d1bf25f438eb4eb7513e7b))
+* **api:** api update ([bf19834](https://github.com/orbcorp/orb-java/commit/bf19834416fab1b4facb56b5bb480a98b4046871))
+* **api:** api update ([db21295](https://github.com/orbcorp/orb-java/commit/db212951f87170757554823c153c63723f1919bb))
+* **api:** api update ([8d0120a](https://github.com/orbcorp/orb-java/commit/8d0120a97c6c732106ca1f18823e0bcb3a2c3ae3))
+* **api:** api update ([dfd1f8b](https://github.com/orbcorp/orb-java/commit/dfd1f8bd061995e3f09660f24d638356ffabbeca))
+* **api:** api update ([2c02d15](https://github.com/orbcorp/orb-java/commit/2c02d1554141dfc72791f2c0a9e6801e24ded3e8))
+* **api:** api update ([c7d3dda](https://github.com/orbcorp/orb-java/commit/c7d3dda3503f7d9a359f439d8388212a710a2e14))
+* **api:** api update ([5f65069](https://github.com/orbcorp/orb-java/commit/5f650699507a73427410d4e30a7694eebabb3376))
+* **api:** api update ([f28bee7](https://github.com/orbcorp/orb-java/commit/f28bee7981fa0077a0d93b9061640c6bbdb05098))
+* **api:** api update ([b6f5318](https://github.com/orbcorp/orb-java/commit/b6f5318aed1e4b03e46f911ad3f9b199fd6c95bd))
+* **api:** api update ([1a45d5d](https://github.com/orbcorp/orb-java/commit/1a45d5d0090f3afda47a434ed4fc2e4d62060e50))
+* **api:** api update ([108cdfc](https://github.com/orbcorp/orb-java/commit/108cdfc98f5d0d46721aa7515634c42846eba1ee))
+* **api:** api update ([f101f63](https://github.com/orbcorp/orb-java/commit/f101f63b19cda34ea15fe08aba62a8706cc5a8fc))
+* **api:** api update ([6c895f2](https://github.com/orbcorp/orb-java/commit/6c895f2348474af8319b87e51db26a28891b7a9c))
+* **api:** api update ([84cc66c](https://github.com/orbcorp/orb-java/commit/84cc66cec7668f2de52760b458f5c732914d0995))
+* **api:** api update ([ab79480](https://github.com/orbcorp/orb-java/commit/ab794808febc46a53d5baf1e41f0ad7b1ab8d1df))
+* **api:** api update ([0f4e585](https://github.com/orbcorp/orb-java/commit/0f4e5853aab9546952e9d80b4c2e50688a8caf6d))
+* **api:** api update ([617892e](https://github.com/orbcorp/orb-java/commit/617892e6526e1717415bfa630529ffce50a70b96))
+* **api:** api update ([bf412bc](https://github.com/orbcorp/orb-java/commit/bf412bca3a157a0e41fef19a5d915c095b09eda1))
+* **api:** api update ([6aa1d53](https://github.com/orbcorp/orb-java/commit/6aa1d5370247b08c937ca7faa9fcacf5b21ed081))
+* **api:** api update ([321aa41](https://github.com/orbcorp/orb-java/commit/321aa4197ce9dbc8601ec7578d0f70017e37c2f6))
+* **api:** api update ([cf6fd19](https://github.com/orbcorp/orb-java/commit/cf6fd1990dc2781ebc0ab860b135ce4b90a58fa2))
+* **api:** api update ([9c8977c](https://github.com/orbcorp/orb-java/commit/9c8977c14697c4907f13e29189a62c2aea441924))
+* **api:** api update ([247937e](https://github.com/orbcorp/orb-java/commit/247937ebe3dba64b53c180a9a58460e10cde4a8c))
+* **api:** api update ([5d00bf2](https://github.com/orbcorp/orb-java/commit/5d00bf2a8be3610043bbd620eb724d13788fc89a))
+* **api:** api update ([05b6a4e](https://github.com/orbcorp/orb-java/commit/05b6a4e2d2e551b8b09168d2a8d6e34851fcd784))
+* **api:** api update ([3b2489b](https://github.com/orbcorp/orb-java/commit/3b2489bdb730033a389ec76cc824df8eb351c678))
+* **api:** api update ([e90f837](https://github.com/orbcorp/orb-java/commit/e90f837c716a2fe6955df54c844b4320a1a26d8b))
+* **api:** define shared model ConversionRateConfig ([13fc2ef](https://github.com/orbcorp/orb-java/commit/13fc2efb464953fc534dbd09ed34b003c17a3d0d))
+* **client:** ensure compat with proguard ([83ddd55](https://github.com/orbcorp/orb-java/commit/83ddd55a2e265b3f2426f47868bc5a596509e3a8))
+* **client:** expose sleeper option ([427df35](https://github.com/orbcorp/orb-java/commit/427df355df00bafcdb972fbfb758f7cb0646aab6))
+* extract minimum composite to type ([3e25650](https://github.com/orbcorp/orb-java/commit/3e256505b03e771aef66c8a435f27a6ec3b9e237))
+
+
+### Bug Fixes
+
+* **ci:** use java-version 21 for publish step ([b290b3a](https://github.com/orbcorp/orb-java/commit/b290b3a558d6f1b4419975855a22c0f0b8b055e2))
+* **client:** cancel okhttp call when future cancelled ([c9b8382](https://github.com/orbcorp/orb-java/commit/c9b8382a9741380a090469881eb5bf242c463a7d))
+* **client:** deserialization of empty objects ([1764089](https://github.com/orbcorp/orb-java/commit/1764089476594bd942efe77f15d4744e6c0a01dd))
+* **client:** ensure single timer is created per client ([427df35](https://github.com/orbcorp/orb-java/commit/427df355df00bafcdb972fbfb758f7cb0646aab6))
+* **client:** incorrect `getPackageVersion` impl ([9bc6ac9](https://github.com/orbcorp/orb-java/commit/9bc6ac99cc3a432ddc30f43dda41d076f4197883))
+* **client:** multi-value header serialization ([bf4d413](https://github.com/orbcorp/orb-java/commit/bf4d413ad8025a208cb99ff68f989b7988d906b0))
+* **client:** r8 support ([27da721](https://github.com/orbcorp/orb-java/commit/27da7219bb085292eba8cf247a8574689f922300))
+* **schema:** Rename unit price type to avoid naming conflict ([7738ed4](https://github.com/orbcorp/orb-java/commit/7738ed44d3ba2df61adb5ef1b7a933b55ab4d5bd))
+
+
+### Chores
+
+* fix formatting ([a6e527f](https://github.com/orbcorp/orb-java/commit/a6e527f946e40ebbfebc97c4eaeec1900845197a))
+* improve formatter performance ([5d37bc1](https://github.com/orbcorp/orb-java/commit/5d37bc171ae17fbfb70c63743afde6b04e29ff1c))
+* **internal:** bump ci test timeout ([0e68dd4](https://github.com/orbcorp/orb-java/commit/0e68dd443b79c48810c94749f88cfc2d9286a725))
+* **internal:** change some comment formatting ([7e80bfe](https://github.com/orbcorp/orb-java/commit/7e80bfeb93b40dc060dd5947e8e37d4fb68a4955))
+* **internal:** codegen related update ([97bd293](https://github.com/orbcorp/orb-java/commit/97bd293da263a5259bac93d2f9d9aeb0f10d5c65))
+* **internal:** codegen related update ([3a4300a](https://github.com/orbcorp/orb-java/commit/3a4300ae19b4ad4c9f82056658d88013a35c992e))
+* **internal:** codegen related update ([185acb8](https://github.com/orbcorp/orb-java/commit/185acb801fe845d8b33f741e1e1f1e07550fd92f))
+* **internal:** codegen related update ([76d269d](https://github.com/orbcorp/orb-java/commit/76d269d0cba09f1150af878d603292b92e003241))
+* **internal:** reduce proguard ci logging ([9b4d208](https://github.com/orbcorp/orb-java/commit/9b4d20849c0af2b5945f155aad5a91c338020f56))
+
+
+### Documentation
+
+* remove `$` for better copy-pasteabality ([c20680a](https://github.com/orbcorp/orb-java/commit/c20680a232316989527ab7da435b6c0baf7885af))
+
## 1.9.0 (2025-07-26)
Full Changelog: [v1.8.0...v1.9.0](https://github.com/orbcorp/orb-java/compare/v1.8.0...v1.9.0)
diff --git a/README.md b/README.md
index b0b339ee1..7ed8a2bb4 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
-[](https://central.sonatype.com/artifact/com.withorb.api/orb-java/1.9.0)
+[](https://central.sonatype.com/artifact/com.withorb.api/orb-java/1.10.0)
@@ -19,7 +19,7 @@ The REST API documentation can be found on [docs.withorb.com](https://docs.witho
### Gradle
```kotlin
-implementation("com.withorb.api:orb-java:1.9.0")
+implementation("com.withorb.api:orb-java:1.10.0")
```
### Maven
@@ -28,7 +28,7 @@ implementation("com.withorb.api:orb-java:1.9.0")
com.withorb.api
orb-java
- 1.9.0
+ 1.10.0
```
@@ -231,6 +231,8 @@ The SDK throws custom unchecked exception types:
- [`OrbIoException`](orb-java-core/src/main/kotlin/com/withorb/api/errors/OrbIoException.kt): I/O networking errors.
+- [`OrbRetryableException`](orb-java-core/src/main/kotlin/com/withorb/api/errors/OrbRetryableException.kt): Generic error indicating a failure that could be retried by the client.
+
- [`OrbInvalidDataException`](orb-java-core/src/main/kotlin/com/withorb/api/errors/OrbInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that's supposed to be required, but the API unexpectedly omitted it from the response.
- [`OrbException`](orb-java-core/src/main/kotlin/com/withorb/api/errors/OrbException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class.
@@ -342,13 +344,13 @@ The SDK uses the standard [OkHttp logging interceptor](https://github.com/square
Enable logging by setting the `ORB_LOG` environment variable to `info`:
```sh
-$ export ORB_LOG=info
+export ORB_LOG=info
```
Or to `debug` for more verbose logging:
```sh
-$ export ORB_LOG=debug
+export ORB_LOG=debug
```
## Webhook Verification
@@ -361,6 +363,12 @@ both of which will raise an error if the signature is invalid.
Note that the `body` parameter must be the raw JSON string sent from the server (do not parse it first).
The `.unwrap()` method can parse this JSON for you.
+## 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 `orb-java-core` is published with a [configuration file](orb-java-core/src/main/resources/META-INF/proguard/orb-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage).
+
+ProGuard and R8 should automatically detect and use the published rules, but you can also manually copy the keep rules if necessary.
+
## Jackson
The SDK depends on [Jackson](https://github.com/FasterXML/jackson) for JSON serialization/deserialization. It is compatible with version 2.13.4 or higher, but depends on version 2.18.2 by default.
diff --git a/build.gradle.kts b/build.gradle.kts
index 961c7eab7..8e1585b2b 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,4 +1,16 @@
allprojects {
group = "com.withorb.api"
- version = "1.9.0" // x-release-please-version
+ version = "1.10.0" // x-release-please-version
+}
+
+subprojects {
+ // These are populated with dependencies by `buildSrc` scripts.
+ tasks.register("format") {
+ group = "Verification"
+ description = "Formats all source files."
+ }
+ tasks.register("lint") {
+ group = "Verification"
+ description = "Verifies all source files are formatted."
+ }
}
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
index 778c89de5..c6dc92ec5 100644
--- a/buildSrc/build.gradle.kts
+++ b/buildSrc/build.gradle.kts
@@ -10,7 +10,6 @@ repositories {
}
dependencies {
- implementation("com.diffplug.spotless:spotless-plugin-gradle:7.0.2")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.20")
implementation("com.vanniktech:gradle-maven-publish-plugin:0.28.0")
}
diff --git a/buildSrc/src/main/kotlin/orb.java.gradle.kts b/buildSrc/src/main/kotlin/orb.java.gradle.kts
index dfbacb86e..70fc33f41 100644
--- a/buildSrc/src/main/kotlin/orb.java.gradle.kts
+++ b/buildSrc/src/main/kotlin/orb.java.gradle.kts
@@ -1,24 +1,13 @@
-import com.diffplug.gradle.spotless.SpotlessExtension
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
plugins {
`java-library`
- id("com.diffplug.spotless")
}
repositories {
mavenCentral()
}
-configure {
- java {
- importOrder()
- removeUnusedImports()
- palantirJavaFormat()
- toggleOffOn()
- }
-}
-
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
@@ -53,3 +42,86 @@ tasks.withType().configureEach {
exceptionFormat = TestExceptionFormat.FULL
}
}
+
+val palantir by configurations.creating
+dependencies {
+ palantir("com.palantir.javaformat:palantir-java-format:2.73.0")
+}
+
+fun registerPalantir(
+ name: String,
+ description: String,
+) {
+ val javaName = "${name}Java"
+ tasks.register(javaName) {
+ group = "Verification"
+ this.description = description
+
+ classpath = palantir
+ mainClass = "com.palantir.javaformat.java.Main"
+
+ // Avoid an `IllegalAccessError` on Java 9+.
+ jvmArgs(
+ "--add-exports", "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
+ "--add-exports", "jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",
+ "--add-exports", "jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED",
+ "--add-exports", "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
+ "--add-exports", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
+ )
+
+ // Use paths relative to the current module.
+ val argumentFile =
+ project.layout.buildDirectory.file("palantir-$name-args.txt").get().asFile
+ val lastRunTimeFile =
+ project.layout.buildDirectory.file("palantir-$name-last-run.txt").get().asFile
+
+ // Read the time when this task was last executed for this module (if ever).
+ val lastRunTime = lastRunTimeFile.takeIf { it.exists() }?.readText()?.toLongOrNull() ?: 0L
+
+ // Use a `fileTree` relative to the module's source directory.
+ val javaFiles = project.fileTree("src") { include("**/*.java") }
+
+ // Determine if any files need to be formatted or linted and continue only if there is at least
+ // one file.
+ onlyIf { javaFiles.any { it.lastModified() > lastRunTime } }
+
+ inputs.files(javaFiles)
+
+ doFirst {
+ // Create the argument file and set the preferred formatting style.
+ argumentFile.parentFile.mkdirs()
+ argumentFile.writeText("--palantir\n")
+
+ if (name == "lint") {
+ // For lint, do a dry run, so no files are modified. Set the exit code to 1 (instead of
+ // the default 0) if any files need to be formatted, indicating that linting has failed.
+ argumentFile.appendText("--dry-run\n")
+ argumentFile.appendText("--set-exit-if-changed\n")
+ } else {
+ // `--dry-run` and `--replace` (for in-place formatting) are mutually exclusive.
+ argumentFile.appendText("--replace\n")
+ }
+
+ // Write the modified files to the argument file.
+ javaFiles.filter { it.lastModified() > lastRunTime }
+ .forEach { argumentFile.appendText("${it.absolutePath}\n") }
+ }
+
+ doLast {
+ // Record the last execution time for later up-to-date checking.
+ lastRunTimeFile.writeText(System.currentTimeMillis().toString())
+ }
+
+ // Pass the argument file using the @ symbol
+ args = listOf("@${argumentFile.absolutePath}")
+
+ outputs.upToDateWhen { javaFiles.none { it.lastModified() > lastRunTime } }
+ }
+
+ tasks.named(name) {
+ dependsOn(tasks.named(javaName))
+ }
+}
+
+registerPalantir(name = "format", description = "Formats all Java source files.")
+registerPalantir(name = "lint", description = "Verifies all Java source files are formatted.")
diff --git a/buildSrc/src/main/kotlin/orb.kotlin.gradle.kts b/buildSrc/src/main/kotlin/orb.kotlin.gradle.kts
index 2d4a5c55c..b908b3bed 100644
--- a/buildSrc/src/main/kotlin/orb.kotlin.gradle.kts
+++ b/buildSrc/src/main/kotlin/orb.kotlin.gradle.kts
@@ -1,4 +1,3 @@
-import com.diffplug.gradle.spotless.SpotlessExtension
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
@@ -7,6 +6,10 @@ plugins {
kotlin("jvm")
}
+repositories {
+ mavenCentral()
+}
+
kotlin {
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of(21))
@@ -27,14 +30,77 @@ kotlin {
}
}
-configure {
- kotlin {
- ktfmt().kotlinlangStyle()
- toggleOffOn()
- }
-}
-
tasks.withType().configureEach {
systemProperty("junit.jupiter.execution.parallel.enabled", true)
systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent")
}
+
+val ktfmt by configurations.creating
+dependencies {
+ ktfmt("com.facebook:ktfmt:0.56")
+}
+
+fun registerKtfmt(
+ name: String,
+ description: String,
+) {
+ val kotlinName = "${name}Kotlin"
+ tasks.register(kotlinName) {
+ group = "Verification"
+ this.description = description
+
+ classpath = ktfmt
+ mainClass = "com.facebook.ktfmt.cli.Main"
+
+ // Use paths relative to the current module.
+ val argumentFile = project.layout.buildDirectory.file("ktfmt-$name-args.txt").get().asFile
+ val lastRunTimeFile =
+ project.layout.buildDirectory.file("ktfmt-$name-last-run.txt").get().asFile
+
+ // Read the time when this task was last executed for this module (if ever).
+ val lastRunTime = lastRunTimeFile.takeIf { it.exists() }?.readText()?.toLongOrNull() ?: 0L
+
+ // Use a `fileTree` relative to the module's source directory.
+ val kotlinFiles = project.fileTree("src") { include("**/*.kt") }
+
+ // Determine if any files need to be formatted or linted and continue only if there is at least
+ // one file (otherwise Ktfmt will fail).
+ onlyIf { kotlinFiles.any { it.lastModified() > lastRunTime } }
+
+ inputs.files(kotlinFiles)
+
+ doFirst {
+ // Create the argument file and set the preferred formatting style.
+ argumentFile.parentFile.mkdirs()
+ argumentFile.writeText("--kotlinlang-style\n")
+
+ if (name == "lint") {
+ // For lint, do a dry run, so no files are modified. Set the exit code to 1 (instead of
+ // the default 0) if any files need to be formatted, indicating that linting has failed.
+ argumentFile.appendText("--dry-run\n")
+ argumentFile.appendText("--set-exit-if-changed\n")
+ }
+
+ // Write the modified files to the argument file.
+ kotlinFiles.filter { it.lastModified() > lastRunTime }
+ .forEach { argumentFile.appendText("${it.absolutePath}\n") }
+ }
+
+ doLast {
+ // Record the last execution time for later up-to-date checking.
+ lastRunTimeFile.writeText(System.currentTimeMillis().toString())
+ }
+
+ // Pass the argument file using the @ symbol
+ args = listOf("@${argumentFile.absolutePath}")
+
+ outputs.upToDateWhen { kotlinFiles.none { it.lastModified() > lastRunTime } }
+ }
+
+ tasks.named(name) {
+ dependsOn(tasks.named(kotlinName))
+ }
+}
+
+registerKtfmt(name = "format", description = "Formats all Kotlin source files.")
+registerKtfmt(name = "lint", description = "Verifies all Kotlin source files are formatted.")
diff --git a/gradle.properties b/gradle.properties
index ff76593f6..6680f9ce9 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -4,12 +4,13 @@ org.gradle.parallel=true
org.gradle.daemon=false
# These options improve our compilation and test performance. They are inherited by the Kotlin daemon.
org.gradle.jvmargs=\
- -Xms1g \
- -Xmx4g \
+ -Xms2g \
+ -Xmx8g \
-XX:+UseParallelGC \
-XX:InitialCodeCacheSize=256m \
-XX:ReservedCodeCacheSize=1G \
- -XX:MetaspaceSize=256m \
+ -XX:MetaspaceSize=512m \
+ -XX:MaxMetaspaceSize=2G \
-XX:TieredStopAtLevel=1 \
-XX:GCTimeRatio=4 \
-XX:CICompilerCount=4 \
diff --git a/orb-java-client-okhttp/build.gradle.kts b/orb-java-client-okhttp/build.gradle.kts
index 9bb088c29..856cade40 100644
--- a/orb-java-client-okhttp/build.gradle.kts
+++ b/orb-java-client-okhttp/build.gradle.kts
@@ -11,4 +11,5 @@ dependencies {
testImplementation(kotlin("test"))
testImplementation("org.assertj:assertj-core:3.25.3")
+ testImplementation("com.github.tomakehurst:wiremock-jre8:2.35.2")
}
diff --git a/orb-java-client-okhttp/src/main/kotlin/com/withorb/api/client/okhttp/OkHttpClient.kt b/orb-java-client-okhttp/src/main/kotlin/com/withorb/api/client/okhttp/OkHttpClient.kt
index a7dade31c..4bf864205 100644
--- a/orb-java-client-okhttp/src/main/kotlin/com/withorb/api/client/okhttp/OkHttpClient.kt
+++ b/orb-java-client-okhttp/src/main/kotlin/com/withorb/api/client/okhttp/OkHttpClient.kt
@@ -13,6 +13,7 @@ import java.io.IOException
import java.io.InputStream
import java.net.Proxy
import java.time.Duration
+import java.util.concurrent.CancellationException
import java.util.concurrent.CompletableFuture
import javax.net.ssl.HostnameVerifier
import javax.net.ssl.SSLSocketFactory
@@ -29,8 +30,8 @@ import okhttp3.Response
import okhttp3.logging.HttpLoggingInterceptor
import okio.BufferedSink
-class OkHttpClient private constructor(private val okHttpClient: okhttp3.OkHttpClient) :
- HttpClient {
+class OkHttpClient
+private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClient) : HttpClient {
override fun execute(request: HttpRequest, requestOptions: RequestOptions): HttpResponse {
val call = newCall(request, requestOptions)
@@ -50,20 +51,25 @@ class OkHttpClient private constructor(private val okHttpClient: okhttp3.OkHttpC
): CompletableFuture {
val future = CompletableFuture()
- request.body?.run { future.whenComplete { _, _ -> close() } }
-
- newCall(request, requestOptions)
- .enqueue(
- object : Callback {
- override fun onResponse(call: Call, response: Response) {
- future.complete(response.toResponse())
- }
+ val call = newCall(request, requestOptions)
+ call.enqueue(
+ object : Callback {
+ override fun onResponse(call: Call, response: Response) {
+ future.complete(response.toResponse())
+ }
- override fun onFailure(call: Call, e: IOException) {
- future.completeExceptionally(OrbIoException("Request failed", e))
- }
+ override fun onFailure(call: Call, e: IOException) {
+ future.completeExceptionally(OrbIoException("Request failed", e))
}
- )
+ }
+ )
+
+ future.whenComplete { _, e ->
+ if (e is CancellationException) {
+ call.cancel()
+ }
+ request.body?.close()
+ }
return future
}
@@ -109,19 +115,19 @@ class OkHttpClient private constructor(private val okHttpClient: okhttp3.OkHttpC
val builder = Request.Builder().url(toUrl()).method(method.name, body)
headers.names().forEach { name ->
- headers.values(name).forEach { builder.header(name, it) }
+ headers.values(name).forEach { builder.addHeader(name, it) }
}
if (
!headers.names().contains("X-Stainless-Read-Timeout") && client.readTimeoutMillis != 0
) {
- builder.header(
+ builder.addHeader(
"X-Stainless-Read-Timeout",
Duration.ofMillis(client.readTimeoutMillis.toLong()).seconds.toString(),
)
}
if (!headers.names().contains("X-Stainless-Timeout") && client.callTimeoutMillis != 0) {
- builder.header(
+ builder.addHeader(
"X-Stainless-Timeout",
Duration.ofMillis(client.callTimeoutMillis.toLong()).seconds.toString(),
)
diff --git a/orb-java-client-okhttp/src/main/kotlin/com/withorb/api/client/okhttp/OrbOkHttpClient.kt b/orb-java-client-okhttp/src/main/kotlin/com/withorb/api/client/okhttp/OrbOkHttpClient.kt
index 931e530c0..a3fd603e2 100644
--- a/orb-java-client-okhttp/src/main/kotlin/com/withorb/api/client/okhttp/OrbOkHttpClient.kt
+++ b/orb-java-client-okhttp/src/main/kotlin/com/withorb/api/client/okhttp/OrbOkHttpClient.kt
@@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper
import com.withorb.api.client.OrbClient
import com.withorb.api.client.OrbClientImpl
import com.withorb.api.core.ClientOptions
+import com.withorb.api.core.Sleeper
import com.withorb.api.core.Timeout
import com.withorb.api.core.http.AsyncStreamResponse
import com.withorb.api.core.http.Headers
@@ -126,11 +127,24 @@ class OrbOkHttpClient private constructor() {
* The executor to use for running [AsyncStreamResponse.Handler] callbacks.
*
* Defaults to a dedicated cached thread pool.
+ *
+ * This class takes ownership of the executor and shuts it down, if possible, when closed.
*/
fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply {
clientOptions.streamHandlerExecutor(streamHandlerExecutor)
}
+ /**
+ * The interface to use for delaying execution, like during retries.
+ *
+ * This is primarily useful for using fake delays in tests.
+ *
+ * Defaults to real execution delays.
+ *
+ * This class takes ownership of the sleeper and closes it when closed.
+ */
+ fun sleeper(sleeper: Sleeper) = apply { clientOptions.sleeper(sleeper) }
+
/**
* The clock to use for operations that require timing, like retries.
*
diff --git a/orb-java-client-okhttp/src/main/kotlin/com/withorb/api/client/okhttp/OrbOkHttpClientAsync.kt b/orb-java-client-okhttp/src/main/kotlin/com/withorb/api/client/okhttp/OrbOkHttpClientAsync.kt
index 7c2423c73..88bdd9feb 100644
--- a/orb-java-client-okhttp/src/main/kotlin/com/withorb/api/client/okhttp/OrbOkHttpClientAsync.kt
+++ b/orb-java-client-okhttp/src/main/kotlin/com/withorb/api/client/okhttp/OrbOkHttpClientAsync.kt
@@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper
import com.withorb.api.client.OrbClientAsync
import com.withorb.api.client.OrbClientAsyncImpl
import com.withorb.api.core.ClientOptions
+import com.withorb.api.core.Sleeper
import com.withorb.api.core.Timeout
import com.withorb.api.core.http.AsyncStreamResponse
import com.withorb.api.core.http.Headers
@@ -126,11 +127,24 @@ class OrbOkHttpClientAsync private constructor() {
* The executor to use for running [AsyncStreamResponse.Handler] callbacks.
*
* Defaults to a dedicated cached thread pool.
+ *
+ * This class takes ownership of the executor and shuts it down, if possible, when closed.
*/
fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply {
clientOptions.streamHandlerExecutor(streamHandlerExecutor)
}
+ /**
+ * The interface to use for delaying execution, like during retries.
+ *
+ * This is primarily useful for using fake delays in tests.
+ *
+ * Defaults to real execution delays.
+ *
+ * This class takes ownership of the sleeper and closes it when closed.
+ */
+ fun sleeper(sleeper: Sleeper) = apply { clientOptions.sleeper(sleeper) }
+
/**
* The clock to use for operations that require timing, like retries.
*
diff --git a/orb-java-client-okhttp/src/test/kotlin/com/withorb/api/client/okhttp/OkHttpClientTest.kt b/orb-java-client-okhttp/src/test/kotlin/com/withorb/api/client/okhttp/OkHttpClientTest.kt
new file mode 100644
index 000000000..daa9ba709
--- /dev/null
+++ b/orb-java-client-okhttp/src/test/kotlin/com/withorb/api/client/okhttp/OkHttpClientTest.kt
@@ -0,0 +1,44 @@
+package com.withorb.api.client.okhttp
+
+import com.github.tomakehurst.wiremock.client.WireMock.*
+import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo
+import com.github.tomakehurst.wiremock.junit5.WireMockTest
+import com.withorb.api.core.http.HttpMethod
+import com.withorb.api.core.http.HttpRequest
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.parallel.ResourceLock
+
+@WireMockTest
+@ResourceLock("https://github.com/wiremock/wiremock/issues/169")
+internal class OkHttpClientTest {
+
+ private lateinit var baseUrl: String
+ private lateinit var httpClient: OkHttpClient
+
+ @BeforeEach
+ fun beforeEach(wmRuntimeInfo: WireMockRuntimeInfo) {
+ baseUrl = wmRuntimeInfo.httpBaseUrl
+ httpClient = OkHttpClient.builder().build()
+ }
+
+ @Test
+ fun executeAsync_whenFutureCancelled_cancelsUnderlyingCall() {
+ stubFor(post(urlPathEqualTo("/something")).willReturn(ok()))
+ val responseFuture =
+ httpClient.executeAsync(
+ HttpRequest.builder()
+ .method(HttpMethod.POST)
+ .baseUrl(baseUrl)
+ .addPathSegment("something")
+ .build()
+ )
+ val call = httpClient.okHttpClient.dispatcher.runningCalls().single()
+
+ responseFuture.cancel(false)
+
+ // Should have cancelled the underlying call
+ assertThat(call.isCanceled()).isTrue()
+ }
+}
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/client/OrbClientAsyncImpl.kt b/orb-java-core/src/main/kotlin/com/withorb/api/client/OrbClientAsyncImpl.kt
index fa0e22b01..4023c67f0 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/client/OrbClientAsyncImpl.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/client/OrbClientAsyncImpl.kt
@@ -153,7 +153,7 @@ class OrbClientAsyncImpl(private val clientOptions: ClientOptions) : OrbClientAs
override fun subscriptionChanges(): SubscriptionChangeServiceAsync = subscriptionChanges
- override fun close() = clientOptions.httpClient.close()
+ override fun close() = clientOptions.close()
class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) :
OrbClientAsync.WithRawResponse {
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/client/OrbClientImpl.kt b/orb-java-core/src/main/kotlin/com/withorb/api/client/OrbClientImpl.kt
index e3671e403..d086412ad 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/client/OrbClientImpl.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/client/OrbClientImpl.kt
@@ -146,7 +146,7 @@ class OrbClientImpl(private val clientOptions: ClientOptions) : OrbClient {
override fun subscriptionChanges(): SubscriptionChangeService = subscriptionChanges
- override fun close() = clientOptions.httpClient.close()
+ override fun close() = clientOptions.close()
class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) :
OrbClient.WithRawResponse {
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/core/ClientOptions.kt b/orb-java-core/src/main/kotlin/com/withorb/api/core/ClientOptions.kt
index b2464f279..cd66b87cb 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/core/ClientOptions.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/core/ClientOptions.kt
@@ -13,6 +13,7 @@ import java.time.Clock
import java.time.Duration
import java.util.Optional
import java.util.concurrent.Executor
+import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.ThreadFactory
import java.util.concurrent.atomic.AtomicLong
@@ -26,6 +27,8 @@ private constructor(
* The HTTP client to use in the SDK.
*
* Use the one published in `orb-java-client-okhttp` or implement your own.
+ *
+ * This class takes ownership of the client and closes it when closed.
*/
@get:JvmName("httpClient") val httpClient: HttpClient,
/**
@@ -47,8 +50,20 @@ private constructor(
* The executor to use for running [AsyncStreamResponse.Handler] callbacks.
*
* Defaults to a dedicated cached thread pool.
+ *
+ * This class takes ownership of the executor and shuts it down, if possible, when closed.
*/
@get:JvmName("streamHandlerExecutor") val streamHandlerExecutor: Executor,
+ /**
+ * The interface to use for delaying execution, like during retries.
+ *
+ * This is primarily useful for using fake delays in tests.
+ *
+ * Defaults to real execution delays.
+ *
+ * This class takes ownership of the sleeper and closes it when closed.
+ */
+ @get:JvmName("sleeper") val sleeper: Sleeper,
/**
* The clock to use for operations that require timing, like retries.
*
@@ -143,6 +158,7 @@ private constructor(
private var checkJacksonVersionCompatibility: Boolean = true
private var jsonMapper: JsonMapper = jsonMapper()
private var streamHandlerExecutor: Executor? = null
+ private var sleeper: Sleeper? = null
private var clock: Clock = Clock.systemUTC()
private var baseUrl: String? = null
private var headers: Headers.Builder = Headers.builder()
@@ -159,6 +175,7 @@ private constructor(
checkJacksonVersionCompatibility = clientOptions.checkJacksonVersionCompatibility
jsonMapper = clientOptions.jsonMapper
streamHandlerExecutor = clientOptions.streamHandlerExecutor
+ sleeper = clientOptions.sleeper
clock = clientOptions.clock
baseUrl = clientOptions.baseUrl
headers = clientOptions.headers.toBuilder()
@@ -174,6 +191,8 @@ private constructor(
* The HTTP client to use in the SDK.
*
* Use the one published in `orb-java-client-okhttp` or implement your own.
+ *
+ * This class takes ownership of the client and closes it when closed.
*/
fun httpClient(httpClient: HttpClient) = apply {
this.httpClient = PhantomReachableClosingHttpClient(httpClient)
@@ -202,11 +221,27 @@ private constructor(
* The executor to use for running [AsyncStreamResponse.Handler] callbacks.
*
* Defaults to a dedicated cached thread pool.
+ *
+ * This class takes ownership of the executor and shuts it down, if possible, when closed.
*/
fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply {
- this.streamHandlerExecutor = streamHandlerExecutor
+ this.streamHandlerExecutor =
+ if (streamHandlerExecutor is ExecutorService)
+ PhantomReachableExecutorService(streamHandlerExecutor)
+ else streamHandlerExecutor
}
+ /**
+ * The interface to use for delaying execution, like during retries.
+ *
+ * This is primarily useful for using fake delays in tests.
+ *
+ * Defaults to real execution delays.
+ *
+ * This class takes ownership of the sleeper and closes it when closed.
+ */
+ fun sleeper(sleeper: Sleeper) = apply { this.sleeper = PhantomReachableSleeper(sleeper) }
+
/**
* The clock to use for operations that require timing, like retries.
*
@@ -398,6 +433,25 @@ private constructor(
*/
fun build(): ClientOptions {
val httpClient = checkRequired("httpClient", httpClient)
+ val streamHandlerExecutor =
+ streamHandlerExecutor
+ ?: PhantomReachableExecutorService(
+ Executors.newCachedThreadPool(
+ object : ThreadFactory {
+
+ private val threadFactory: ThreadFactory =
+ Executors.defaultThreadFactory()
+ private val count = AtomicLong(0)
+
+ override fun newThread(runnable: Runnable): Thread =
+ threadFactory.newThread(runnable).also {
+ it.name =
+ "orb-stream-handler-thread-${count.getAndIncrement()}"
+ }
+ }
+ )
+ )
+ val sleeper = sleeper ?: PhantomReachableSleeper(DefaultSleeper())
val apiKey = checkRequired("apiKey", apiKey)
val headers = Headers.builder()
@@ -421,26 +475,15 @@ private constructor(
httpClient,
RetryingHttpClient.builder()
.httpClient(httpClient)
+ .sleeper(sleeper)
.clock(clock)
.maxRetries(maxRetries)
.idempotencyHeader("Idempotency-Key")
.build(),
checkJacksonVersionCompatibility,
jsonMapper,
- streamHandlerExecutor
- ?: Executors.newCachedThreadPool(
- object : ThreadFactory {
-
- private val threadFactory: ThreadFactory =
- Executors.defaultThreadFactory()
- private val count = AtomicLong(0)
-
- override fun newThread(runnable: Runnable): Thread =
- threadFactory.newThread(runnable).also {
- it.name = "orb-stream-handler-thread-${count.getAndIncrement()}"
- }
- }
- ),
+ streamHandlerExecutor,
+ sleeper,
clock,
baseUrl,
headers.build(),
@@ -453,4 +496,20 @@ private constructor(
)
}
}
+
+ /**
+ * Closes these client options, relinquishing any underlying resources.
+ *
+ * This is purposefully not inherited from [AutoCloseable] because the client options are
+ * long-lived and usually should not be synchronously closed via try-with-resources.
+ *
+ * It's also usually not necessary to call this method at all. the default client automatically
+ * releases threads and connections if they remain idle, but if you are writing an application
+ * that needs to aggressively release unused resources, then you may call this method.
+ */
+ fun close() {
+ httpClient.close()
+ (streamHandlerExecutor as? ExecutorService)?.shutdown()
+ sleeper.close()
+ }
}
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/core/DefaultSleeper.kt b/orb-java-core/src/main/kotlin/com/withorb/api/core/DefaultSleeper.kt
new file mode 100644
index 000000000..f80d76866
--- /dev/null
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/core/DefaultSleeper.kt
@@ -0,0 +1,28 @@
+package com.withorb.api.core
+
+import java.time.Duration
+import java.util.Timer
+import java.util.TimerTask
+import java.util.concurrent.CompletableFuture
+
+class DefaultSleeper : Sleeper {
+
+ private val timer = Timer("DefaultSleeper", true)
+
+ override fun sleep(duration: Duration) = Thread.sleep(duration.toMillis())
+
+ override fun sleepAsync(duration: Duration): CompletableFuture {
+ val future = CompletableFuture()
+ timer.schedule(
+ object : TimerTask() {
+ override fun run() {
+ future.complete(null)
+ }
+ },
+ duration.toMillis(),
+ )
+ return future
+ }
+
+ override fun close() = timer.cancel()
+}
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/core/PhantomReachableExecutorService.kt b/orb-java-core/src/main/kotlin/com/withorb/api/core/PhantomReachableExecutorService.kt
new file mode 100644
index 000000000..b4617be28
--- /dev/null
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/core/PhantomReachableExecutorService.kt
@@ -0,0 +1,58 @@
+package com.withorb.api.core
+
+import java.util.concurrent.Callable
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Future
+import java.util.concurrent.TimeUnit
+
+/**
+ * A delegating wrapper around an [ExecutorService] that shuts it down once it's only phantom
+ * reachable.
+ *
+ * This class ensures the [ExecutorService] is shut down even if the user forgets to do it.
+ */
+internal class PhantomReachableExecutorService(private val executorService: ExecutorService) :
+ ExecutorService {
+ init {
+ closeWhenPhantomReachable(this) { executorService.shutdown() }
+ }
+
+ override fun execute(command: Runnable) = executorService.execute(command)
+
+ override fun shutdown() = executorService.shutdown()
+
+ override fun shutdownNow(): MutableList = executorService.shutdownNow()
+
+ override fun isShutdown(): Boolean = executorService.isShutdown
+
+ override fun isTerminated(): Boolean = executorService.isTerminated
+
+ override fun awaitTermination(timeout: Long, unit: TimeUnit): Boolean =
+ executorService.awaitTermination(timeout, unit)
+
+ override fun submit(task: Callable): Future = executorService.submit(task)
+
+ override fun submit(task: Runnable, result: T): Future =
+ executorService.submit(task, result)
+
+ override fun submit(task: Runnable): Future<*> = executorService.submit(task)
+
+ override fun invokeAll(
+ tasks: MutableCollection>
+ ): MutableList> = executorService.invokeAll(tasks)
+
+ override fun invokeAll(
+ tasks: MutableCollection>,
+ timeout: Long,
+ unit: TimeUnit,
+ ): MutableList> = executorService.invokeAll(tasks, timeout, unit)
+
+ override fun invokeAny(tasks: MutableCollection>): T =
+ executorService.invokeAny(tasks)
+
+ override fun invokeAny(
+ tasks: MutableCollection>,
+ timeout: Long,
+ unit: TimeUnit,
+ ): T = executorService.invokeAny(tasks, timeout, unit)
+}
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/core/PhantomReachableSleeper.kt b/orb-java-core/src/main/kotlin/com/withorb/api/core/PhantomReachableSleeper.kt
new file mode 100644
index 000000000..32a73ac1a
--- /dev/null
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/core/PhantomReachableSleeper.kt
@@ -0,0 +1,23 @@
+package com.withorb.api.core
+
+import java.time.Duration
+import java.util.concurrent.CompletableFuture
+
+/**
+ * A delegating wrapper around a [Sleeper] that closes it once it's only phantom reachable.
+ *
+ * This class ensures the [Sleeper] is closed even if the user forgets to do it.
+ */
+internal class PhantomReachableSleeper(private val sleeper: Sleeper) : Sleeper {
+
+ init {
+ closeWhenPhantomReachable(this, sleeper)
+ }
+
+ override fun sleep(duration: Duration) = sleeper.sleep(duration)
+
+ override fun sleepAsync(duration: Duration): CompletableFuture =
+ sleeper.sleepAsync(duration)
+
+ override fun close() = sleeper.close()
+}
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/core/Properties.kt b/orb-java-core/src/main/kotlin/com/withorb/api/core/Properties.kt
index 9045e4dbf..f0f63ba44 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/core/Properties.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/core/Properties.kt
@@ -2,7 +2,7 @@
package com.withorb.api.core
-import java.util.Properties
+import com.withorb.api.client.OrbClient
fun getOsArch(): String {
val osArch = System.getProperty("os.arch")
@@ -16,7 +16,7 @@ fun getOsArch(): String {
"x86_64" -> "x64"
"arm" -> "arm"
"aarch64" -> "arm64"
- else -> "other:${osArch}"
+ else -> "other:$osArch"
}
}
@@ -30,13 +30,12 @@ fun getOsName(): String {
osName.startsWith("Linux") -> "Linux"
osName.startsWith("Mac OS") -> "MacOS"
osName.startsWith("Windows") -> "Windows"
- else -> "Other:${osName}"
+ else -> "Other:$osName"
}
}
fun getOsVersion(): String = System.getProperty("os.version", "unknown")
-fun getPackageVersion(): String =
- Properties::class.java.`package`.implementationVersion ?: "unknown"
+fun getPackageVersion(): String = OrbClient::class.java.`package`.implementationVersion ?: "unknown"
fun getJavaVersion(): String = System.getProperty("java.version", "unknown")
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/core/Sleeper.kt b/orb-java-core/src/main/kotlin/com/withorb/api/core/Sleeper.kt
new file mode 100644
index 000000000..a10a12ead
--- /dev/null
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/core/Sleeper.kt
@@ -0,0 +1,21 @@
+package com.withorb.api.core
+
+import java.time.Duration
+import java.util.concurrent.CompletableFuture
+
+/**
+ * An interface for delaying execution for a specified amount of time.
+ *
+ * Useful for testing and cleaning up resources.
+ */
+interface Sleeper : AutoCloseable {
+
+ /** Synchronously pauses execution for the given [duration]. */
+ fun sleep(duration: Duration)
+
+ /** Asynchronously pauses execution for the given [duration]. */
+ fun sleepAsync(duration: Duration): CompletableFuture
+
+ /** Overridden from [AutoCloseable] to not have a checked exception in its signature. */
+ override fun close()
+}
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/core/Timeout.kt b/orb-java-core/src/main/kotlin/com/withorb/api/core/Timeout.kt
index 182de0a90..0da3dbe91 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/core/Timeout.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/core/Timeout.kt
@@ -157,10 +157,14 @@ private constructor(
return true
}
- return /* spotless:off */ other is Timeout && connect == other.connect && read == other.read && write == other.write && request == other.request /* spotless:on */
+ return other is Timeout &&
+ connect == other.connect &&
+ read == other.read &&
+ write == other.write &&
+ request == other.request
}
- override fun hashCode(): Int = /* spotless:off */ Objects.hash(connect, read, write, request) /* spotless:on */
+ override fun hashCode(): Int = Objects.hash(connect, read, write, request)
override fun toString() =
"Timeout{connect=$connect, read=$read, write=$write, request=$request}"
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/core/Utils.kt b/orb-java-core/src/main/kotlin/com/withorb/api/core/Utils.kt
index e0ad480db..c392401d6 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/core/Utils.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/core/Utils.kt
@@ -6,6 +6,8 @@ import com.withorb.api.core.http.Headers
import com.withorb.api.errors.OrbInvalidDataException
import java.util.Collections
import java.util.SortedMap
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.locks.Lock
@JvmSynthetic
internal fun T?.getOrThrow(name: String): T =
@@ -95,3 +97,24 @@ internal fun Headers.getRequiredHeader(name: String): String =
values(name).firstOrNull() ?: throw OrbInvalidDataException("Could not find $name header")
internal interface Enum
+
+/**
+ * Executes the given [action] while holding the lock, returning a [CompletableFuture] with the
+ * result.
+ *
+ * @param action The asynchronous action to execute while holding the lock
+ * @return A [CompletableFuture] that completes with the result of the action
+ */
+@JvmSynthetic
+internal fun Lock.withLockAsync(action: () -> CompletableFuture): CompletableFuture {
+ lock()
+ val future =
+ try {
+ action()
+ } catch (e: Throwable) {
+ unlock()
+ throw e
+ }
+ future.whenComplete { _, _ -> unlock() }
+ return future
+}
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/core/http/RetryingHttpClient.kt b/orb-java-core/src/main/kotlin/com/withorb/api/core/http/RetryingHttpClient.kt
index cba6f15bc..e53177d25 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/core/http/RetryingHttpClient.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/core/http/RetryingHttpClient.kt
@@ -1,8 +1,11 @@
package com.withorb.api.core.http
+import com.withorb.api.core.DefaultSleeper
import com.withorb.api.core.RequestOptions
+import com.withorb.api.core.Sleeper
import com.withorb.api.core.checkRequired
import com.withorb.api.errors.OrbIoException
+import com.withorb.api.errors.OrbRetryableException
import java.io.IOException
import java.time.Clock
import java.time.Duration
@@ -10,8 +13,6 @@ import java.time.OffsetDateTime
import java.time.format.DateTimeFormatter
import java.time.format.DateTimeParseException
import java.time.temporal.ChronoUnit
-import java.util.Timer
-import java.util.TimerTask
import java.util.UUID
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ThreadLocalRandom
@@ -129,7 +130,10 @@ private constructor(
return executeWithRetries(modifiedRequest, requestOptions)
}
- override fun close() = httpClient.close()
+ override fun close() {
+ httpClient.close()
+ sleeper.close()
+ }
private fun isRetryable(request: HttpRequest): Boolean =
// Some requests, such as when a request body is being streamed, cannot be retried because
@@ -176,9 +180,10 @@ private constructor(
}
private fun shouldRetry(throwable: Throwable): Boolean =
- // Only retry IOException and OrbIoException, other exceptions are not intended to be
- // retried.
- throwable is IOException || throwable is OrbIoException
+ // Only retry known retryable exceptions, other exceptions are not intended to be retried.
+ throwable is IOException ||
+ throwable is OrbIoException ||
+ throwable is OrbRetryableException
private fun getRetryBackoffDuration(retries: Int, response: HttpResponse?): Duration {
// About the Retry-After header:
@@ -233,33 +238,14 @@ private constructor(
class Builder internal constructor() {
private var httpClient: HttpClient? = null
- private var sleeper: Sleeper =
- object : Sleeper {
-
- private val timer = Timer("RetryingHttpClient", true)
-
- override fun sleep(duration: Duration) = Thread.sleep(duration.toMillis())
-
- override fun sleepAsync(duration: Duration): CompletableFuture {
- val future = CompletableFuture()
- timer.schedule(
- object : TimerTask() {
- override fun run() {
- future.complete(null)
- }
- },
- duration.toMillis(),
- )
- return future
- }
- }
+ private var sleeper: Sleeper? = null
private var clock: Clock = Clock.systemUTC()
private var maxRetries: Int = 2
private var idempotencyHeader: String? = null
fun httpClient(httpClient: HttpClient) = apply { this.httpClient = httpClient }
- @JvmSynthetic internal fun sleeper(sleeper: Sleeper) = apply { this.sleeper = sleeper }
+ fun sleeper(sleeper: Sleeper) = apply { this.sleeper = sleeper }
fun clock(clock: Clock) = apply { this.clock = clock }
@@ -270,17 +256,10 @@ private constructor(
fun build(): HttpClient =
RetryingHttpClient(
checkRequired("httpClient", httpClient),
- sleeper,
+ sleeper ?: DefaultSleeper(),
clock,
maxRetries,
idempotencyHeader,
)
}
-
- internal interface Sleeper {
-
- fun sleep(duration: Duration)
-
- fun sleepAsync(duration: Duration): CompletableFuture
- }
}
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/errors/OrbRetryableException.kt b/orb-java-core/src/main/kotlin/com/withorb/api/errors/OrbRetryableException.kt
new file mode 100644
index 000000000..61061c4e3
--- /dev/null
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/errors/OrbRetryableException.kt
@@ -0,0 +1,14 @@
+package com.withorb.api.errors
+
+/**
+ * Exception that indicates a transient error that can be retried.
+ *
+ * When this exception is thrown during an HTTP request, the SDK will automatically retry the
+ * request up to the maximum number of retries.
+ *
+ * @param message A descriptive error message
+ * @param cause The underlying cause of this exception, if any
+ */
+class OrbRetryableException
+@JvmOverloads
+constructor(message: String? = null, cause: Throwable? = null) : OrbException(message, cause)
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AccountingProviderConfig.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AccountingProviderConfig.kt
index 9b5fa1d3b..bfbf6c224 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AccountingProviderConfig.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AccountingProviderConfig.kt
@@ -16,6 +16,7 @@ import java.util.Collections
import java.util.Objects
class AccountingProviderConfig
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val externalProviderId: JsonField,
private val providerType: JsonField,
@@ -205,12 +206,15 @@ private constructor(
return true
}
- return /* spotless:off */ other is AccountingProviderConfig && externalProviderId == other.externalProviderId && providerType == other.providerType && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is AccountingProviderConfig &&
+ externalProviderId == other.externalProviderId &&
+ providerType == other.providerType &&
+ additionalProperties == other.additionalProperties
}
- /* spotless:off */
- private val hashCode: Int by lazy { Objects.hash(externalProviderId, providerType, additionalProperties) }
- /* spotless:on */
+ private val hashCode: Int by lazy {
+ Objects.hash(externalProviderId, providerType, additionalProperties)
+ }
override fun hashCode(): Int = hashCode
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/Address.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/Address.kt
index 9ddf4805d..de9c14aed 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/Address.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/Address.kt
@@ -18,6 +18,7 @@ import java.util.Optional
import kotlin.jvm.optionals.getOrNull
class Address
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val city: JsonField,
private val country: JsonField,
@@ -340,12 +341,19 @@ private constructor(
return true
}
- return /* spotless:off */ other is Address && city == other.city && country == other.country && line1 == other.line1 && line2 == other.line2 && postalCode == other.postalCode && state == other.state && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is Address &&
+ city == other.city &&
+ country == other.country &&
+ line1 == other.line1 &&
+ line2 == other.line2 &&
+ postalCode == other.postalCode &&
+ state == other.state &&
+ additionalProperties == other.additionalProperties
}
- /* spotless:off */
- private val hashCode: Int by lazy { Objects.hash(city, country, line1, line2, postalCode, state, additionalProperties) }
- /* spotless:on */
+ private val hashCode: Int by lazy {
+ Objects.hash(city, country, line1, line2, postalCode, state, additionalProperties)
+ }
override fun hashCode(): Int = hashCode
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AddressInput.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AddressInput.kt
index 25b700c00..9dbc4e7fe 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AddressInput.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AddressInput.kt
@@ -17,6 +17,7 @@ import java.util.Optional
import kotlin.jvm.optionals.getOrNull
class AddressInput
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val city: JsonField,
private val country: JsonField,
@@ -315,12 +316,19 @@ private constructor(
return true
}
- return /* spotless:off */ other is AddressInput && city == other.city && country == other.country && line1 == other.line1 && line2 == other.line2 && postalCode == other.postalCode && state == other.state && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is AddressInput &&
+ city == other.city &&
+ country == other.country &&
+ line1 == other.line1 &&
+ line2 == other.line2 &&
+ postalCode == other.postalCode &&
+ state == other.state &&
+ additionalProperties == other.additionalProperties
}
- /* spotless:off */
- private val hashCode: Int by lazy { Objects.hash(city, country, line1, line2, postalCode, state, additionalProperties) }
- /* spotless:on */
+ private val hashCode: Int by lazy {
+ Objects.hash(city, country, line1, line2, postalCode, state, additionalProperties)
+ }
override fun hashCode(): Int = hashCode
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AdjustmentInterval.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AdjustmentInterval.kt
index 7fe9f69ed..17115a571 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AdjustmentInterval.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AdjustmentInterval.kt
@@ -31,6 +31,7 @@ import java.util.Optional
import kotlin.jvm.optionals.getOrNull
class AdjustmentInterval
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val id: JsonField,
private val adjustment: JsonField,
@@ -512,10 +513,16 @@ private constructor(
return true
}
- return /* spotless:off */ other is Adjustment && usageDiscount == other.usageDiscount && amountDiscount == other.amountDiscount && percentageDiscount == other.percentageDiscount && minimum == other.minimum && maximum == other.maximum /* spotless:on */
+ return other is Adjustment &&
+ usageDiscount == other.usageDiscount &&
+ amountDiscount == other.amountDiscount &&
+ percentageDiscount == other.percentageDiscount &&
+ minimum == other.minimum &&
+ maximum == other.maximum
}
- override fun hashCode(): Int = /* spotless:off */ Objects.hash(usageDiscount, amountDiscount, percentageDiscount, minimum, maximum) /* spotless:on */
+ override fun hashCode(): Int =
+ Objects.hash(usageDiscount, amountDiscount, percentageDiscount, minimum, maximum)
override fun toString(): String =
when {
@@ -655,12 +662,25 @@ private constructor(
return true
}
- return /* spotless:off */ other is AdjustmentInterval && id == other.id && adjustment == other.adjustment && appliesToPriceIntervalIds == other.appliesToPriceIntervalIds && endDate == other.endDate && startDate == other.startDate && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is AdjustmentInterval &&
+ id == other.id &&
+ adjustment == other.adjustment &&
+ appliesToPriceIntervalIds == other.appliesToPriceIntervalIds &&
+ endDate == other.endDate &&
+ startDate == other.startDate &&
+ additionalProperties == other.additionalProperties
}
- /* spotless:off */
- private val hashCode: Int by lazy { Objects.hash(id, adjustment, appliesToPriceIntervalIds, endDate, startDate, additionalProperties) }
- /* spotless:on */
+ private val hashCode: Int by lazy {
+ Objects.hash(
+ id,
+ adjustment,
+ appliesToPriceIntervalIds,
+ endDate,
+ startDate,
+ additionalProperties,
+ )
+ }
override fun hashCode(): Int = hashCode
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AffectedBlock.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AffectedBlock.kt
index ab3de3150..342db5eb0 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AffectedBlock.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AffectedBlock.kt
@@ -6,11 +6,14 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter
import com.fasterxml.jackson.annotation.JsonAnySetter
import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty
+import com.withorb.api.core.Enum
import com.withorb.api.core.ExcludeMissing
import com.withorb.api.core.JsonField
import com.withorb.api.core.JsonMissing
import com.withorb.api.core.JsonValue
+import com.withorb.api.core.checkKnown
import com.withorb.api.core.checkRequired
+import com.withorb.api.core.toImmutable
import com.withorb.api.errors.OrbInvalidDataException
import java.time.OffsetDateTime
import java.util.Collections
@@ -19,9 +22,11 @@ import java.util.Optional
import kotlin.jvm.optionals.getOrNull
class AffectedBlock
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val id: JsonField,
private val expiryDate: JsonField,
+ private val filters: JsonField>,
private val perUnitCostBasis: JsonField,
private val additionalProperties: MutableMap,
) {
@@ -32,10 +37,13 @@ private constructor(
@JsonProperty("expiry_date")
@ExcludeMissing
expiryDate: JsonField = JsonMissing.of(),
+ @JsonProperty("filters")
+ @ExcludeMissing
+ filters: JsonField> = JsonMissing.of(),
@JsonProperty("per_unit_cost_basis")
@ExcludeMissing
perUnitCostBasis: JsonField = JsonMissing.of(),
- ) : this(id, expiryDate, perUnitCostBasis, mutableMapOf())
+ ) : this(id, expiryDate, filters, perUnitCostBasis, mutableMapOf())
/**
* @throws OrbInvalidDataException if the JSON field has an unexpected type or is unexpectedly
@@ -49,6 +57,12 @@ private constructor(
*/
fun expiryDate(): Optional = expiryDate.getOptional("expiry_date")
+ /**
+ * @throws OrbInvalidDataException if the JSON field has an unexpected type or is unexpectedly
+ * missing or null (e.g. if the server responded with an unexpected value).
+ */
+ fun filters(): List = filters.getRequired("filters")
+
/**
* @throws OrbInvalidDataException if the JSON field has an unexpected type (e.g. if the server
* responded with an unexpected value).
@@ -71,6 +85,13 @@ private constructor(
@ExcludeMissing
fun _expiryDate(): JsonField = expiryDate
+ /**
+ * Returns the raw JSON value of [filters].
+ *
+ * Unlike [filters], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("filters") @ExcludeMissing fun _filters(): JsonField> = filters
+
/**
* Returns the raw JSON value of [perUnitCostBasis].
*
@@ -102,6 +123,7 @@ private constructor(
* ```java
* .id()
* .expiryDate()
+ * .filters()
* .perUnitCostBasis()
* ```
*/
@@ -113,6 +135,7 @@ private constructor(
private var id: JsonField? = null
private var expiryDate: JsonField? = null
+ private var filters: JsonField>? = null
private var perUnitCostBasis: JsonField? = null
private var additionalProperties: MutableMap = mutableMapOf()
@@ -120,6 +143,7 @@ private constructor(
internal fun from(affectedBlock: AffectedBlock) = apply {
id = affectedBlock.id
expiryDate = affectedBlock.expiryDate
+ filters = affectedBlock.filters.map { it.toMutableList() }
perUnitCostBasis = affectedBlock.perUnitCostBasis
additionalProperties = affectedBlock.additionalProperties.toMutableMap()
}
@@ -150,6 +174,31 @@ private constructor(
this.expiryDate = expiryDate
}
+ fun filters(filters: List) = filters(JsonField.of(filters))
+
+ /**
+ * Sets [Builder.filters] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.filters] with a well-typed `List` value instead.
+ * This method is primarily for setting the field to an undocumented or not yet supported
+ * value.
+ */
+ fun filters(filters: JsonField>) = apply {
+ this.filters = filters.map { it.toMutableList() }
+ }
+
+ /**
+ * Adds a single [Filter] to [filters].
+ *
+ * @throws IllegalStateException if the field was previously set to a non-list.
+ */
+ fun addFilter(filter: Filter) = apply {
+ filters =
+ (filters ?: JsonField.of(mutableListOf())).also {
+ checkKnown("filters", it).add(filter)
+ }
+ }
+
fun perUnitCostBasis(perUnitCostBasis: String?) =
perUnitCostBasis(JsonField.ofNullable(perUnitCostBasis))
@@ -196,6 +245,7 @@ private constructor(
* ```java
* .id()
* .expiryDate()
+ * .filters()
* .perUnitCostBasis()
* ```
*
@@ -205,6 +255,7 @@ private constructor(
AffectedBlock(
checkRequired("id", id),
checkRequired("expiryDate", expiryDate),
+ checkRequired("filters", filters).map { it.toImmutable() },
checkRequired("perUnitCostBasis", perUnitCostBasis),
additionalProperties.toMutableMap(),
)
@@ -219,6 +270,7 @@ private constructor(
id()
expiryDate()
+ filters().forEach { it.validate() }
perUnitCostBasis()
validated = true
}
@@ -240,22 +292,558 @@ private constructor(
internal fun validity(): Int =
(if (id.asKnown().isPresent) 1 else 0) +
(if (expiryDate.asKnown().isPresent) 1 else 0) +
+ (filters.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) +
(if (perUnitCostBasis.asKnown().isPresent) 1 else 0)
+ class Filter
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
+ private constructor(
+ private val field: JsonField,
+ private val operator: JsonField,
+ private val values: JsonField>,
+ private val additionalProperties: MutableMap,
+ ) {
+
+ @JsonCreator
+ private constructor(
+ @JsonProperty("field") @ExcludeMissing field: JsonField = JsonMissing.of(),
+ @JsonProperty("operator")
+ @ExcludeMissing
+ operator: JsonField = JsonMissing.of(),
+ @JsonProperty("values")
+ @ExcludeMissing
+ values: JsonField> = JsonMissing.of(),
+ ) : this(field, operator, values, mutableMapOf())
+
+ /**
+ * The property of the price to filter on.
+ *
+ * @throws OrbInvalidDataException if the JSON field has an unexpected type or is
+ * unexpectedly missing or null (e.g. if the server responded with an unexpected value).
+ */
+ fun field(): Field = field.getRequired("field")
+
+ /**
+ * Should prices that match the filter be included or excluded.
+ *
+ * @throws OrbInvalidDataException if the JSON field has an unexpected type or is
+ * unexpectedly missing or null (e.g. if the server responded with an unexpected value).
+ */
+ fun operator(): Operator = operator.getRequired("operator")
+
+ /**
+ * The IDs or values that match this filter.
+ *
+ * @throws OrbInvalidDataException if the JSON field has an unexpected type or is
+ * unexpectedly missing or null (e.g. if the server responded with an unexpected value).
+ */
+ fun values(): List = values.getRequired("values")
+
+ /**
+ * Returns the raw JSON value of [field].
+ *
+ * Unlike [field], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("field") @ExcludeMissing fun _field(): JsonField = field
+
+ /**
+ * Returns the raw JSON value of [operator].
+ *
+ * Unlike [operator], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("operator") @ExcludeMissing fun _operator(): JsonField = operator
+
+ /**
+ * Returns the raw JSON value of [values].
+ *
+ * Unlike [values], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("values") @ExcludeMissing fun _values(): JsonField> = values
+
+ @JsonAnySetter
+ private fun putAdditionalProperty(key: String, value: JsonValue) {
+ additionalProperties.put(key, value)
+ }
+
+ @JsonAnyGetter
+ @ExcludeMissing
+ fun _additionalProperties(): Map =
+ Collections.unmodifiableMap(additionalProperties)
+
+ fun toBuilder() = Builder().from(this)
+
+ companion object {
+
+ /**
+ * Returns a mutable builder for constructing an instance of [Filter].
+ *
+ * The following fields are required:
+ * ```java
+ * .field()
+ * .operator()
+ * .values()
+ * ```
+ */
+ @JvmStatic fun builder() = Builder()
+ }
+
+ /** A builder for [Filter]. */
+ class Builder internal constructor() {
+
+ private var field: JsonField? = null
+ private var operator: JsonField? = null
+ private var values: JsonField>? = null
+ private var additionalProperties: MutableMap = mutableMapOf()
+
+ @JvmSynthetic
+ internal fun from(filter: Filter) = apply {
+ field = filter.field
+ operator = filter.operator
+ values = filter.values.map { it.toMutableList() }
+ additionalProperties = filter.additionalProperties.toMutableMap()
+ }
+
+ /** The property of the price to filter on. */
+ fun field(field: Field) = field(JsonField.of(field))
+
+ /**
+ * Sets [Builder.field] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.field] with a well-typed [Field] value instead. This
+ * method is primarily for setting the field to an undocumented or not yet supported
+ * value.
+ */
+ fun field(field: JsonField) = apply { this.field = field }
+
+ /** Should prices that match the filter be included or excluded. */
+ fun operator(operator: Operator) = operator(JsonField.of(operator))
+
+ /**
+ * Sets [Builder.operator] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.operator] with a well-typed [Operator] value
+ * instead. This method is primarily for setting the field to an undocumented or not yet
+ * supported value.
+ */
+ fun operator(operator: JsonField) = apply { this.operator = operator }
+
+ /** The IDs or values that match this filter. */
+ fun values(values: List) = values(JsonField.of(values))
+
+ /**
+ * Sets [Builder.values] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.values] with a well-typed `List` value
+ * instead. This method is primarily for setting the field to an undocumented or not yet
+ * supported value.
+ */
+ fun values(values: JsonField>) = apply {
+ this.values = values.map { it.toMutableList() }
+ }
+
+ /**
+ * Adds a single [String] to [values].
+ *
+ * @throws IllegalStateException if the field was previously set to a non-list.
+ */
+ fun addValue(value: String) = apply {
+ values =
+ (values ?: JsonField.of(mutableListOf())).also {
+ checkKnown("values", it).add(value)
+ }
+ }
+
+ fun additionalProperties(additionalProperties: Map) = apply {
+ this.additionalProperties.clear()
+ putAllAdditionalProperties(additionalProperties)
+ }
+
+ fun putAdditionalProperty(key: String, value: JsonValue) = apply {
+ additionalProperties.put(key, value)
+ }
+
+ fun putAllAdditionalProperties(additionalProperties: Map) = apply {
+ this.additionalProperties.putAll(additionalProperties)
+ }
+
+ fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) }
+
+ fun removeAllAdditionalProperties(keys: Set) = apply {
+ keys.forEach(::removeAdditionalProperty)
+ }
+
+ /**
+ * Returns an immutable instance of [Filter].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ *
+ * The following fields are required:
+ * ```java
+ * .field()
+ * .operator()
+ * .values()
+ * ```
+ *
+ * @throws IllegalStateException if any required field is unset.
+ */
+ fun build(): Filter =
+ Filter(
+ checkRequired("field", field),
+ checkRequired("operator", operator),
+ checkRequired("values", values).map { it.toImmutable() },
+ additionalProperties.toMutableMap(),
+ )
+ }
+
+ private var validated: Boolean = false
+
+ fun validate(): Filter = apply {
+ if (validated) {
+ return@apply
+ }
+
+ field().validate()
+ operator().validate()
+ values()
+ validated = true
+ }
+
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: OrbInvalidDataException) {
+ false
+ }
+
+ /**
+ * Returns a score indicating how many valid values are contained in this object
+ * recursively.
+ *
+ * Used for best match union deserialization.
+ */
+ @JvmSynthetic
+ internal fun validity(): Int =
+ (field.asKnown().getOrNull()?.validity() ?: 0) +
+ (operator.asKnown().getOrNull()?.validity() ?: 0) +
+ (values.asKnown().getOrNull()?.size ?: 0)
+
+ /** The property of the price to filter on. */
+ class Field @JsonCreator private constructor(private val value: JsonField) : Enum {
+
+ /**
+ * Returns this class instance's raw value.
+ *
+ * This is usually only useful if this instance was deserialized from data that doesn't
+ * match any known member, and you want to know that value. For example, if the SDK is
+ * on an older version than the API, then the API may respond with new members that the
+ * SDK is unaware of.
+ */
+ @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value
+
+ companion object {
+
+ @JvmField val PRICE_ID = of("price_id")
+
+ @JvmField val ITEM_ID = of("item_id")
+
+ @JvmField val PRICE_TYPE = of("price_type")
+
+ @JvmField val CURRENCY = of("currency")
+
+ @JvmField val PRICING_UNIT_ID = of("pricing_unit_id")
+
+ @JvmStatic fun of(value: String) = Field(JsonField.of(value))
+ }
+
+ /** An enum containing [Field]'s known values. */
+ enum class Known {
+ PRICE_ID,
+ ITEM_ID,
+ PRICE_TYPE,
+ CURRENCY,
+ PRICING_UNIT_ID,
+ }
+
+ /**
+ * An enum containing [Field]'s known values, as well as an [_UNKNOWN] member.
+ *
+ * An instance of [Field] can contain an unknown value in a couple of cases:
+ * - It was deserialized from data that doesn't match any known member. For example, if
+ * the SDK is on an older version than the API, then the API may respond with new
+ * members that the SDK is unaware of.
+ * - It was constructed with an arbitrary value using the [of] method.
+ */
+ enum class Value {
+ PRICE_ID,
+ ITEM_ID,
+ PRICE_TYPE,
+ CURRENCY,
+ PRICING_UNIT_ID,
+ /**
+ * An enum member indicating that [Field] was instantiated with an unknown value.
+ */
+ _UNKNOWN,
+ }
+
+ /**
+ * Returns an enum member corresponding to this class instance's value, or
+ * [Value._UNKNOWN] if the class was instantiated with an unknown value.
+ *
+ * Use the [known] method instead if you're certain the value is always known or if you
+ * want to throw for the unknown case.
+ */
+ fun value(): Value =
+ when (this) {
+ PRICE_ID -> Value.PRICE_ID
+ ITEM_ID -> Value.ITEM_ID
+ PRICE_TYPE -> Value.PRICE_TYPE
+ CURRENCY -> Value.CURRENCY
+ PRICING_UNIT_ID -> Value.PRICING_UNIT_ID
+ else -> Value._UNKNOWN
+ }
+
+ /**
+ * Returns an enum member corresponding to this class instance's value.
+ *
+ * Use the [value] method instead if you're uncertain the value is always known and
+ * don't want to throw for the unknown case.
+ *
+ * @throws OrbInvalidDataException if this class instance's value is a not a known
+ * member.
+ */
+ fun known(): Known =
+ when (this) {
+ PRICE_ID -> Known.PRICE_ID
+ ITEM_ID -> Known.ITEM_ID
+ PRICE_TYPE -> Known.PRICE_TYPE
+ CURRENCY -> Known.CURRENCY
+ PRICING_UNIT_ID -> Known.PRICING_UNIT_ID
+ else -> throw OrbInvalidDataException("Unknown Field: $value")
+ }
+
+ /**
+ * Returns this class instance's primitive wire representation.
+ *
+ * This differs from the [toString] method because that method is primarily for
+ * debugging and generally doesn't throw.
+ *
+ * @throws OrbInvalidDataException if this class instance's value does not have the
+ * expected primitive type.
+ */
+ fun asString(): String =
+ _value().asString().orElseThrow { OrbInvalidDataException("Value is not a String") }
+
+ private var validated: Boolean = false
+
+ fun validate(): Field = apply {
+ if (validated) {
+ return@apply
+ }
+
+ known()
+ validated = true
+ }
+
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: OrbInvalidDataException) {
+ false
+ }
+
+ /**
+ * Returns a score indicating how many valid values are contained in this object
+ * recursively.
+ *
+ * Used for best match union deserialization.
+ */
+ @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is Field && value == other.value
+ }
+
+ override fun hashCode() = value.hashCode()
+
+ override fun toString() = value.toString()
+ }
+
+ /** Should prices that match the filter be included or excluded. */
+ class Operator @JsonCreator private constructor(private val value: JsonField) :
+ Enum {
+
+ /**
+ * Returns this class instance's raw value.
+ *
+ * This is usually only useful if this instance was deserialized from data that doesn't
+ * match any known member, and you want to know that value. For example, if the SDK is
+ * on an older version than the API, then the API may respond with new members that the
+ * SDK is unaware of.
+ */
+ @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value
+
+ companion object {
+
+ @JvmField val INCLUDES = of("includes")
+
+ @JvmField val EXCLUDES = of("excludes")
+
+ @JvmStatic fun of(value: String) = Operator(JsonField.of(value))
+ }
+
+ /** An enum containing [Operator]'s known values. */
+ enum class Known {
+ INCLUDES,
+ EXCLUDES,
+ }
+
+ /**
+ * An enum containing [Operator]'s known values, as well as an [_UNKNOWN] member.
+ *
+ * An instance of [Operator] can contain an unknown value in a couple of cases:
+ * - It was deserialized from data that doesn't match any known member. For example, if
+ * the SDK is on an older version than the API, then the API may respond with new
+ * members that the SDK is unaware of.
+ * - It was constructed with an arbitrary value using the [of] method.
+ */
+ enum class Value {
+ INCLUDES,
+ EXCLUDES,
+ /**
+ * An enum member indicating that [Operator] was instantiated with an unknown value.
+ */
+ _UNKNOWN,
+ }
+
+ /**
+ * Returns an enum member corresponding to this class instance's value, or
+ * [Value._UNKNOWN] if the class was instantiated with an unknown value.
+ *
+ * Use the [known] method instead if you're certain the value is always known or if you
+ * want to throw for the unknown case.
+ */
+ fun value(): Value =
+ when (this) {
+ INCLUDES -> Value.INCLUDES
+ EXCLUDES -> Value.EXCLUDES
+ else -> Value._UNKNOWN
+ }
+
+ /**
+ * Returns an enum member corresponding to this class instance's value.
+ *
+ * Use the [value] method instead if you're uncertain the value is always known and
+ * don't want to throw for the unknown case.
+ *
+ * @throws OrbInvalidDataException if this class instance's value is a not a known
+ * member.
+ */
+ fun known(): Known =
+ when (this) {
+ INCLUDES -> Known.INCLUDES
+ EXCLUDES -> Known.EXCLUDES
+ else -> throw OrbInvalidDataException("Unknown Operator: $value")
+ }
+
+ /**
+ * Returns this class instance's primitive wire representation.
+ *
+ * This differs from the [toString] method because that method is primarily for
+ * debugging and generally doesn't throw.
+ *
+ * @throws OrbInvalidDataException if this class instance's value does not have the
+ * expected primitive type.
+ */
+ fun asString(): String =
+ _value().asString().orElseThrow { OrbInvalidDataException("Value is not a String") }
+
+ private var validated: Boolean = false
+
+ fun validate(): Operator = apply {
+ if (validated) {
+ return@apply
+ }
+
+ known()
+ validated = true
+ }
+
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: OrbInvalidDataException) {
+ false
+ }
+
+ /**
+ * Returns a score indicating how many valid values are contained in this object
+ * recursively.
+ *
+ * Used for best match union deserialization.
+ */
+ @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is Operator && value == other.value
+ }
+
+ override fun hashCode() = value.hashCode()
+
+ override fun toString() = value.toString()
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is Filter &&
+ field == other.field &&
+ operator == other.operator &&
+ values == other.values &&
+ additionalProperties == other.additionalProperties
+ }
+
+ private val hashCode: Int by lazy {
+ Objects.hash(field, operator, values, additionalProperties)
+ }
+
+ override fun hashCode(): Int = hashCode
+
+ override fun toString() =
+ "Filter{field=$field, operator=$operator, values=$values, additionalProperties=$additionalProperties}"
+ }
+
override fun equals(other: Any?): Boolean {
if (this === other) {
return true
}
- return /* spotless:off */ other is AffectedBlock && id == other.id && expiryDate == other.expiryDate && perUnitCostBasis == other.perUnitCostBasis && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is AffectedBlock &&
+ id == other.id &&
+ expiryDate == other.expiryDate &&
+ filters == other.filters &&
+ perUnitCostBasis == other.perUnitCostBasis &&
+ additionalProperties == other.additionalProperties
}
- /* spotless:off */
- private val hashCode: Int by lazy { Objects.hash(id, expiryDate, perUnitCostBasis, additionalProperties) }
- /* spotless:on */
+ private val hashCode: Int by lazy {
+ Objects.hash(id, expiryDate, filters, perUnitCostBasis, additionalProperties)
+ }
override fun hashCode(): Int = hashCode
override fun toString() =
- "AffectedBlock{id=$id, expiryDate=$expiryDate, perUnitCostBasis=$perUnitCostBasis, additionalProperties=$additionalProperties}"
+ "AffectedBlock{id=$id, expiryDate=$expiryDate, filters=$filters, perUnitCostBasis=$perUnitCostBasis, additionalProperties=$additionalProperties}"
}
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AggregatedCost.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AggregatedCost.kt
index 06198fab3..132a3db87 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AggregatedCost.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AggregatedCost.kt
@@ -20,6 +20,7 @@ import java.util.Objects
import kotlin.jvm.optionals.getOrNull
class AggregatedCost
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val perPriceCosts: JsonField>,
private val subtotal: JsonField,
@@ -330,12 +331,25 @@ private constructor(
return true
}
- return /* spotless:off */ other is AggregatedCost && perPriceCosts == other.perPriceCosts && subtotal == other.subtotal && timeframeEnd == other.timeframeEnd && timeframeStart == other.timeframeStart && total == other.total && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is AggregatedCost &&
+ perPriceCosts == other.perPriceCosts &&
+ subtotal == other.subtotal &&
+ timeframeEnd == other.timeframeEnd &&
+ timeframeStart == other.timeframeStart &&
+ total == other.total &&
+ additionalProperties == other.additionalProperties
}
- /* spotless:off */
- private val hashCode: Int by lazy { Objects.hash(perPriceCosts, subtotal, timeframeEnd, timeframeStart, total, additionalProperties) }
- /* spotless:on */
+ private val hashCode: Int by lazy {
+ Objects.hash(
+ perPriceCosts,
+ subtotal,
+ timeframeEnd,
+ timeframeStart,
+ total,
+ additionalProperties,
+ )
+ }
override fun hashCode(): Int = hashCode
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/Alert.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/Alert.kt
index 3d7bc9376..f35084b4a 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/Alert.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/Alert.kt
@@ -28,6 +28,7 @@ import kotlin.jvm.optionals.getOrNull
* Alerts created through the API can be scoped to either customers or subscriptions.
*/
class Alert
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val id: JsonField,
private val createdAt: JsonField,
@@ -616,6 +617,7 @@ private constructor(
/** The metric the alert applies to. */
class Metric
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val id: JsonField,
private val additionalProperties: MutableMap,
@@ -754,12 +756,12 @@ private constructor(
return true
}
- return /* spotless:off */ other is Metric && id == other.id && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is Metric &&
+ id == other.id &&
+ additionalProperties == other.additionalProperties
}
- /* spotless:off */
private val hashCode: Int by lazy { Objects.hash(id, additionalProperties) }
- /* spotless:on */
override fun hashCode(): Int = hashCode
@@ -768,6 +770,7 @@ private constructor(
/** The plan the alert applies to. */
class Plan
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val id: JsonField,
private val externalPlanId: JsonField,
@@ -1043,12 +1046,17 @@ private constructor(
return true
}
- return /* spotless:off */ other is Plan && id == other.id && externalPlanId == other.externalPlanId && name == other.name && planVersion == other.planVersion && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is Plan &&
+ id == other.id &&
+ externalPlanId == other.externalPlanId &&
+ name == other.name &&
+ planVersion == other.planVersion &&
+ additionalProperties == other.additionalProperties
}
- /* spotless:off */
- private val hashCode: Int by lazy { Objects.hash(id, externalPlanId, name, planVersion, additionalProperties) }
- /* spotless:on */
+ private val hashCode: Int by lazy {
+ Objects.hash(id, externalPlanId, name, planVersion, additionalProperties)
+ }
override fun hashCode(): Int = hashCode
@@ -1191,7 +1199,7 @@ private constructor(
return true
}
- return /* spotless:off */ other is Type && value == other.value /* spotless:on */
+ return other is Type && value == other.value
}
override fun hashCode() = value.hashCode()
@@ -1201,6 +1209,7 @@ private constructor(
/** Alert status is used to determine if an alert is currently in-alert or not. */
class BalanceAlertStatus
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val inAlert: JsonField,
private val thresholdValue: JsonField,
@@ -1393,12 +1402,15 @@ private constructor(
return true
}
- return /* spotless:off */ other is BalanceAlertStatus && inAlert == other.inAlert && thresholdValue == other.thresholdValue && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is BalanceAlertStatus &&
+ inAlert == other.inAlert &&
+ thresholdValue == other.thresholdValue &&
+ additionalProperties == other.additionalProperties
}
- /* spotless:off */
- private val hashCode: Int by lazy { Objects.hash(inAlert, thresholdValue, additionalProperties) }
- /* spotless:on */
+ private val hashCode: Int by lazy {
+ Objects.hash(inAlert, thresholdValue, additionalProperties)
+ }
override fun hashCode(): Int = hashCode
@@ -1411,12 +1423,37 @@ private constructor(
return true
}
- return /* spotless:off */ other is Alert && id == other.id && createdAt == other.createdAt && currency == other.currency && customer == other.customer && enabled == other.enabled && metric == other.metric && plan == other.plan && subscription == other.subscription && thresholds == other.thresholds && type == other.type && balanceAlertStatus == other.balanceAlertStatus && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is Alert &&
+ id == other.id &&
+ createdAt == other.createdAt &&
+ currency == other.currency &&
+ customer == other.customer &&
+ enabled == other.enabled &&
+ metric == other.metric &&
+ plan == other.plan &&
+ subscription == other.subscription &&
+ thresholds == other.thresholds &&
+ type == other.type &&
+ balanceAlertStatus == other.balanceAlertStatus &&
+ additionalProperties == other.additionalProperties
}
- /* spotless:off */
- private val hashCode: Int by lazy { Objects.hash(id, createdAt, currency, customer, enabled, metric, plan, subscription, thresholds, type, balanceAlertStatus, additionalProperties) }
- /* spotless:on */
+ private val hashCode: Int by lazy {
+ Objects.hash(
+ id,
+ createdAt,
+ currency,
+ customer,
+ enabled,
+ metric,
+ plan,
+ subscription,
+ thresholds,
+ type,
+ balanceAlertStatus,
+ additionalProperties,
+ )
+ }
override fun hashCode(): Int = hashCode
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertCreateForCustomerParams.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertCreateForCustomerParams.kt
index 01c066405..23046502e 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertCreateForCustomerParams.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertCreateForCustomerParams.kt
@@ -340,6 +340,7 @@ private constructor(
override fun _queryParams(): QueryParams = additionalQueryParams
class Body
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val currency: JsonField,
private val type: JsonField,
@@ -581,12 +582,16 @@ private constructor(
return true
}
- return /* spotless:off */ other is Body && currency == other.currency && type == other.type && thresholds == other.thresholds && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is Body &&
+ currency == other.currency &&
+ type == other.type &&
+ thresholds == other.thresholds &&
+ additionalProperties == other.additionalProperties
}
- /* spotless:off */
- private val hashCode: Int by lazy { Objects.hash(currency, type, thresholds, additionalProperties) }
- /* spotless:on */
+ private val hashCode: Int by lazy {
+ Objects.hash(currency, type, thresholds, additionalProperties)
+ }
override fun hashCode(): Int = hashCode
@@ -717,7 +722,7 @@ private constructor(
return true
}
- return /* spotless:off */ other is Type && value == other.value /* spotless:on */
+ return other is Type && value == other.value
}
override fun hashCode() = value.hashCode()
@@ -730,10 +735,15 @@ private constructor(
return true
}
- return /* spotless:off */ other is AlertCreateForCustomerParams && customerId == other.customerId && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */
+ return other is AlertCreateForCustomerParams &&
+ customerId == other.customerId &&
+ body == other.body &&
+ additionalHeaders == other.additionalHeaders &&
+ additionalQueryParams == other.additionalQueryParams
}
- override fun hashCode(): Int = /* spotless:off */ Objects.hash(customerId, body, additionalHeaders, additionalQueryParams) /* spotless:on */
+ override fun hashCode(): Int =
+ Objects.hash(customerId, body, additionalHeaders, additionalQueryParams)
override fun toString() =
"AlertCreateForCustomerParams{customerId=$customerId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}"
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertCreateForExternalCustomerParams.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertCreateForExternalCustomerParams.kt
index 6852ecd0f..e33329641 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertCreateForExternalCustomerParams.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertCreateForExternalCustomerParams.kt
@@ -349,6 +349,7 @@ private constructor(
override fun _queryParams(): QueryParams = additionalQueryParams
class Body
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val currency: JsonField,
private val type: JsonField,
@@ -590,12 +591,16 @@ private constructor(
return true
}
- return /* spotless:off */ other is Body && currency == other.currency && type == other.type && thresholds == other.thresholds && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is Body &&
+ currency == other.currency &&
+ type == other.type &&
+ thresholds == other.thresholds &&
+ additionalProperties == other.additionalProperties
}
- /* spotless:off */
- private val hashCode: Int by lazy { Objects.hash(currency, type, thresholds, additionalProperties) }
- /* spotless:on */
+ private val hashCode: Int by lazy {
+ Objects.hash(currency, type, thresholds, additionalProperties)
+ }
override fun hashCode(): Int = hashCode
@@ -726,7 +731,7 @@ private constructor(
return true
}
- return /* spotless:off */ other is Type && value == other.value /* spotless:on */
+ return other is Type && value == other.value
}
override fun hashCode() = value.hashCode()
@@ -739,10 +744,15 @@ private constructor(
return true
}
- return /* spotless:off */ other is AlertCreateForExternalCustomerParams && externalCustomerId == other.externalCustomerId && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */
+ return other is AlertCreateForExternalCustomerParams &&
+ externalCustomerId == other.externalCustomerId &&
+ body == other.body &&
+ additionalHeaders == other.additionalHeaders &&
+ additionalQueryParams == other.additionalQueryParams
}
- override fun hashCode(): Int = /* spotless:off */ Objects.hash(externalCustomerId, body, additionalHeaders, additionalQueryParams) /* spotless:on */
+ override fun hashCode(): Int =
+ Objects.hash(externalCustomerId, body, additionalHeaders, additionalQueryParams)
override fun toString() =
"AlertCreateForExternalCustomerParams{externalCustomerId=$externalCustomerId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}"
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertCreateForSubscriptionParams.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertCreateForSubscriptionParams.kt
index 0f3748d63..7329b98c4 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertCreateForSubscriptionParams.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertCreateForSubscriptionParams.kt
@@ -348,6 +348,7 @@ private constructor(
override fun _queryParams(): QueryParams = additionalQueryParams
class Body
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val thresholds: JsonField>,
private val type: JsonField,
@@ -587,12 +588,16 @@ private constructor(
return true
}
- return /* spotless:off */ other is Body && thresholds == other.thresholds && type == other.type && metricId == other.metricId && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is Body &&
+ thresholds == other.thresholds &&
+ type == other.type &&
+ metricId == other.metricId &&
+ additionalProperties == other.additionalProperties
}
- /* spotless:off */
- private val hashCode: Int by lazy { Objects.hash(thresholds, type, metricId, additionalProperties) }
- /* spotless:on */
+ private val hashCode: Int by lazy {
+ Objects.hash(thresholds, type, metricId, additionalProperties)
+ }
override fun hashCode(): Int = hashCode
@@ -717,7 +722,7 @@ private constructor(
return true
}
- return /* spotless:off */ other is Type && value == other.value /* spotless:on */
+ return other is Type && value == other.value
}
override fun hashCode() = value.hashCode()
@@ -730,10 +735,15 @@ private constructor(
return true
}
- return /* spotless:off */ other is AlertCreateForSubscriptionParams && subscriptionId == other.subscriptionId && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */
+ return other is AlertCreateForSubscriptionParams &&
+ subscriptionId == other.subscriptionId &&
+ body == other.body &&
+ additionalHeaders == other.additionalHeaders &&
+ additionalQueryParams == other.additionalQueryParams
}
- override fun hashCode(): Int = /* spotless:off */ Objects.hash(subscriptionId, body, additionalHeaders, additionalQueryParams) /* spotless:on */
+ override fun hashCode(): Int =
+ Objects.hash(subscriptionId, body, additionalHeaders, additionalQueryParams)
override fun toString() =
"AlertCreateForSubscriptionParams{subscriptionId=$subscriptionId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}"
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertDisableParams.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertDisableParams.kt
index 5ad3565f5..009f1233d 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertDisableParams.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertDisableParams.kt
@@ -244,10 +244,22 @@ private constructor(
return true
}
- return /* spotless:off */ other is AlertDisableParams && alertConfigurationId == other.alertConfigurationId && subscriptionId == other.subscriptionId && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams && additionalBodyProperties == other.additionalBodyProperties /* spotless:on */
+ return other is AlertDisableParams &&
+ alertConfigurationId == other.alertConfigurationId &&
+ subscriptionId == other.subscriptionId &&
+ additionalHeaders == other.additionalHeaders &&
+ additionalQueryParams == other.additionalQueryParams &&
+ additionalBodyProperties == other.additionalBodyProperties
}
- override fun hashCode(): Int = /* spotless:off */ Objects.hash(alertConfigurationId, subscriptionId, additionalHeaders, additionalQueryParams, additionalBodyProperties) /* spotless:on */
+ override fun hashCode(): Int =
+ Objects.hash(
+ alertConfigurationId,
+ subscriptionId,
+ additionalHeaders,
+ additionalQueryParams,
+ additionalBodyProperties,
+ )
override fun toString() =
"AlertDisableParams{alertConfigurationId=$alertConfigurationId, subscriptionId=$subscriptionId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}"
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertEnableParams.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertEnableParams.kt
index d7dc775f0..65cfb8a82 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertEnableParams.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertEnableParams.kt
@@ -244,10 +244,22 @@ private constructor(
return true
}
- return /* spotless:off */ other is AlertEnableParams && alertConfigurationId == other.alertConfigurationId && subscriptionId == other.subscriptionId && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams && additionalBodyProperties == other.additionalBodyProperties /* spotless:on */
+ return other is AlertEnableParams &&
+ alertConfigurationId == other.alertConfigurationId &&
+ subscriptionId == other.subscriptionId &&
+ additionalHeaders == other.additionalHeaders &&
+ additionalQueryParams == other.additionalQueryParams &&
+ additionalBodyProperties == other.additionalBodyProperties
}
- override fun hashCode(): Int = /* spotless:off */ Objects.hash(alertConfigurationId, subscriptionId, additionalHeaders, additionalQueryParams, additionalBodyProperties) /* spotless:on */
+ override fun hashCode(): Int =
+ Objects.hash(
+ alertConfigurationId,
+ subscriptionId,
+ additionalHeaders,
+ additionalQueryParams,
+ additionalBodyProperties,
+ )
override fun toString() =
"AlertEnableParams{alertConfigurationId=$alertConfigurationId, subscriptionId=$subscriptionId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}"
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertListPage.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertListPage.kt
index 04cab0536..c1a378dab 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertListPage.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertListPage.kt
@@ -122,10 +122,13 @@ private constructor(
return true
}
- return /* spotless:off */ other is AlertListPage && service == other.service && params == other.params && response == other.response /* spotless:on */
+ return other is AlertListPage &&
+ service == other.service &&
+ params == other.params &&
+ response == other.response
}
- override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */
+ override fun hashCode(): Int = Objects.hash(service, params, response)
override fun toString() = "AlertListPage{service=$service, params=$params, response=$response}"
}
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertListPageAsync.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertListPageAsync.kt
index aee23ad70..579d43539 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertListPageAsync.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertListPageAsync.kt
@@ -134,10 +134,14 @@ private constructor(
return true
}
- return /* spotless:off */ other is AlertListPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */
+ return other is AlertListPageAsync &&
+ service == other.service &&
+ streamHandlerExecutor == other.streamHandlerExecutor &&
+ params == other.params &&
+ response == other.response
}
- override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */
+ override fun hashCode(): Int = Objects.hash(service, streamHandlerExecutor, params, response)
override fun toString() =
"AlertListPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}"
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertListPageResponse.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertListPageResponse.kt
index 76540e990..bfa4b2799 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertListPageResponse.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertListPageResponse.kt
@@ -19,6 +19,7 @@ import java.util.Objects
import kotlin.jvm.optionals.getOrNull
class AlertListPageResponse
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val data: JsonField>,
private val paginationMetadata: JsonField,
@@ -217,12 +218,15 @@ private constructor(
return true
}
- return /* spotless:off */ other is AlertListPageResponse && data == other.data && paginationMetadata == other.paginationMetadata && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is AlertListPageResponse &&
+ data == other.data &&
+ paginationMetadata == other.paginationMetadata &&
+ additionalProperties == other.additionalProperties
}
- /* spotless:off */
- private val hashCode: Int by lazy { Objects.hash(data, paginationMetadata, additionalProperties) }
- /* spotless:on */
+ private val hashCode: Int by lazy {
+ Objects.hash(data, paginationMetadata, additionalProperties)
+ }
override fun hashCode(): Int = hashCode
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertListParams.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertListParams.kt
index 9e9689ef7..a95f34f59 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertListParams.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertListParams.kt
@@ -16,7 +16,7 @@ import kotlin.jvm.optionals.getOrNull
*
* The request must specify one of `customer_id`, `external_customer_id`, or `subscription_id`.
*
- * If querying by subscripion_id, the endpoint will return the subscription level alerts as well as
+ * If querying by subscription_id, the endpoint will return the subscription level alerts as well as
* the plan level alerts associated with the subscription.
*
* The list of alerts is ordered starting from the most recently created alert. This endpoint
@@ -329,10 +329,34 @@ private constructor(
return true
}
- return /* spotless:off */ other is AlertListParams && createdAtGt == other.createdAtGt && createdAtGte == other.createdAtGte && createdAtLt == other.createdAtLt && createdAtLte == other.createdAtLte && cursor == other.cursor && customerId == other.customerId && externalCustomerId == other.externalCustomerId && limit == other.limit && subscriptionId == other.subscriptionId && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */
+ return other is AlertListParams &&
+ createdAtGt == other.createdAtGt &&
+ createdAtGte == other.createdAtGte &&
+ createdAtLt == other.createdAtLt &&
+ createdAtLte == other.createdAtLte &&
+ cursor == other.cursor &&
+ customerId == other.customerId &&
+ externalCustomerId == other.externalCustomerId &&
+ limit == other.limit &&
+ subscriptionId == other.subscriptionId &&
+ additionalHeaders == other.additionalHeaders &&
+ additionalQueryParams == other.additionalQueryParams
}
- override fun hashCode(): Int = /* spotless:off */ Objects.hash(createdAtGt, createdAtGte, createdAtLt, createdAtLte, cursor, customerId, externalCustomerId, limit, subscriptionId, additionalHeaders, additionalQueryParams) /* spotless:on */
+ override fun hashCode(): Int =
+ Objects.hash(
+ createdAtGt,
+ createdAtGte,
+ createdAtLt,
+ createdAtLte,
+ cursor,
+ customerId,
+ externalCustomerId,
+ limit,
+ subscriptionId,
+ additionalHeaders,
+ additionalQueryParams,
+ )
override fun toString() =
"AlertListParams{createdAtGt=$createdAtGt, createdAtGte=$createdAtGte, createdAtLt=$createdAtLt, createdAtLte=$createdAtLte, cursor=$cursor, customerId=$customerId, externalCustomerId=$externalCustomerId, limit=$limit, subscriptionId=$subscriptionId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}"
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertRetrieveParams.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertRetrieveParams.kt
index 23daf4dd1..293640ff0 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertRetrieveParams.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertRetrieveParams.kt
@@ -176,10 +176,13 @@ private constructor(
return true
}
- return /* spotless:off */ other is AlertRetrieveParams && alertId == other.alertId && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */
+ return other is AlertRetrieveParams &&
+ alertId == other.alertId &&
+ additionalHeaders == other.additionalHeaders &&
+ additionalQueryParams == other.additionalQueryParams
}
- override fun hashCode(): Int = /* spotless:off */ Objects.hash(alertId, additionalHeaders, additionalQueryParams) /* spotless:on */
+ override fun hashCode(): Int = Objects.hash(alertId, additionalHeaders, additionalQueryParams)
override fun toString() =
"AlertRetrieveParams{alertId=$alertId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}"
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertUpdateParams.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertUpdateParams.kt
index 6a2e123e9..96f3f152b 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertUpdateParams.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AlertUpdateParams.kt
@@ -279,6 +279,7 @@ private constructor(
override fun _queryParams(): QueryParams = additionalQueryParams
class Body
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val thresholds: JsonField>,
private val additionalProperties: MutableMap,
@@ -443,12 +444,12 @@ private constructor(
return true
}
- return /* spotless:off */ other is Body && thresholds == other.thresholds && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is Body &&
+ thresholds == other.thresholds &&
+ additionalProperties == other.additionalProperties
}
- /* spotless:off */
private val hashCode: Int by lazy { Objects.hash(thresholds, additionalProperties) }
- /* spotless:on */
override fun hashCode(): Int = hashCode
@@ -461,10 +462,15 @@ private constructor(
return true
}
- return /* spotless:off */ other is AlertUpdateParams && alertConfigurationId == other.alertConfigurationId && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */
+ return other is AlertUpdateParams &&
+ alertConfigurationId == other.alertConfigurationId &&
+ body == other.body &&
+ additionalHeaders == other.additionalHeaders &&
+ additionalQueryParams == other.additionalQueryParams
}
- override fun hashCode(): Int = /* spotless:off */ Objects.hash(alertConfigurationId, body, additionalHeaders, additionalQueryParams) /* spotless:on */
+ override fun hashCode(): Int =
+ Objects.hash(alertConfigurationId, body, additionalHeaders, additionalQueryParams)
override fun toString() =
"AlertUpdateParams{alertConfigurationId=$alertConfigurationId, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}"
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/Allocation.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/Allocation.kt
index 440e9c087..ab6fd5234 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/Allocation.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/Allocation.kt
@@ -6,11 +6,14 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter
import com.fasterxml.jackson.annotation.JsonAnySetter
import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty
+import com.withorb.api.core.Enum
import com.withorb.api.core.ExcludeMissing
import com.withorb.api.core.JsonField
import com.withorb.api.core.JsonMissing
import com.withorb.api.core.JsonValue
+import com.withorb.api.core.checkKnown
import com.withorb.api.core.checkRequired
+import com.withorb.api.core.toImmutable
import com.withorb.api.errors.OrbInvalidDataException
import java.util.Collections
import java.util.Objects
@@ -18,10 +21,12 @@ import java.util.Optional
import kotlin.jvm.optionals.getOrNull
class Allocation
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val allowsRollover: JsonField,
private val currency: JsonField,
private val customExpiration: JsonField,
+ private val filters: JsonField>,
private val additionalProperties: MutableMap,
) {
@@ -34,7 +39,8 @@ private constructor(
@JsonProperty("custom_expiration")
@ExcludeMissing
customExpiration: JsonField = JsonMissing.of(),
- ) : this(allowsRollover, currency, customExpiration, mutableMapOf())
+ @JsonProperty("filters") @ExcludeMissing filters: JsonField> = JsonMissing.of(),
+ ) : this(allowsRollover, currency, customExpiration, filters, mutableMapOf())
/**
* @throws OrbInvalidDataException if the JSON field has an unexpected type or is unexpectedly
@@ -55,6 +61,12 @@ private constructor(
fun customExpiration(): Optional =
customExpiration.getOptional("custom_expiration")
+ /**
+ * @throws OrbInvalidDataException if the JSON field has an unexpected type (e.g. if the server
+ * responded with an unexpected value).
+ */
+ fun filters(): Optional> = filters.getOptional("filters")
+
/**
* Returns the raw JSON value of [allowsRollover].
*
@@ -81,6 +93,13 @@ private constructor(
@ExcludeMissing
fun _customExpiration(): JsonField = customExpiration
+ /**
+ * Returns the raw JSON value of [filters].
+ *
+ * Unlike [filters], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("filters") @ExcludeMissing fun _filters(): JsonField> = filters
+
@JsonAnySetter
private fun putAdditionalProperty(key: String, value: JsonValue) {
additionalProperties.put(key, value)
@@ -114,6 +133,7 @@ private constructor(
private var allowsRollover: JsonField? = null
private var currency: JsonField? = null
private var customExpiration: JsonField? = null
+ private var filters: JsonField>? = null
private var additionalProperties: MutableMap = mutableMapOf()
@JvmSynthetic
@@ -121,6 +141,7 @@ private constructor(
allowsRollover = allocation.allowsRollover
currency = allocation.currency
customExpiration = allocation.customExpiration
+ filters = allocation.filters.map { it.toMutableList() }
additionalProperties = allocation.additionalProperties.toMutableMap()
}
@@ -165,6 +186,31 @@ private constructor(
this.customExpiration = customExpiration
}
+ fun filters(filters: List) = filters(JsonField.of(filters))
+
+ /**
+ * Sets [Builder.filters] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.filters] with a well-typed `List` value instead.
+ * This method is primarily for setting the field to an undocumented or not yet supported
+ * value.
+ */
+ fun filters(filters: JsonField>) = apply {
+ this.filters = filters.map { it.toMutableList() }
+ }
+
+ /**
+ * Adds a single [Filter] to [filters].
+ *
+ * @throws IllegalStateException if the field was previously set to a non-list.
+ */
+ fun addFilter(filter: Filter) = apply {
+ filters =
+ (filters ?: JsonField.of(mutableListOf())).also {
+ checkKnown("filters", it).add(filter)
+ }
+ }
+
fun additionalProperties(additionalProperties: Map) = apply {
this.additionalProperties.clear()
putAllAdditionalProperties(additionalProperties)
@@ -203,6 +249,7 @@ private constructor(
checkRequired("allowsRollover", allowsRollover),
checkRequired("currency", currency),
checkRequired("customExpiration", customExpiration),
+ (filters ?: JsonMissing.of()).map { it.toImmutable() },
additionalProperties.toMutableMap(),
)
}
@@ -217,6 +264,7 @@ private constructor(
allowsRollover()
currency()
customExpiration().ifPresent { it.validate() }
+ filters().ifPresent { it.forEach { it.validate() } }
validated = true
}
@@ -237,22 +285,558 @@ private constructor(
internal fun validity(): Int =
(if (allowsRollover.asKnown().isPresent) 1 else 0) +
(if (currency.asKnown().isPresent) 1 else 0) +
- (customExpiration.asKnown().getOrNull()?.validity() ?: 0)
+ (customExpiration.asKnown().getOrNull()?.validity() ?: 0) +
+ (filters.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0)
+
+ class Filter
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
+ private constructor(
+ private val field: JsonField,
+ private val operator: JsonField,
+ private val values: JsonField>,
+ private val additionalProperties: MutableMap,
+ ) {
+
+ @JsonCreator
+ private constructor(
+ @JsonProperty("field") @ExcludeMissing field: JsonField = JsonMissing.of(),
+ @JsonProperty("operator")
+ @ExcludeMissing
+ operator: JsonField = JsonMissing.of(),
+ @JsonProperty("values")
+ @ExcludeMissing
+ values: JsonField> = JsonMissing.of(),
+ ) : this(field, operator, values, mutableMapOf())
+
+ /**
+ * The property of the price to filter on.
+ *
+ * @throws OrbInvalidDataException if the JSON field has an unexpected type or is
+ * unexpectedly missing or null (e.g. if the server responded with an unexpected value).
+ */
+ fun field(): Field = field.getRequired("field")
+
+ /**
+ * Should prices that match the filter be included or excluded.
+ *
+ * @throws OrbInvalidDataException if the JSON field has an unexpected type or is
+ * unexpectedly missing or null (e.g. if the server responded with an unexpected value).
+ */
+ fun operator(): Operator = operator.getRequired("operator")
+
+ /**
+ * The IDs or values that match this filter.
+ *
+ * @throws OrbInvalidDataException if the JSON field has an unexpected type or is
+ * unexpectedly missing or null (e.g. if the server responded with an unexpected value).
+ */
+ fun values(): List = values.getRequired("values")
+
+ /**
+ * Returns the raw JSON value of [field].
+ *
+ * Unlike [field], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("field") @ExcludeMissing fun _field(): JsonField = field
+
+ /**
+ * Returns the raw JSON value of [operator].
+ *
+ * Unlike [operator], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("operator") @ExcludeMissing fun _operator(): JsonField = operator
+
+ /**
+ * Returns the raw JSON value of [values].
+ *
+ * Unlike [values], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("values") @ExcludeMissing fun _values(): JsonField> = values
+
+ @JsonAnySetter
+ private fun putAdditionalProperty(key: String, value: JsonValue) {
+ additionalProperties.put(key, value)
+ }
+
+ @JsonAnyGetter
+ @ExcludeMissing
+ fun _additionalProperties(): Map =
+ Collections.unmodifiableMap(additionalProperties)
+
+ fun toBuilder() = Builder().from(this)
+
+ companion object {
+
+ /**
+ * Returns a mutable builder for constructing an instance of [Filter].
+ *
+ * The following fields are required:
+ * ```java
+ * .field()
+ * .operator()
+ * .values()
+ * ```
+ */
+ @JvmStatic fun builder() = Builder()
+ }
+
+ /** A builder for [Filter]. */
+ class Builder internal constructor() {
+
+ private var field: JsonField? = null
+ private var operator: JsonField? = null
+ private var values: JsonField>? = null
+ private var additionalProperties: MutableMap = mutableMapOf()
+
+ @JvmSynthetic
+ internal fun from(filter: Filter) = apply {
+ field = filter.field
+ operator = filter.operator
+ values = filter.values.map { it.toMutableList() }
+ additionalProperties = filter.additionalProperties.toMutableMap()
+ }
+
+ /** The property of the price to filter on. */
+ fun field(field: Field) = field(JsonField.of(field))
+
+ /**
+ * Sets [Builder.field] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.field] with a well-typed [Field] value instead. This
+ * method is primarily for setting the field to an undocumented or not yet supported
+ * value.
+ */
+ fun field(field: JsonField) = apply { this.field = field }
+
+ /** Should prices that match the filter be included or excluded. */
+ fun operator(operator: Operator) = operator(JsonField.of(operator))
+
+ /**
+ * Sets [Builder.operator] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.operator] with a well-typed [Operator] value
+ * instead. This method is primarily for setting the field to an undocumented or not yet
+ * supported value.
+ */
+ fun operator(operator: JsonField) = apply { this.operator = operator }
+
+ /** The IDs or values that match this filter. */
+ fun values(values: List) = values(JsonField.of(values))
+
+ /**
+ * Sets [Builder.values] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.values] with a well-typed `List` value
+ * instead. This method is primarily for setting the field to an undocumented or not yet
+ * supported value.
+ */
+ fun values(values: JsonField>) = apply {
+ this.values = values.map { it.toMutableList() }
+ }
+
+ /**
+ * Adds a single [String] to [values].
+ *
+ * @throws IllegalStateException if the field was previously set to a non-list.
+ */
+ fun addValue(value: String) = apply {
+ values =
+ (values ?: JsonField.of(mutableListOf())).also {
+ checkKnown("values", it).add(value)
+ }
+ }
+
+ fun additionalProperties(additionalProperties: Map) = apply {
+ this.additionalProperties.clear()
+ putAllAdditionalProperties(additionalProperties)
+ }
+
+ fun putAdditionalProperty(key: String, value: JsonValue) = apply {
+ additionalProperties.put(key, value)
+ }
+
+ fun putAllAdditionalProperties(additionalProperties: Map) = apply {
+ this.additionalProperties.putAll(additionalProperties)
+ }
+
+ fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) }
+
+ fun removeAllAdditionalProperties(keys: Set) = apply {
+ keys.forEach(::removeAdditionalProperty)
+ }
+
+ /**
+ * Returns an immutable instance of [Filter].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ *
+ * The following fields are required:
+ * ```java
+ * .field()
+ * .operator()
+ * .values()
+ * ```
+ *
+ * @throws IllegalStateException if any required field is unset.
+ */
+ fun build(): Filter =
+ Filter(
+ checkRequired("field", field),
+ checkRequired("operator", operator),
+ checkRequired("values", values).map { it.toImmutable() },
+ additionalProperties.toMutableMap(),
+ )
+ }
+
+ private var validated: Boolean = false
+
+ fun validate(): Filter = apply {
+ if (validated) {
+ return@apply
+ }
+
+ field().validate()
+ operator().validate()
+ values()
+ validated = true
+ }
+
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: OrbInvalidDataException) {
+ false
+ }
+
+ /**
+ * Returns a score indicating how many valid values are contained in this object
+ * recursively.
+ *
+ * Used for best match union deserialization.
+ */
+ @JvmSynthetic
+ internal fun validity(): Int =
+ (field.asKnown().getOrNull()?.validity() ?: 0) +
+ (operator.asKnown().getOrNull()?.validity() ?: 0) +
+ (values.asKnown().getOrNull()?.size ?: 0)
+
+ /** The property of the price to filter on. */
+ class Field @JsonCreator private constructor(private val value: JsonField) : Enum {
+
+ /**
+ * Returns this class instance's raw value.
+ *
+ * This is usually only useful if this instance was deserialized from data that doesn't
+ * match any known member, and you want to know that value. For example, if the SDK is
+ * on an older version than the API, then the API may respond with new members that the
+ * SDK is unaware of.
+ */
+ @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value
+
+ companion object {
+
+ @JvmField val PRICE_ID = of("price_id")
+
+ @JvmField val ITEM_ID = of("item_id")
+
+ @JvmField val PRICE_TYPE = of("price_type")
+
+ @JvmField val CURRENCY = of("currency")
+
+ @JvmField val PRICING_UNIT_ID = of("pricing_unit_id")
+
+ @JvmStatic fun of(value: String) = Field(JsonField.of(value))
+ }
+
+ /** An enum containing [Field]'s known values. */
+ enum class Known {
+ PRICE_ID,
+ ITEM_ID,
+ PRICE_TYPE,
+ CURRENCY,
+ PRICING_UNIT_ID,
+ }
+
+ /**
+ * An enum containing [Field]'s known values, as well as an [_UNKNOWN] member.
+ *
+ * An instance of [Field] can contain an unknown value in a couple of cases:
+ * - It was deserialized from data that doesn't match any known member. For example, if
+ * the SDK is on an older version than the API, then the API may respond with new
+ * members that the SDK is unaware of.
+ * - It was constructed with an arbitrary value using the [of] method.
+ */
+ enum class Value {
+ PRICE_ID,
+ ITEM_ID,
+ PRICE_TYPE,
+ CURRENCY,
+ PRICING_UNIT_ID,
+ /**
+ * An enum member indicating that [Field] was instantiated with an unknown value.
+ */
+ _UNKNOWN,
+ }
+
+ /**
+ * Returns an enum member corresponding to this class instance's value, or
+ * [Value._UNKNOWN] if the class was instantiated with an unknown value.
+ *
+ * Use the [known] method instead if you're certain the value is always known or if you
+ * want to throw for the unknown case.
+ */
+ fun value(): Value =
+ when (this) {
+ PRICE_ID -> Value.PRICE_ID
+ ITEM_ID -> Value.ITEM_ID
+ PRICE_TYPE -> Value.PRICE_TYPE
+ CURRENCY -> Value.CURRENCY
+ PRICING_UNIT_ID -> Value.PRICING_UNIT_ID
+ else -> Value._UNKNOWN
+ }
+
+ /**
+ * Returns an enum member corresponding to this class instance's value.
+ *
+ * Use the [value] method instead if you're uncertain the value is always known and
+ * don't want to throw for the unknown case.
+ *
+ * @throws OrbInvalidDataException if this class instance's value is a not a known
+ * member.
+ */
+ fun known(): Known =
+ when (this) {
+ PRICE_ID -> Known.PRICE_ID
+ ITEM_ID -> Known.ITEM_ID
+ PRICE_TYPE -> Known.PRICE_TYPE
+ CURRENCY -> Known.CURRENCY
+ PRICING_UNIT_ID -> Known.PRICING_UNIT_ID
+ else -> throw OrbInvalidDataException("Unknown Field: $value")
+ }
+
+ /**
+ * Returns this class instance's primitive wire representation.
+ *
+ * This differs from the [toString] method because that method is primarily for
+ * debugging and generally doesn't throw.
+ *
+ * @throws OrbInvalidDataException if this class instance's value does not have the
+ * expected primitive type.
+ */
+ fun asString(): String =
+ _value().asString().orElseThrow { OrbInvalidDataException("Value is not a String") }
+
+ private var validated: Boolean = false
+
+ fun validate(): Field = apply {
+ if (validated) {
+ return@apply
+ }
+
+ known()
+ validated = true
+ }
+
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: OrbInvalidDataException) {
+ false
+ }
+
+ /**
+ * Returns a score indicating how many valid values are contained in this object
+ * recursively.
+ *
+ * Used for best match union deserialization.
+ */
+ @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is Field && value == other.value
+ }
+
+ override fun hashCode() = value.hashCode()
+
+ override fun toString() = value.toString()
+ }
+
+ /** Should prices that match the filter be included or excluded. */
+ class Operator @JsonCreator private constructor(private val value: JsonField) :
+ Enum {
+
+ /**
+ * Returns this class instance's raw value.
+ *
+ * This is usually only useful if this instance was deserialized from data that doesn't
+ * match any known member, and you want to know that value. For example, if the SDK is
+ * on an older version than the API, then the API may respond with new members that the
+ * SDK is unaware of.
+ */
+ @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value
+
+ companion object {
+
+ @JvmField val INCLUDES = of("includes")
+
+ @JvmField val EXCLUDES = of("excludes")
+
+ @JvmStatic fun of(value: String) = Operator(JsonField.of(value))
+ }
+
+ /** An enum containing [Operator]'s known values. */
+ enum class Known {
+ INCLUDES,
+ EXCLUDES,
+ }
+
+ /**
+ * An enum containing [Operator]'s known values, as well as an [_UNKNOWN] member.
+ *
+ * An instance of [Operator] can contain an unknown value in a couple of cases:
+ * - It was deserialized from data that doesn't match any known member. For example, if
+ * the SDK is on an older version than the API, then the API may respond with new
+ * members that the SDK is unaware of.
+ * - It was constructed with an arbitrary value using the [of] method.
+ */
+ enum class Value {
+ INCLUDES,
+ EXCLUDES,
+ /**
+ * An enum member indicating that [Operator] was instantiated with an unknown value.
+ */
+ _UNKNOWN,
+ }
+
+ /**
+ * Returns an enum member corresponding to this class instance's value, or
+ * [Value._UNKNOWN] if the class was instantiated with an unknown value.
+ *
+ * Use the [known] method instead if you're certain the value is always known or if you
+ * want to throw for the unknown case.
+ */
+ fun value(): Value =
+ when (this) {
+ INCLUDES -> Value.INCLUDES
+ EXCLUDES -> Value.EXCLUDES
+ else -> Value._UNKNOWN
+ }
+
+ /**
+ * Returns an enum member corresponding to this class instance's value.
+ *
+ * Use the [value] method instead if you're uncertain the value is always known and
+ * don't want to throw for the unknown case.
+ *
+ * @throws OrbInvalidDataException if this class instance's value is a not a known
+ * member.
+ */
+ fun known(): Known =
+ when (this) {
+ INCLUDES -> Known.INCLUDES
+ EXCLUDES -> Known.EXCLUDES
+ else -> throw OrbInvalidDataException("Unknown Operator: $value")
+ }
+
+ /**
+ * Returns this class instance's primitive wire representation.
+ *
+ * This differs from the [toString] method because that method is primarily for
+ * debugging and generally doesn't throw.
+ *
+ * @throws OrbInvalidDataException if this class instance's value does not have the
+ * expected primitive type.
+ */
+ fun asString(): String =
+ _value().asString().orElseThrow { OrbInvalidDataException("Value is not a String") }
+
+ private var validated: Boolean = false
+
+ fun validate(): Operator = apply {
+ if (validated) {
+ return@apply
+ }
+
+ known()
+ validated = true
+ }
+
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: OrbInvalidDataException) {
+ false
+ }
+
+ /**
+ * Returns a score indicating how many valid values are contained in this object
+ * recursively.
+ *
+ * Used for best match union deserialization.
+ */
+ @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is Operator && value == other.value
+ }
+
+ override fun hashCode() = value.hashCode()
+
+ override fun toString() = value.toString()
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is Filter &&
+ field == other.field &&
+ operator == other.operator &&
+ values == other.values &&
+ additionalProperties == other.additionalProperties
+ }
+
+ private val hashCode: Int by lazy {
+ Objects.hash(field, operator, values, additionalProperties)
+ }
+
+ override fun hashCode(): Int = hashCode
+
+ override fun toString() =
+ "Filter{field=$field, operator=$operator, values=$values, additionalProperties=$additionalProperties}"
+ }
override fun equals(other: Any?): Boolean {
if (this === other) {
return true
}
- return /* spotless:off */ other is Allocation && allowsRollover == other.allowsRollover && currency == other.currency && customExpiration == other.customExpiration && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is Allocation &&
+ allowsRollover == other.allowsRollover &&
+ currency == other.currency &&
+ customExpiration == other.customExpiration &&
+ filters == other.filters &&
+ additionalProperties == other.additionalProperties
}
- /* spotless:off */
- private val hashCode: Int by lazy { Objects.hash(allowsRollover, currency, customExpiration, additionalProperties) }
- /* spotless:on */
+ private val hashCode: Int by lazy {
+ Objects.hash(allowsRollover, currency, customExpiration, filters, additionalProperties)
+ }
override fun hashCode(): Int = hashCode
override fun toString() =
- "Allocation{allowsRollover=$allowsRollover, currency=$currency, customExpiration=$customExpiration, additionalProperties=$additionalProperties}"
+ "Allocation{allowsRollover=$allowsRollover, currency=$currency, customExpiration=$customExpiration, filters=$filters, additionalProperties=$additionalProperties}"
}
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AmendmentLedgerEntry.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AmendmentLedgerEntry.kt
index 2c0f3e57d..9e161e9e2 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AmendmentLedgerEntry.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AmendmentLedgerEntry.kt
@@ -21,6 +21,7 @@ import java.util.Optional
import kotlin.jvm.optionals.getOrNull
class AmendmentLedgerEntry
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val id: JsonField,
private val amount: JsonField,
@@ -742,7 +743,7 @@ private constructor(
return true
}
- return /* spotless:off */ other is EntryStatus && value == other.value /* spotless:on */
+ return other is EntryStatus && value == other.value
}
override fun hashCode() = value.hashCode()
@@ -862,7 +863,7 @@ private constructor(
return true
}
- return /* spotless:off */ other is EntryType && value == other.value /* spotless:on */
+ return other is EntryType && value == other.value
}
override fun hashCode() = value.hashCode()
@@ -964,12 +965,10 @@ private constructor(
return true
}
- return /* spotless:off */ other is Metadata && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is Metadata && additionalProperties == other.additionalProperties
}
- /* spotless:off */
private val hashCode: Int by lazy { Objects.hash(additionalProperties) }
- /* spotless:on */
override fun hashCode(): Int = hashCode
@@ -981,12 +980,41 @@ private constructor(
return true
}
- return /* spotless:off */ other is AmendmentLedgerEntry && id == other.id && amount == other.amount && createdAt == other.createdAt && creditBlock == other.creditBlock && currency == other.currency && customer == other.customer && description == other.description && endingBalance == other.endingBalance && entryStatus == other.entryStatus && entryType == other.entryType && ledgerSequenceNumber == other.ledgerSequenceNumber && metadata == other.metadata && startingBalance == other.startingBalance && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is AmendmentLedgerEntry &&
+ id == other.id &&
+ amount == other.amount &&
+ createdAt == other.createdAt &&
+ creditBlock == other.creditBlock &&
+ currency == other.currency &&
+ customer == other.customer &&
+ description == other.description &&
+ endingBalance == other.endingBalance &&
+ entryStatus == other.entryStatus &&
+ entryType == other.entryType &&
+ ledgerSequenceNumber == other.ledgerSequenceNumber &&
+ metadata == other.metadata &&
+ startingBalance == other.startingBalance &&
+ additionalProperties == other.additionalProperties
}
- /* spotless:off */
- private val hashCode: Int by lazy { Objects.hash(id, amount, createdAt, creditBlock, currency, customer, description, endingBalance, entryStatus, entryType, ledgerSequenceNumber, metadata, startingBalance, additionalProperties) }
- /* spotless:on */
+ private val hashCode: Int by lazy {
+ Objects.hash(
+ id,
+ amount,
+ createdAt,
+ creditBlock,
+ currency,
+ customer,
+ description,
+ endingBalance,
+ entryStatus,
+ entryType,
+ ledgerSequenceNumber,
+ metadata,
+ startingBalance,
+ additionalProperties,
+ )
+ }
override fun hashCode(): Int = hashCode
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AmountDiscount.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AmountDiscount.kt
index b88a2c7f5..9a03097b9 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AmountDiscount.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AmountDiscount.kt
@@ -21,11 +21,12 @@ import java.util.Optional
import kotlin.jvm.optionals.getOrNull
class AmountDiscount
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val amountDiscount: JsonField,
private val discountType: JsonField,
private val appliesToPriceIds: JsonField>,
- private val filters: JsonField>,
+ private val filters: JsonField>,
private val reason: JsonField,
private val additionalProperties: MutableMap,
) {
@@ -43,7 +44,7 @@ private constructor(
appliesToPriceIds: JsonField> = JsonMissing.of(),
@JsonProperty("filters")
@ExcludeMissing
- filters: JsonField> = JsonMissing.of(),
+ filters: JsonField> = JsonMissing.of(),
@JsonProperty("reason") @ExcludeMissing reason: JsonField = JsonMissing.of(),
) : this(amountDiscount, discountType, appliesToPriceIds, filters, reason, mutableMapOf())
@@ -77,7 +78,7 @@ private constructor(
* @throws OrbInvalidDataException if the JSON field has an unexpected type (e.g. if the server
* responded with an unexpected value).
*/
- fun filters(): Optional> = filters.getOptional("filters")
+ fun filters(): Optional> = filters.getOptional("filters")
/**
* @throws OrbInvalidDataException if the JSON field has an unexpected type (e.g. if the server
@@ -118,9 +119,7 @@ private constructor(
*
* Unlike [filters], this method doesn't throw if the JSON field has an unexpected type.
*/
- @JsonProperty("filters")
- @ExcludeMissing
- fun _filters(): JsonField> = filters
+ @JsonProperty("filters") @ExcludeMissing fun _filters(): JsonField> = filters
/**
* Returns the raw JSON value of [reason].
@@ -161,7 +160,7 @@ private constructor(
private var amountDiscount: JsonField? = null
private var discountType: JsonField? = null
private var appliesToPriceIds: JsonField>? = null
- private var filters: JsonField>? = null
+ private var filters: JsonField>? = null
private var reason: JsonField = JsonMissing.of()
private var additionalProperties: MutableMap = mutableMapOf()
@@ -237,28 +236,28 @@ private constructor(
}
/** The filters that determine which prices to apply this discount to. */
- fun filters(filters: List?) = filters(JsonField.ofNullable(filters))
+ fun filters(filters: List?) = filters(JsonField.ofNullable(filters))
/** Alias for calling [Builder.filters] with `filters.orElse(null)`. */
- fun filters(filters: Optional>) = filters(filters.getOrNull())
+ fun filters(filters: Optional>) = filters(filters.getOrNull())
/**
* Sets [Builder.filters] to an arbitrary JSON value.
*
- * You should usually call [Builder.filters] with a well-typed `List`
- * value instead. This method is primarily for setting the field to an undocumented or not
- * yet supported value.
+ * You should usually call [Builder.filters] with a well-typed `List` value instead.
+ * This method is primarily for setting the field to an undocumented or not yet supported
+ * value.
*/
- fun filters(filters: JsonField>) = apply {
+ fun filters(filters: JsonField>) = apply {
this.filters = filters.map { it.toMutableList() }
}
/**
- * Adds a single [TransformPriceFilter] to [filters].
+ * Adds a single [Filter] to [filters].
*
* @throws IllegalStateException if the field was previously set to a non-list.
*/
- fun addFilter(filter: TransformPriceFilter) = apply {
+ fun addFilter(filter: Filter) = apply {
filters =
(filters ?: JsonField.of(mutableListOf())).also {
checkKnown("filters", it).add(filter)
@@ -470,7 +469,7 @@ private constructor(
return true
}
- return /* spotless:off */ other is DiscountType && value == other.value /* spotless:on */
+ return other is DiscountType && value == other.value
}
override fun hashCode() = value.hashCode()
@@ -478,17 +477,560 @@ private constructor(
override fun toString() = value.toString()
}
+ class Filter
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
+ private constructor(
+ private val field: JsonField,
+ private val operator: JsonField,
+ private val values: JsonField>,
+ private val additionalProperties: MutableMap,
+ ) {
+
+ @JsonCreator
+ private constructor(
+ @JsonProperty("field") @ExcludeMissing field: JsonField = JsonMissing.of(),
+ @JsonProperty("operator")
+ @ExcludeMissing
+ operator: JsonField = JsonMissing.of(),
+ @JsonProperty("values")
+ @ExcludeMissing
+ values: JsonField> = JsonMissing.of(),
+ ) : this(field, operator, values, mutableMapOf())
+
+ /**
+ * The property of the price to filter on.
+ *
+ * @throws OrbInvalidDataException if the JSON field has an unexpected type or is
+ * unexpectedly missing or null (e.g. if the server responded with an unexpected value).
+ */
+ fun field(): Field = field.getRequired("field")
+
+ /**
+ * Should prices that match the filter be included or excluded.
+ *
+ * @throws OrbInvalidDataException if the JSON field has an unexpected type or is
+ * unexpectedly missing or null (e.g. if the server responded with an unexpected value).
+ */
+ fun operator(): Operator = operator.getRequired("operator")
+
+ /**
+ * The IDs or values that match this filter.
+ *
+ * @throws OrbInvalidDataException if the JSON field has an unexpected type or is
+ * unexpectedly missing or null (e.g. if the server responded with an unexpected value).
+ */
+ fun values(): List = values.getRequired("values")
+
+ /**
+ * Returns the raw JSON value of [field].
+ *
+ * Unlike [field], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("field") @ExcludeMissing fun _field(): JsonField = field
+
+ /**
+ * Returns the raw JSON value of [operator].
+ *
+ * Unlike [operator], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("operator") @ExcludeMissing fun _operator(): JsonField = operator
+
+ /**
+ * Returns the raw JSON value of [values].
+ *
+ * Unlike [values], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("values") @ExcludeMissing fun _values(): JsonField> = values
+
+ @JsonAnySetter
+ private fun putAdditionalProperty(key: String, value: JsonValue) {
+ additionalProperties.put(key, value)
+ }
+
+ @JsonAnyGetter
+ @ExcludeMissing
+ fun _additionalProperties(): Map =
+ Collections.unmodifiableMap(additionalProperties)
+
+ fun toBuilder() = Builder().from(this)
+
+ companion object {
+
+ /**
+ * Returns a mutable builder for constructing an instance of [Filter].
+ *
+ * The following fields are required:
+ * ```java
+ * .field()
+ * .operator()
+ * .values()
+ * ```
+ */
+ @JvmStatic fun builder() = Builder()
+ }
+
+ /** A builder for [Filter]. */
+ class Builder internal constructor() {
+
+ private var field: JsonField? = null
+ private var operator: JsonField? = null
+ private var values: JsonField>? = null
+ private var additionalProperties: MutableMap = mutableMapOf()
+
+ @JvmSynthetic
+ internal fun from(filter: Filter) = apply {
+ field = filter.field
+ operator = filter.operator
+ values = filter.values.map { it.toMutableList() }
+ additionalProperties = filter.additionalProperties.toMutableMap()
+ }
+
+ /** The property of the price to filter on. */
+ fun field(field: Field) = field(JsonField.of(field))
+
+ /**
+ * Sets [Builder.field] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.field] with a well-typed [Field] value instead. This
+ * method is primarily for setting the field to an undocumented or not yet supported
+ * value.
+ */
+ fun field(field: JsonField) = apply { this.field = field }
+
+ /** Should prices that match the filter be included or excluded. */
+ fun operator(operator: Operator) = operator(JsonField.of(operator))
+
+ /**
+ * Sets [Builder.operator] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.operator] with a well-typed [Operator] value
+ * instead. This method is primarily for setting the field to an undocumented or not yet
+ * supported value.
+ */
+ fun operator(operator: JsonField) = apply { this.operator = operator }
+
+ /** The IDs or values that match this filter. */
+ fun values(values: List) = values(JsonField.of(values))
+
+ /**
+ * Sets [Builder.values] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.values] with a well-typed `List` value
+ * instead. This method is primarily for setting the field to an undocumented or not yet
+ * supported value.
+ */
+ fun values(values: JsonField>) = apply {
+ this.values = values.map { it.toMutableList() }
+ }
+
+ /**
+ * Adds a single [String] to [values].
+ *
+ * @throws IllegalStateException if the field was previously set to a non-list.
+ */
+ fun addValue(value: String) = apply {
+ values =
+ (values ?: JsonField.of(mutableListOf())).also {
+ checkKnown("values", it).add(value)
+ }
+ }
+
+ fun additionalProperties(additionalProperties: Map) = apply {
+ this.additionalProperties.clear()
+ putAllAdditionalProperties(additionalProperties)
+ }
+
+ fun putAdditionalProperty(key: String, value: JsonValue) = apply {
+ additionalProperties.put(key, value)
+ }
+
+ fun putAllAdditionalProperties(additionalProperties: Map) = apply {
+ this.additionalProperties.putAll(additionalProperties)
+ }
+
+ fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) }
+
+ fun removeAllAdditionalProperties(keys: Set) = apply {
+ keys.forEach(::removeAdditionalProperty)
+ }
+
+ /**
+ * Returns an immutable instance of [Filter].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ *
+ * The following fields are required:
+ * ```java
+ * .field()
+ * .operator()
+ * .values()
+ * ```
+ *
+ * @throws IllegalStateException if any required field is unset.
+ */
+ fun build(): Filter =
+ Filter(
+ checkRequired("field", field),
+ checkRequired("operator", operator),
+ checkRequired("values", values).map { it.toImmutable() },
+ additionalProperties.toMutableMap(),
+ )
+ }
+
+ private var validated: Boolean = false
+
+ fun validate(): Filter = apply {
+ if (validated) {
+ return@apply
+ }
+
+ field().validate()
+ operator().validate()
+ values()
+ validated = true
+ }
+
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: OrbInvalidDataException) {
+ false
+ }
+
+ /**
+ * Returns a score indicating how many valid values are contained in this object
+ * recursively.
+ *
+ * Used for best match union deserialization.
+ */
+ @JvmSynthetic
+ internal fun validity(): Int =
+ (field.asKnown().getOrNull()?.validity() ?: 0) +
+ (operator.asKnown().getOrNull()?.validity() ?: 0) +
+ (values.asKnown().getOrNull()?.size ?: 0)
+
+ /** The property of the price to filter on. */
+ class Field @JsonCreator private constructor(private val value: JsonField) : Enum {
+
+ /**
+ * Returns this class instance's raw value.
+ *
+ * This is usually only useful if this instance was deserialized from data that doesn't
+ * match any known member, and you want to know that value. For example, if the SDK is
+ * on an older version than the API, then the API may respond with new members that the
+ * SDK is unaware of.
+ */
+ @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value
+
+ companion object {
+
+ @JvmField val PRICE_ID = of("price_id")
+
+ @JvmField val ITEM_ID = of("item_id")
+
+ @JvmField val PRICE_TYPE = of("price_type")
+
+ @JvmField val CURRENCY = of("currency")
+
+ @JvmField val PRICING_UNIT_ID = of("pricing_unit_id")
+
+ @JvmStatic fun of(value: String) = Field(JsonField.of(value))
+ }
+
+ /** An enum containing [Field]'s known values. */
+ enum class Known {
+ PRICE_ID,
+ ITEM_ID,
+ PRICE_TYPE,
+ CURRENCY,
+ PRICING_UNIT_ID,
+ }
+
+ /**
+ * An enum containing [Field]'s known values, as well as an [_UNKNOWN] member.
+ *
+ * An instance of [Field] can contain an unknown value in a couple of cases:
+ * - It was deserialized from data that doesn't match any known member. For example, if
+ * the SDK is on an older version than the API, then the API may respond with new
+ * members that the SDK is unaware of.
+ * - It was constructed with an arbitrary value using the [of] method.
+ */
+ enum class Value {
+ PRICE_ID,
+ ITEM_ID,
+ PRICE_TYPE,
+ CURRENCY,
+ PRICING_UNIT_ID,
+ /**
+ * An enum member indicating that [Field] was instantiated with an unknown value.
+ */
+ _UNKNOWN,
+ }
+
+ /**
+ * Returns an enum member corresponding to this class instance's value, or
+ * [Value._UNKNOWN] if the class was instantiated with an unknown value.
+ *
+ * Use the [known] method instead if you're certain the value is always known or if you
+ * want to throw for the unknown case.
+ */
+ fun value(): Value =
+ when (this) {
+ PRICE_ID -> Value.PRICE_ID
+ ITEM_ID -> Value.ITEM_ID
+ PRICE_TYPE -> Value.PRICE_TYPE
+ CURRENCY -> Value.CURRENCY
+ PRICING_UNIT_ID -> Value.PRICING_UNIT_ID
+ else -> Value._UNKNOWN
+ }
+
+ /**
+ * Returns an enum member corresponding to this class instance's value.
+ *
+ * Use the [value] method instead if you're uncertain the value is always known and
+ * don't want to throw for the unknown case.
+ *
+ * @throws OrbInvalidDataException if this class instance's value is a not a known
+ * member.
+ */
+ fun known(): Known =
+ when (this) {
+ PRICE_ID -> Known.PRICE_ID
+ ITEM_ID -> Known.ITEM_ID
+ PRICE_TYPE -> Known.PRICE_TYPE
+ CURRENCY -> Known.CURRENCY
+ PRICING_UNIT_ID -> Known.PRICING_UNIT_ID
+ else -> throw OrbInvalidDataException("Unknown Field: $value")
+ }
+
+ /**
+ * Returns this class instance's primitive wire representation.
+ *
+ * This differs from the [toString] method because that method is primarily for
+ * debugging and generally doesn't throw.
+ *
+ * @throws OrbInvalidDataException if this class instance's value does not have the
+ * expected primitive type.
+ */
+ fun asString(): String =
+ _value().asString().orElseThrow { OrbInvalidDataException("Value is not a String") }
+
+ private var validated: Boolean = false
+
+ fun validate(): Field = apply {
+ if (validated) {
+ return@apply
+ }
+
+ known()
+ validated = true
+ }
+
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: OrbInvalidDataException) {
+ false
+ }
+
+ /**
+ * Returns a score indicating how many valid values are contained in this object
+ * recursively.
+ *
+ * Used for best match union deserialization.
+ */
+ @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is Field && value == other.value
+ }
+
+ override fun hashCode() = value.hashCode()
+
+ override fun toString() = value.toString()
+ }
+
+ /** Should prices that match the filter be included or excluded. */
+ class Operator @JsonCreator private constructor(private val value: JsonField) :
+ Enum {
+
+ /**
+ * Returns this class instance's raw value.
+ *
+ * This is usually only useful if this instance was deserialized from data that doesn't
+ * match any known member, and you want to know that value. For example, if the SDK is
+ * on an older version than the API, then the API may respond with new members that the
+ * SDK is unaware of.
+ */
+ @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value
+
+ companion object {
+
+ @JvmField val INCLUDES = of("includes")
+
+ @JvmField val EXCLUDES = of("excludes")
+
+ @JvmStatic fun of(value: String) = Operator(JsonField.of(value))
+ }
+
+ /** An enum containing [Operator]'s known values. */
+ enum class Known {
+ INCLUDES,
+ EXCLUDES,
+ }
+
+ /**
+ * An enum containing [Operator]'s known values, as well as an [_UNKNOWN] member.
+ *
+ * An instance of [Operator] can contain an unknown value in a couple of cases:
+ * - It was deserialized from data that doesn't match any known member. For example, if
+ * the SDK is on an older version than the API, then the API may respond with new
+ * members that the SDK is unaware of.
+ * - It was constructed with an arbitrary value using the [of] method.
+ */
+ enum class Value {
+ INCLUDES,
+ EXCLUDES,
+ /**
+ * An enum member indicating that [Operator] was instantiated with an unknown value.
+ */
+ _UNKNOWN,
+ }
+
+ /**
+ * Returns an enum member corresponding to this class instance's value, or
+ * [Value._UNKNOWN] if the class was instantiated with an unknown value.
+ *
+ * Use the [known] method instead if you're certain the value is always known or if you
+ * want to throw for the unknown case.
+ */
+ fun value(): Value =
+ when (this) {
+ INCLUDES -> Value.INCLUDES
+ EXCLUDES -> Value.EXCLUDES
+ else -> Value._UNKNOWN
+ }
+
+ /**
+ * Returns an enum member corresponding to this class instance's value.
+ *
+ * Use the [value] method instead if you're uncertain the value is always known and
+ * don't want to throw for the unknown case.
+ *
+ * @throws OrbInvalidDataException if this class instance's value is a not a known
+ * member.
+ */
+ fun known(): Known =
+ when (this) {
+ INCLUDES -> Known.INCLUDES
+ EXCLUDES -> Known.EXCLUDES
+ else -> throw OrbInvalidDataException("Unknown Operator: $value")
+ }
+
+ /**
+ * Returns this class instance's primitive wire representation.
+ *
+ * This differs from the [toString] method because that method is primarily for
+ * debugging and generally doesn't throw.
+ *
+ * @throws OrbInvalidDataException if this class instance's value does not have the
+ * expected primitive type.
+ */
+ fun asString(): String =
+ _value().asString().orElseThrow { OrbInvalidDataException("Value is not a String") }
+
+ private var validated: Boolean = false
+
+ fun validate(): Operator = apply {
+ if (validated) {
+ return@apply
+ }
+
+ known()
+ validated = true
+ }
+
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: OrbInvalidDataException) {
+ false
+ }
+
+ /**
+ * Returns a score indicating how many valid values are contained in this object
+ * recursively.
+ *
+ * Used for best match union deserialization.
+ */
+ @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is Operator && value == other.value
+ }
+
+ override fun hashCode() = value.hashCode()
+
+ override fun toString() = value.toString()
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is Filter &&
+ field == other.field &&
+ operator == other.operator &&
+ values == other.values &&
+ additionalProperties == other.additionalProperties
+ }
+
+ private val hashCode: Int by lazy {
+ Objects.hash(field, operator, values, additionalProperties)
+ }
+
+ override fun hashCode(): Int = hashCode
+
+ override fun toString() =
+ "Filter{field=$field, operator=$operator, values=$values, additionalProperties=$additionalProperties}"
+ }
+
override fun equals(other: Any?): Boolean {
if (this === other) {
return true
}
- return /* spotless:off */ other is AmountDiscount && amountDiscount == other.amountDiscount && discountType == other.discountType && appliesToPriceIds == other.appliesToPriceIds && filters == other.filters && reason == other.reason && additionalProperties == other.additionalProperties /* spotless:on */
+ return other is AmountDiscount &&
+ amountDiscount == other.amountDiscount &&
+ discountType == other.discountType &&
+ appliesToPriceIds == other.appliesToPriceIds &&
+ filters == other.filters &&
+ reason == other.reason &&
+ additionalProperties == other.additionalProperties
}
- /* spotless:off */
- private val hashCode: Int by lazy { Objects.hash(amountDiscount, discountType, appliesToPriceIds, filters, reason, additionalProperties) }
- /* spotless:on */
+ private val hashCode: Int by lazy {
+ Objects.hash(
+ amountDiscount,
+ discountType,
+ appliesToPriceIds,
+ filters,
+ reason,
+ additionalProperties,
+ )
+ }
override fun hashCode(): Int = hashCode
diff --git a/orb-java-core/src/main/kotlin/com/withorb/api/models/AmountDiscountInterval.kt b/orb-java-core/src/main/kotlin/com/withorb/api/models/AmountDiscountInterval.kt
index 630e58485..affadf3b6 100644
--- a/orb-java-core/src/main/kotlin/com/withorb/api/models/AmountDiscountInterval.kt
+++ b/orb-java-core/src/main/kotlin/com/withorb/api/models/AmountDiscountInterval.kt
@@ -22,12 +22,13 @@ import java.util.Optional
import kotlin.jvm.optionals.getOrNull
class AmountDiscountInterval
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val amountDiscount: JsonField,
private val appliesToPriceIntervalIds: JsonField>,
private val discountType: JsonField,
private val endDate: JsonField,
- private val filters: JsonField>,
+ private val filters: JsonField>,
private val startDate: JsonField,
private val additionalProperties: MutableMap,
) {
@@ -48,7 +49,7 @@ private constructor(
endDate: JsonField = JsonMissing.of(),
@JsonProperty("filters")
@ExcludeMissing
- filters: JsonField> = JsonMissing.of(),
+ filters: JsonField> = JsonMissing.of(),
@JsonProperty("start_date")
@ExcludeMissing
startDate: JsonField = JsonMissing.of(),
@@ -99,7 +100,7 @@ private constructor(
* @throws OrbInvalidDataException if the JSON field has an unexpected type or is unexpectedly
* missing or null (e.g. if the server responded with an unexpected value).
*/
- fun filters(): List = filters.getRequired("filters")
+ fun filters(): List = filters.getRequired("filters")
/**
* The start date of the discount interval.
@@ -149,9 +150,7 @@ private constructor(
*
* Unlike [filters], this method doesn't throw if the JSON field has an unexpected type.
*/
- @JsonProperty("filters")
- @ExcludeMissing
- fun _filters(): JsonField> = filters
+ @JsonProperty("filters") @ExcludeMissing fun _filters(): JsonField> = filters
/**
* Returns the raw JSON value of [startDate].
@@ -199,7 +198,7 @@ private constructor(
private var appliesToPriceIntervalIds: JsonField>? = null
private var discountType: JsonField? = null
private var endDate: JsonField? = null
- private var filters: JsonField>? = null
+ private var filters: JsonField>? = null
private var startDate: JsonField? = null
private var additionalProperties: MutableMap = mutableMapOf()
@@ -285,25 +284,25 @@ private constructor(
fun endDate(endDate: JsonField) = apply { this.endDate = endDate }
/** The filters that determine which prices this discount interval applies to. */
- fun filters(filters: List) = filters(JsonField.of(filters))
+ fun filters(filters: List) = filters(JsonField.of(filters))
/**
* Sets [Builder.filters] to an arbitrary JSON value.
*
- * You should usually call [Builder.filters] with a well-typed `List`
- * value instead. This method is primarily for setting the field to an undocumented or not
- * yet supported value.
+ * You should usually call [Builder.filters] with a well-typed `List` value instead.
+ * This method is primarily for setting the field to an undocumented or not yet supported
+ * value.
*/
- fun filters(filters: JsonField>) = apply {
+ fun filters(filters: JsonField>) = apply {
this.filters = filters.map { it.toMutableList() }
}
/**
- * Adds a single [TransformPriceFilter] to [filters].
+ * Adds a single [Filter] to [filters].
*
* @throws IllegalStateException if the field was previously set to a non-list.
*/
- fun addFilter(filter: TransformPriceFilter) = apply {
+ fun addFilter(filter: Filter) = apply {
filters =
(filters ?: JsonField.of(mutableListOf())).also {
checkKnown("filters", it).add(filter)
@@ -523,7 +522,7 @@ private constructor(
return true
}
- return /* spotless:off */ other is DiscountType && value == other.value /* spotless:on */
+ return other is DiscountType && value == other.value
}
override fun hashCode() = value.hashCode()
@@ -531,17 +530,562 @@ private constructor(
override fun toString() = value.toString()
}
+ class Filter
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
+ private constructor(
+ private val field: JsonField,
+ private val operator: JsonField,
+ private val values: JsonField>,
+ private val additionalProperties: MutableMap,
+ ) {
+
+ @JsonCreator
+ private constructor(
+ @JsonProperty("field") @ExcludeMissing field: JsonField = JsonMissing.of(),
+ @JsonProperty("operator")
+ @ExcludeMissing
+ operator: JsonField