diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 2ed3b71..3d2ac0b 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.0.4"
+ ".": "0.1.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index 92721c7..48b33b3 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 5
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cas-parser%2Fcas-parser-b7fdba3d3f97c7debc22c7ca30b828bce81bcd64648df8c94029b27a3321ebb9.yml
-openapi_spec_hash: 03f1315f1d32ada42445ca920f047dff
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cas-parser%2Fcas-parser-38618cc5c938e87eeacf4893d6a6ba4e6ef7da390e6283dc7b50b484a7b97165.yml
+openapi_spec_hash: b9e439ecee904ded01aa34efdee88856
config_hash: cb5d75abef6264b5d86448caf7295afa
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f21b326..e027a9b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,27 @@
# Changelog
+## 0.1.0 (2026-01-01)
+
+Full Changelog: [v0.0.4...v0.1.0](https://github.com/CASParser/cas-parser-java/compare/v0.0.4...v0.1.0)
+
+### Features
+
+* **api:** api update ([91a54b7](https://github.com/CASParser/cas-parser-java/commit/91a54b7acbf164ad459293fe697a4b0c9a795758))
+* **api:** api update ([557721f](https://github.com/CASParser/cas-parser-java/commit/557721f0775228db057005e912d8f820f512fcca))
+* **client:** expose sleeper option ([482319f](https://github.com/CASParser/cas-parser-java/commit/482319f0e19023df4e3ba5414e38914f6ad037fa))
+
+
+### Bug Fixes
+
+* **client:** deserialization of empty objects ([ce29632](https://github.com/CASParser/cas-parser-java/commit/ce29632f7f03c172ad042bbaa68e431ab2fd7fa7))
+* **client:** ensure single timer is created per client ([482319f](https://github.com/CASParser/cas-parser-java/commit/482319f0e19023df4e3ba5414e38914f6ad037fa))
+* **client:** incorrect `getPackageVersion` impl ([6772c5e](https://github.com/CASParser/cas-parser-java/commit/6772c5eeb5557a1e494852713cc55ec722b75145))
+
+
+### Chores
+
+* improve formatter performance ([692db64](https://github.com/CASParser/cas-parser-java/commit/692db64a36ef927e9c0ea23bd57192af99aaaf02))
+
## 0.0.4 (2025-09-13)
Full Changelog: [v0.0.3...v0.0.4](https://github.com/CASParser/cas-parser-java/compare/v0.0.3...v0.0.4)
diff --git a/LICENSE b/LICENSE
index f1756ce..6bbb512 100644
--- a/LICENSE
+++ b/LICENSE
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright 2025 Cas Parser
+ Copyright 2026 Cas Parser
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/README.md b/README.md
index eb1c0bb..93ea651 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,8 @@
-[](https://central.sonatype.com/artifact/com.cas_parser.api/cas-parser-java/0.0.4)
-[](https://javadoc.io/doc/com.cas_parser.api/cas-parser-java/0.0.4)
+[](https://central.sonatype.com/artifact/com.cas_parser.api/cas-parser-java/0.1.0)
+[](https://javadoc.io/doc/com.cas_parser.api/cas-parser-java/0.1.0)
@@ -13,7 +13,7 @@ It is generated with [Stainless](https://www.stainless.com/).
-The REST API documentation can be found on [docs.casparser.in](https://docs.casparser.in/reference). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.cas_parser.api/cas-parser-java/0.0.4).
+The REST API documentation can be found on [docs.casparser.in](https://docs.casparser.in/reference). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.cas_parser.api/cas-parser-java/0.1.0).
@@ -24,7 +24,7 @@ The REST API documentation can be found on [docs.casparser.in](https://docs.casp
### Gradle
```kotlin
-implementation("com.cas_parser.api:cas-parser-java:0.0.4")
+implementation("com.cas_parser.api:cas-parser-java:0.1.0")
```
### Maven
@@ -33,7 +33,7 @@ implementation("com.cas_parser.api:cas-parser-java:0.0.4")
com.cas_parser.api
cas-parser-java
- 0.0.4
+ 0.1.0
```
@@ -248,13 +248,13 @@ The SDK uses the standard [OkHttp logging interceptor](https://github.com/square
Enable logging by setting the `CAS_PARSER_LOG` environment variable to `info`:
```sh
-$ export CAS_PARSER_LOG=info
+export CAS_PARSER_LOG=info
```
Or to `debug` for more verbose logging:
```sh
-$ export CAS_PARSER_LOG=debug
+export CAS_PARSER_LOG=debug
```
## ProGuard and R8
diff --git a/build.gradle.kts b/build.gradle.kts
index d58d78e..30b3cae 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -9,7 +9,7 @@ repositories {
allprojects {
group = "com.cas_parser.api"
- version = "0.0.4" // x-release-please-version
+ version = "0.1.0" // x-release-please-version
}
subprojects {
diff --git a/cas-parser-java-client-okhttp/build.gradle.kts b/cas-parser-java-client-okhttp/build.gradle.kts
index 115d28c..91df2a9 100644
--- a/cas-parser-java-client-okhttp/build.gradle.kts
+++ b/cas-parser-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/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/CasParserOkHttpClient.kt b/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/CasParserOkHttpClient.kt
index 687527a..f75536a 100644
--- a/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/CasParserOkHttpClient.kt
+++ b/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/CasParserOkHttpClient.kt
@@ -5,6 +5,7 @@ package com.cas_parser.api.client.okhttp
import com.cas_parser.api.client.CasParserClient
import com.cas_parser.api.client.CasParserClientImpl
import com.cas_parser.api.core.ClientOptions
+import com.cas_parser.api.core.Sleeper
import com.cas_parser.api.core.Timeout
import com.cas_parser.api.core.http.Headers
import com.cas_parser.api.core.http.HttpClient
@@ -120,6 +121,17 @@ class CasParserOkHttpClient private constructor() {
*/
fun jsonMapper(jsonMapper: JsonMapper) = apply { clientOptions.jsonMapper(jsonMapper) }
+ /**
+ * 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/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/CasParserOkHttpClientAsync.kt b/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/CasParserOkHttpClientAsync.kt
index 186bbe4..4142acc 100644
--- a/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/CasParserOkHttpClientAsync.kt
+++ b/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/CasParserOkHttpClientAsync.kt
@@ -5,6 +5,7 @@ package com.cas_parser.api.client.okhttp
import com.cas_parser.api.client.CasParserClientAsync
import com.cas_parser.api.client.CasParserClientAsyncImpl
import com.cas_parser.api.core.ClientOptions
+import com.cas_parser.api.core.Sleeper
import com.cas_parser.api.core.Timeout
import com.cas_parser.api.core.http.Headers
import com.cas_parser.api.core.http.HttpClient
@@ -120,6 +121,17 @@ class CasParserOkHttpClientAsync private constructor() {
*/
fun jsonMapper(jsonMapper: JsonMapper) = apply { clientOptions.jsonMapper(jsonMapper) }
+ /**
+ * 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/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/OkHttpClient.kt b/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/OkHttpClient.kt
index 281e1c4..eee1317 100644
--- a/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/OkHttpClient.kt
+++ b/cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/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(CasParserIoException("Request failed", e))
- }
+ override fun onFailure(call: Call, e: IOException) {
+ future.completeExceptionally(CasParserIoException("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/cas-parser-java-client-okhttp/src/test/kotlin/com/cas_parser/api/client/okhttp/OkHttpClientTest.kt b/cas-parser-java-client-okhttp/src/test/kotlin/com/cas_parser/api/client/okhttp/OkHttpClientTest.kt
new file mode 100644
index 0000000..457b40c
--- /dev/null
+++ b/cas-parser-java-client-okhttp/src/test/kotlin/com/cas_parser/api/client/okhttp/OkHttpClientTest.kt
@@ -0,0 +1,44 @@
+package com.cas_parser.api.client.okhttp
+
+import com.cas_parser.api.core.http.HttpMethod
+import com.cas_parser.api.core.http.HttpRequest
+import com.github.tomakehurst.wiremock.client.WireMock.*
+import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo
+import com.github.tomakehurst.wiremock.junit5.WireMockTest
+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/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/ClientOptions.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/ClientOptions.kt
index d330bc7..f5195cd 100644
--- a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/ClientOptions.kt
+++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/ClientOptions.kt
@@ -40,6 +40,16 @@ private constructor(
* rarely needs to be overridden.
*/
@get:JvmName("jsonMapper") val jsonMapper: JsonMapper,
+ /**
+ * 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.
*
@@ -131,6 +141,7 @@ private constructor(
private var httpClient: HttpClient? = null
private var checkJacksonVersionCompatibility: Boolean = true
private var jsonMapper: JsonMapper = jsonMapper()
+ private var sleeper: Sleeper? = null
private var clock: Clock = Clock.systemUTC()
private var baseUrl: String? = null
private var headers: Headers.Builder = Headers.builder()
@@ -145,6 +156,7 @@ private constructor(
httpClient = clientOptions.originalHttpClient
checkJacksonVersionCompatibility = clientOptions.checkJacksonVersionCompatibility
jsonMapper = clientOptions.jsonMapper
+ sleeper = clientOptions.sleeper
clock = clientOptions.clock
baseUrl = clientOptions.baseUrl
headers = clientOptions.headers.toBuilder()
@@ -185,6 +197,17 @@ private constructor(
*/
fun jsonMapper(jsonMapper: JsonMapper) = apply { this.jsonMapper = jsonMapper }
+ /**
+ * 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.
*
@@ -369,6 +392,7 @@ private constructor(
*/
fun build(): ClientOptions {
val httpClient = checkRequired("httpClient", httpClient)
+ val sleeper = sleeper ?: PhantomReachableSleeper(DefaultSleeper())
val apiKey = checkRequired("apiKey", apiKey)
val headers = Headers.builder()
@@ -392,11 +416,13 @@ private constructor(
httpClient,
RetryingHttpClient.builder()
.httpClient(httpClient)
+ .sleeper(sleeper)
.clock(clock)
.maxRetries(maxRetries)
.build(),
checkJacksonVersionCompatibility,
jsonMapper,
+ sleeper,
clock,
baseUrl,
headers.build(),
@@ -421,5 +447,6 @@ private constructor(
*/
fun close() {
httpClient.close()
+ sleeper.close()
}
}
diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/DefaultSleeper.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/DefaultSleeper.kt
new file mode 100644
index 0000000..5e092e2
--- /dev/null
+++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/DefaultSleeper.kt
@@ -0,0 +1,28 @@
+package com.cas_parser.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/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/PhantomReachableSleeper.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/PhantomReachableSleeper.kt
new file mode 100644
index 0000000..2b3afd5
--- /dev/null
+++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/PhantomReachableSleeper.kt
@@ -0,0 +1,23 @@
+package com.cas_parser.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/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/Properties.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/Properties.kt
index c715f1a..dc9a375 100644
--- a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/Properties.kt
+++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/Properties.kt
@@ -2,7 +2,7 @@
package com.cas_parser.api.core
-import java.util.Properties
+import com.cas_parser.api.client.CasParserClient
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,13 @@ 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"
+ CasParserClient::class.java.`package`.implementationVersion ?: "unknown"
fun getJavaVersion(): String = System.getProperty("java.version", "unknown")
diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/Sleeper.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/Sleeper.kt
new file mode 100644
index 0000000..5a93d9a
--- /dev/null
+++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/Sleeper.kt
@@ -0,0 +1,21 @@
+package com.cas_parser.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/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/http/RetryingHttpClient.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/http/RetryingHttpClient.kt
index 569b1aa..2bf9815 100644
--- a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/http/RetryingHttpClient.kt
+++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/core/http/RetryingHttpClient.kt
@@ -1,6 +1,8 @@
package com.cas_parser.api.core.http
+import com.cas_parser.api.core.DefaultSleeper
import com.cas_parser.api.core.RequestOptions
+import com.cas_parser.api.core.Sleeper
import com.cas_parser.api.core.checkRequired
import com.cas_parser.api.errors.CasParserIoException
import com.cas_parser.api.errors.CasParserRetryableException
@@ -11,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
@@ -130,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
@@ -235,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 }
@@ -272,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/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasParams.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasParams.kt
index eb7213c..598c6a2 100644
--- a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasParams.kt
+++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasParams.kt
@@ -394,6 +394,7 @@ private constructor(
override fun _queryParams(): QueryParams = additionalQueryParams
class Body
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val email: JsonField,
private val fromDate: JsonField,
diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasResponse.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasResponse.kt
index 09df4cd..ad4901d 100644
--- a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasResponse.kt
+++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casgenerator/CasGeneratorGenerateCasResponse.kt
@@ -16,6 +16,7 @@ import java.util.Objects
import java.util.Optional
class CasGeneratorGenerateCasResponse
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val msg: JsonField,
private val status: JsonField,
diff --git a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casparser/UnifiedResponse.kt b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casparser/UnifiedResponse.kt
index 2c18576..e64ebfb 100644
--- a/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casparser/UnifiedResponse.kt
+++ b/cas-parser-java-core/src/main/kotlin/com/cas_parser/api/models/casparser/UnifiedResponse.kt
@@ -22,12 +22,14 @@ import java.util.Optional
import kotlin.jvm.optionals.getOrNull
class UnifiedResponse
+@JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val dematAccounts: JsonField>,
private val insurance: JsonField,
private val investor: JsonField,
private val meta: JsonField,
private val mutualFunds: JsonField>,
+ private val nps: JsonField>,
private val summary: JsonField,
private val additionalProperties: MutableMap,
) {
@@ -45,8 +47,9 @@ private constructor(
@JsonProperty("mutual_funds")
@ExcludeMissing
mutualFunds: JsonField> = JsonMissing.of(),
+ @JsonProperty("nps") @ExcludeMissing nps: JsonField> = JsonMissing.of(),
@JsonProperty("summary") @ExcludeMissing summary: JsonField = JsonMissing.of(),
- ) : this(dematAccounts, insurance, investor, meta, mutualFunds, summary, mutableMapOf())
+ ) : this(dematAccounts, insurance, investor, meta, mutualFunds, nps, summary, mutableMapOf())
/**
* @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if the
@@ -78,6 +81,14 @@ private constructor(
*/
fun mutualFunds(): Optional> = mutualFunds.getOptional("mutual_funds")
+ /**
+ * List of NPS accounts
+ *
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if the
+ * server responded with an unexpected value).
+ */
+ fun nps(): Optional> = nps.getOptional("nps")
+
/**
* @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if the
* server responded with an unexpected value).
@@ -123,6 +134,13 @@ private constructor(
@ExcludeMissing
fun _mutualFunds(): JsonField> = mutualFunds
+ /**
+ * Returns the raw JSON value of [nps].
+ *
+ * Unlike [nps], this method doesn't throw if the JSON field has an unexpected type.
+ */
+ @JsonProperty("nps") @ExcludeMissing fun _nps(): JsonField> = nps
+
/**
* Returns the raw JSON value of [summary].
*
@@ -156,6 +174,7 @@ private constructor(
private var investor: JsonField = JsonMissing.of()
private var meta: JsonField = JsonMissing.of()
private var mutualFunds: JsonField>? = null
+ private var nps: JsonField>? = null
private var summary: JsonField = JsonMissing.of()
private var additionalProperties: MutableMap = mutableMapOf()
@@ -166,6 +185,7 @@ private constructor(
investor = unifiedResponse.investor
meta = unifiedResponse.meta
mutualFunds = unifiedResponse.mutualFunds.map { it.toMutableList() }
+ nps = unifiedResponse.nps.map { it.toMutableList() }
summary = unifiedResponse.summary
additionalProperties = unifiedResponse.additionalProperties.toMutableMap()
}
@@ -253,6 +273,26 @@ private constructor(
}
}
+ /** List of NPS accounts */
+ fun nps(nps: List) = nps(JsonField.of(nps))
+
+ /**
+ * Sets [Builder.nps] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.nps] with a well-typed `List` value instead. This
+ * method is primarily for setting the field to an undocumented or not yet supported value.
+ */
+ fun nps(nps: JsonField>) = apply { this.nps = nps.map { it.toMutableList() } }
+
+ /**
+ * Adds a single [Np] to [nps].
+ *
+ * @throws IllegalStateException if the field was previously set to a non-list.
+ */
+ fun addNp(np: Np) = apply {
+ nps = (nps ?: JsonField.of(mutableListOf())).also { checkKnown("nps", it).add(np) }
+ }
+
fun summary(summary: Summary) = summary(JsonField.of(summary))
/**
@@ -294,6 +334,7 @@ private constructor(
investor,
meta,
(mutualFunds ?: JsonMissing.of()).map { it.toImmutable() },
+ (nps ?: JsonMissing.of()).map { it.toImmutable() },
summary,
additionalProperties.toMutableMap(),
)
@@ -311,6 +352,7 @@ private constructor(
investor().ifPresent { it.validate() }
meta().ifPresent { it.validate() }
mutualFunds().ifPresent { it.forEach { it.validate() } }
+ nps().ifPresent { it.forEach { it.validate() } }
summary().ifPresent { it.validate() }
validated = true
}
@@ -335,9 +377,11 @@ private constructor(
(investor.asKnown().getOrNull()?.validity() ?: 0) +
(meta.asKnown().getOrNull()?.validity() ?: 0) +
(mutualFunds.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) +
+ (nps.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) +
(summary.asKnown().getOrNull()?.validity() ?: 0)
class DematAccount
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val additionalInfo: JsonField,
private val boId: JsonField,
@@ -346,6 +390,7 @@ private constructor(
private val dpId: JsonField,
private val dpName: JsonField,
private val holdings: JsonField,
+ private val linkedHolders: JsonField>,
private val value: JsonField,
private val additionalProperties: MutableMap,
) {
@@ -367,6 +412,9 @@ private constructor(
@JsonProperty("holdings")
@ExcludeMissing
holdings: JsonField = JsonMissing.of(),
+ @JsonProperty("linked_holders")
+ @ExcludeMissing
+ linkedHolders: JsonField> = JsonMissing.of(),
@JsonProperty("value") @ExcludeMissing value: JsonField = JsonMissing.of(),
) : this(
additionalInfo,
@@ -376,6 +424,7 @@ private constructor(
dpId,
dpName,
holdings,
+ linkedHolders,
value,
mutableMapOf(),
)
@@ -435,6 +484,15 @@ private constructor(
*/
fun holdings(): Optional = holdings.getOptional("holdings")
+ /**
+ * List of account holders linked to this demat account
+ *
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected type (e.g. if
+ * the server responded with an unexpected value).
+ */
+ fun linkedHolders(): Optional> =
+ linkedHolders.getOptional("linked_holders")
+
/**
* Total value of the demat account
*
@@ -497,6 +555,16 @@ private constructor(
*/
@JsonProperty("holdings") @ExcludeMissing fun _holdings(): JsonField = holdings
+ /**
+ * Returns the raw JSON value of [linkedHolders].
+ *
+ * Unlike [linkedHolders], this method doesn't throw if the JSON field has an unexpected
+ * type.
+ */
+ @JsonProperty("linked_holders")
+ @ExcludeMissing
+ fun _linkedHolders(): JsonField> = linkedHolders
+
/**
* Returns the raw JSON value of [value].
*
@@ -532,6 +600,7 @@ private constructor(
private var dpId: JsonField = JsonMissing.of()
private var dpName: JsonField = JsonMissing.of()
private var holdings: JsonField = JsonMissing.of()
+ private var linkedHolders: JsonField>? = null
private var value: JsonField = JsonMissing.of()
private var additionalProperties: MutableMap = mutableMapOf()
@@ -544,6 +613,7 @@ private constructor(
dpId = dematAccount.dpId
dpName = dematAccount.dpName
holdings = dematAccount.holdings
+ linkedHolders = dematAccount.linkedHolders.map { it.toMutableList() }
value = dematAccount.value
additionalProperties = dematAccount.additionalProperties.toMutableMap()
}
@@ -634,6 +704,33 @@ private constructor(
*/
fun holdings(holdings: JsonField) = apply { this.holdings = holdings }
+ /** List of account holders linked to this demat account */
+ fun linkedHolders(linkedHolders: List) =
+ linkedHolders(JsonField.of(linkedHolders))
+
+ /**
+ * Sets [Builder.linkedHolders] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.linkedHolders] with a well-typed
+ * `List` value instead. This method is primarily for setting the field to
+ * an undocumented or not yet supported value.
+ */
+ fun linkedHolders(linkedHolders: JsonField>) = apply {
+ this.linkedHolders = linkedHolders.map { it.toMutableList() }
+ }
+
+ /**
+ * Adds a single [LinkedHolder] to [linkedHolders].
+ *
+ * @throws IllegalStateException if the field was previously set to a non-list.
+ */
+ fun addLinkedHolder(linkedHolder: LinkedHolder) = apply {
+ linkedHolders =
+ (linkedHolders ?: JsonField.of(mutableListOf())).also {
+ checkKnown("linkedHolders", it).add(linkedHolder)
+ }
+ }
+
/** Total value of the demat account */
fun value(value: Float) = value(JsonField.of(value))
@@ -679,6 +776,7 @@ private constructor(
dpId,
dpName,
holdings,
+ (linkedHolders ?: JsonMissing.of()).map { it.toImmutable() },
value,
additionalProperties.toMutableMap(),
)
@@ -698,6 +796,7 @@ private constructor(
dpId()
dpName()
holdings().ifPresent { it.validate() }
+ linkedHolders().ifPresent { it.forEach { it.validate() } }
value()
validated = true
}
@@ -725,10 +824,12 @@ private constructor(
(if (dpId.asKnown().isPresent) 1 else 0) +
(if (dpName.asKnown().isPresent) 1 else 0) +
(holdings.asKnown().getOrNull()?.validity() ?: 0) +
+ (linkedHolders.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) +
(if (value.asKnown().isPresent) 1 else 0)
/** Additional information specific to the demat account type */
class AdditionalInfo
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val boStatus: JsonField,
private val boSubStatus: JsonField,
@@ -1310,6 +1411,7 @@ private constructor(
}
class Holdings
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val aifs: JsonField>,
private val corporateBonds: JsonField>,
@@ -1668,10 +1770,12 @@ private constructor(
?: 0)
class Aif
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
- private val additionalInfo: JsonValue,
+ private val additionalInfo: JsonField,
private val isin: JsonField,
private val name: JsonField,
+ private val transactions: JsonField>,
private val units: JsonField,
private val value: JsonField,
private val additionalProperties: MutableMap,
@@ -1681,25 +1785,32 @@ private constructor(
private constructor(
@JsonProperty("additional_info")
@ExcludeMissing
- additionalInfo: JsonValue = JsonMissing.of(),
+ additionalInfo: JsonField = JsonMissing.of(),
@JsonProperty("isin")
@ExcludeMissing
isin: JsonField = JsonMissing.of(),
@JsonProperty("name")
@ExcludeMissing
name: JsonField = JsonMissing.of(),
+ @JsonProperty("transactions")
+ @ExcludeMissing
+ transactions: JsonField> = JsonMissing.of(),
@JsonProperty("units")
@ExcludeMissing
units: JsonField = JsonMissing.of(),
@JsonProperty("value")
@ExcludeMissing
value: JsonField = JsonMissing.of(),
- ) : this(additionalInfo, isin, name, units, value, mutableMapOf())
+ ) : this(additionalInfo, isin, name, transactions, units, value, mutableMapOf())
- /** Additional information specific to the AIF */
- @JsonProperty("additional_info")
- @ExcludeMissing
- fun _additionalInfo(): JsonValue = additionalInfo
+ /**
+ * Additional information specific to the AIF
+ *
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected type
+ * (e.g. if the server responded with an unexpected value).
+ */
+ fun additionalInfo(): Optional =
+ additionalInfo.getOptional("additional_info")
/**
* ISIN code of the AIF
@@ -1717,6 +1828,15 @@ private constructor(
*/
fun name(): Optional = name.getOptional("name")
+ /**
+ * List of transactions for this holding (beta)
+ *
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected type
+ * (e.g. if the server responded with an unexpected value).
+ */
+ fun transactions(): Optional> =
+ transactions.getOptional("transactions")
+
/**
* Number of units held
*
@@ -1733,6 +1853,16 @@ private constructor(
*/
fun value(): Optional = value.getOptional("value")
+ /**
+ * Returns the raw JSON value of [additionalInfo].
+ *
+ * Unlike [additionalInfo], this method doesn't throw if the JSON field has an
+ * unexpected type.
+ */
+ @JsonProperty("additional_info")
+ @ExcludeMissing
+ fun _additionalInfo(): JsonField = additionalInfo
+
/**
* Returns the raw JSON value of [isin].
*
@@ -1749,6 +1879,16 @@ private constructor(
*/
@JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name
+ /**
+ * Returns the raw JSON value of [transactions].
+ *
+ * Unlike [transactions], this method doesn't throw if the JSON field has an
+ * unexpected type.
+ */
+ @JsonProperty("transactions")
+ @ExcludeMissing
+ fun _transactions(): JsonField> = transactions
+
/**
* Returns the raw JSON value of [units].
*
@@ -1786,9 +1926,10 @@ private constructor(
/** A builder for [Aif]. */
class Builder internal constructor() {
- private var additionalInfo: JsonValue = JsonMissing.of()
+ private var additionalInfo: JsonField = JsonMissing.of()
private var isin: JsonField = JsonMissing.of()
private var name: JsonField = JsonMissing.of()
+ private var transactions: JsonField>? = null
private var units: JsonField = JsonMissing.of()
private var value: JsonField = JsonMissing.of()
private var additionalProperties: MutableMap = mutableMapOf()
@@ -1798,13 +1939,24 @@ private constructor(
additionalInfo = aif.additionalInfo
isin = aif.isin
name = aif.name
+ transactions = aif.transactions.map { it.toMutableList() }
units = aif.units
value = aif.value
additionalProperties = aif.additionalProperties.toMutableMap()
}
/** Additional information specific to the AIF */
- fun additionalInfo(additionalInfo: JsonValue) = apply {
+ fun additionalInfo(additionalInfo: AdditionalInfo) =
+ additionalInfo(JsonField.of(additionalInfo))
+
+ /**
+ * Sets [Builder.additionalInfo] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.additionalInfo] with a well-typed
+ * [AdditionalInfo] value instead. This method is primarily for setting the
+ * field to an undocumented or not yet supported value.
+ */
+ fun additionalInfo(additionalInfo: JsonField) = apply {
this.additionalInfo = additionalInfo
}
@@ -1832,6 +1984,33 @@ private constructor(
*/
fun name(name: JsonField) = apply { this.name = name }
+ /** List of transactions for this holding (beta) */
+ fun transactions(transactions: List) =
+ transactions(JsonField.of(transactions))
+
+ /**
+ * Sets [Builder.transactions] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.transactions] with a well-typed
+ * `List` value instead. This method is primarily for setting the
+ * field to an undocumented or not yet supported value.
+ */
+ fun transactions(transactions: JsonField>) = apply {
+ this.transactions = transactions.map { it.toMutableList() }
+ }
+
+ /**
+ * Adds a single [Transaction] to [transactions].
+ *
+ * @throws IllegalStateException if the field was previously set to a non-list.
+ */
+ fun addTransaction(transaction: Transaction) = apply {
+ transactions =
+ (transactions ?: JsonField.of(mutableListOf())).also {
+ checkKnown("transactions", it).add(transaction)
+ }
+ }
+
/** Number of units held */
fun units(units: Float) = units(JsonField.of(units))
@@ -1888,6 +2067,7 @@ private constructor(
additionalInfo,
isin,
name,
+ (transactions ?: JsonMissing.of()).map { it.toImmutable() },
units,
value,
additionalProperties.toMutableMap(),
@@ -1901,8 +2081,10 @@ private constructor(
return@apply
}
+ additionalInfo().ifPresent { it.validate() }
isin()
name()
+ transactions().ifPresent { it.forEach { it.validate() } }
units()
value()
validated = true
@@ -1924,373 +2106,1553 @@ private constructor(
*/
@JvmSynthetic
internal fun validity(): Int =
- (if (isin.asKnown().isPresent) 1 else 0) +
+ (additionalInfo.asKnown().getOrNull()?.validity() ?: 0) +
+ (if (isin.asKnown().isPresent) 1 else 0) +
(if (name.asKnown().isPresent) 1 else 0) +
+ (transactions.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) +
(if (units.asKnown().isPresent) 1 else 0) +
(if (value.asKnown().isPresent) 1 else 0)
- override fun equals(other: Any?): Boolean {
- if (this === other) {
- return true
- }
+ /** Additional information specific to the AIF */
+ class AdditionalInfo
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
+ private constructor(
+ private val closeUnits: JsonField,
+ private val openUnits: JsonField,
+ private val additionalProperties: MutableMap,
+ ) {
+
+ @JsonCreator
+ private constructor(
+ @JsonProperty("close_units")
+ @ExcludeMissing
+ closeUnits: JsonField = JsonMissing.of(),
+ @JsonProperty("open_units")
+ @ExcludeMissing
+ openUnits: JsonField = JsonMissing.of(),
+ ) : this(closeUnits, openUnits, mutableMapOf())
- return other is Aif &&
- additionalInfo == other.additionalInfo &&
- isin == other.isin &&
- name == other.name &&
- units == other.units &&
- value == other.value &&
- additionalProperties == other.additionalProperties
- }
+ /**
+ * Closing balance units for the statement period (beta)
+ *
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected
+ * type (e.g. if the server responded with an unexpected value).
+ */
+ fun closeUnits(): Optional = closeUnits.getOptional("close_units")
- private val hashCode: Int by lazy {
- Objects.hash(additionalInfo, isin, name, units, value, additionalProperties)
- }
+ /**
+ * Opening balance units for the statement period (beta)
+ *
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected
+ * type (e.g. if the server responded with an unexpected value).
+ */
+ fun openUnits(): Optional = openUnits.getOptional("open_units")
- override fun hashCode(): Int = hashCode
+ /**
+ * Returns the raw JSON value of [closeUnits].
+ *
+ * Unlike [closeUnits], this method doesn't throw if the JSON field has an
+ * unexpected type.
+ */
+ @JsonProperty("close_units")
+ @ExcludeMissing
+ fun _closeUnits(): JsonField = closeUnits
- override fun toString() =
- "Aif{additionalInfo=$additionalInfo, isin=$isin, name=$name, units=$units, value=$value, additionalProperties=$additionalProperties}"
- }
+ /**
+ * Returns the raw JSON value of [openUnits].
+ *
+ * Unlike [openUnits], this method doesn't throw if the JSON field has an
+ * unexpected type.
+ */
+ @JsonProperty("open_units")
+ @ExcludeMissing
+ fun _openUnits(): JsonField = openUnits
- class CorporateBond
- private constructor(
- private val additionalInfo: JsonValue,
- private val isin: JsonField,
- private val name: JsonField,
- private val units: JsonField,
- private val value: JsonField,
- private val additionalProperties: MutableMap,
- ) {
+ @JsonAnySetter
+ private fun putAdditionalProperty(key: String, value: JsonValue) {
+ additionalProperties.put(key, value)
+ }
- @JsonCreator
- private constructor(
- @JsonProperty("additional_info")
- @ExcludeMissing
- additionalInfo: JsonValue = JsonMissing.of(),
- @JsonProperty("isin")
- @ExcludeMissing
- isin: JsonField = JsonMissing.of(),
- @JsonProperty("name")
- @ExcludeMissing
- name: JsonField = JsonMissing.of(),
- @JsonProperty("units")
- @ExcludeMissing
- units: JsonField = JsonMissing.of(),
- @JsonProperty("value")
+ @JsonAnyGetter
@ExcludeMissing
- value: JsonField = JsonMissing.of(),
- ) : this(additionalInfo, isin, name, units, value, mutableMapOf())
+ fun _additionalProperties(): Map =
+ Collections.unmodifiableMap(additionalProperties)
- /** Additional information specific to the corporate bond */
- @JsonProperty("additional_info")
- @ExcludeMissing
- fun _additionalInfo(): JsonValue = additionalInfo
+ fun toBuilder() = Builder().from(this)
- /**
- * ISIN code of the corporate bond
- *
- * @throws CasParserInvalidDataException if the JSON field has an unexpected type
- * (e.g. if the server responded with an unexpected value).
- */
- fun isin(): Optional = isin.getOptional("isin")
+ companion object {
- /**
- * Name of the corporate bond
- *
- * @throws CasParserInvalidDataException if the JSON field has an unexpected type
- * (e.g. if the server responded with an unexpected value).
- */
- fun name(): Optional = name.getOptional("name")
+ /**
+ * Returns a mutable builder for constructing an instance of
+ * [AdditionalInfo].
+ */
+ @JvmStatic fun builder() = Builder()
+ }
- /**
- * Number of units held
- *
- * @throws CasParserInvalidDataException if the JSON field has an unexpected type
- * (e.g. if the server responded with an unexpected value).
- */
- fun units(): Optional = units.getOptional("units")
+ /** A builder for [AdditionalInfo]. */
+ class Builder internal constructor() {
- /**
- * Current market value of the holding
- *
- * @throws CasParserInvalidDataException if the JSON field has an unexpected type
- * (e.g. if the server responded with an unexpected value).
- */
- fun value(): Optional = value.getOptional("value")
+ private var closeUnits: JsonField = JsonMissing.of()
+ private var openUnits: JsonField = JsonMissing.of()
+ private var additionalProperties: MutableMap =
+ mutableMapOf()
- /**
- * Returns the raw JSON value of [isin].
- *
- * Unlike [isin], this method doesn't throw if the JSON field has an unexpected
- * type.
- */
- @JsonProperty("isin") @ExcludeMissing fun _isin(): JsonField = isin
+ @JvmSynthetic
+ internal fun from(additionalInfo: AdditionalInfo) = apply {
+ closeUnits = additionalInfo.closeUnits
+ openUnits = additionalInfo.openUnits
+ additionalProperties =
+ additionalInfo.additionalProperties.toMutableMap()
+ }
- /**
- * Returns the raw JSON value of [name].
- *
- * Unlike [name], this method doesn't throw if the JSON field has an unexpected
- * type.
- */
- @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name
+ /** Closing balance units for the statement period (beta) */
+ fun closeUnits(closeUnits: Float?) =
+ closeUnits(JsonField.ofNullable(closeUnits))
+
+ /**
+ * Alias for [Builder.closeUnits].
+ *
+ * This unboxed primitive overload exists for backwards compatibility.
+ */
+ fun closeUnits(closeUnits: Float) = closeUnits(closeUnits as Float?)
+
+ /**
+ * Alias for calling [Builder.closeUnits] with `closeUnits.orElse(null)`.
+ */
+ fun closeUnits(closeUnits: Optional) =
+ closeUnits(closeUnits.getOrNull())
+
+ /**
+ * Sets [Builder.closeUnits] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.closeUnits] with a well-typed [Float]
+ * value instead. This method is primarily for setting the field to an
+ * undocumented or not yet supported value.
+ */
+ fun closeUnits(closeUnits: JsonField) = apply {
+ this.closeUnits = closeUnits
+ }
- /**
- * Returns the raw JSON value of [units].
- *
- * Unlike [units], this method doesn't throw if the JSON field has an unexpected
- * type.
- */
- @JsonProperty("units") @ExcludeMissing fun _units(): JsonField = units
+ /** Opening balance units for the statement period (beta) */
+ fun openUnits(openUnits: Float?) =
+ openUnits(JsonField.ofNullable(openUnits))
+
+ /**
+ * Alias for [Builder.openUnits].
+ *
+ * This unboxed primitive overload exists for backwards compatibility.
+ */
+ fun openUnits(openUnits: Float) = openUnits(openUnits as Float?)
+
+ /** Alias for calling [Builder.openUnits] with `openUnits.orElse(null)`. */
+ fun openUnits(openUnits: Optional) = openUnits(openUnits.getOrNull())
+
+ /**
+ * Sets [Builder.openUnits] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.openUnits] with a well-typed [Float]
+ * value instead. This method is primarily for setting the field to an
+ * undocumented or not yet supported value.
+ */
+ fun openUnits(openUnits: JsonField) = apply {
+ this.openUnits = openUnits
+ }
- /**
- * Returns the raw JSON value of [value].
- *
- * Unlike [value], this method doesn't throw if the JSON field has an unexpected
- * type.
- */
- @JsonProperty("value") @ExcludeMissing fun _value(): JsonField = value
+ fun additionalProperties(additionalProperties: Map) =
+ apply {
+ this.additionalProperties.clear()
+ putAllAdditionalProperties(additionalProperties)
+ }
- @JsonAnySetter
- private fun putAdditionalProperty(key: String, value: JsonValue) {
- additionalProperties.put(key, value)
- }
+ fun putAdditionalProperty(key: String, value: JsonValue) = apply {
+ additionalProperties.put(key, value)
+ }
- @JsonAnyGetter
- @ExcludeMissing
- fun _additionalProperties(): Map =
- Collections.unmodifiableMap(additionalProperties)
+ fun putAllAdditionalProperties(
+ additionalProperties: Map
+ ) = apply { this.additionalProperties.putAll(additionalProperties) }
- fun toBuilder() = Builder().from(this)
+ fun removeAdditionalProperty(key: String) = apply {
+ additionalProperties.remove(key)
+ }
- companion object {
+ fun removeAllAdditionalProperties(keys: Set) = apply {
+ keys.forEach(::removeAdditionalProperty)
+ }
- /**
- * Returns a mutable builder for constructing an instance of [CorporateBond].
- */
- @JvmStatic fun builder() = Builder()
- }
+ /**
+ * Returns an immutable instance of [AdditionalInfo].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ */
+ fun build(): AdditionalInfo =
+ AdditionalInfo(
+ closeUnits,
+ openUnits,
+ additionalProperties.toMutableMap(),
+ )
+ }
- /** A builder for [CorporateBond]. */
- class Builder internal constructor() {
+ private var validated: Boolean = false
- private var additionalInfo: JsonValue = JsonMissing.of()
- private var isin: JsonField = JsonMissing.of()
- private var name: JsonField = JsonMissing.of()
- private var units: JsonField = JsonMissing.of()
- private var value: JsonField = JsonMissing.of()
- private var additionalProperties: MutableMap = mutableMapOf()
+ fun validate(): AdditionalInfo = apply {
+ if (validated) {
+ return@apply
+ }
- @JvmSynthetic
- internal fun from(corporateBond: CorporateBond) = apply {
- additionalInfo = corporateBond.additionalInfo
- isin = corporateBond.isin
- name = corporateBond.name
- units = corporateBond.units
- value = corporateBond.value
- additionalProperties = corporateBond.additionalProperties.toMutableMap()
+ closeUnits()
+ openUnits()
+ validated = true
}
- /** Additional information specific to the corporate bond */
- fun additionalInfo(additionalInfo: JsonValue) = apply {
- this.additionalInfo = additionalInfo
- }
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: CasParserInvalidDataException) {
+ false
+ }
- /** ISIN code of the corporate bond */
- fun isin(isin: String) = isin(JsonField.of(isin))
+ /**
+ * 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 (closeUnits.asKnown().isPresent) 1 else 0) +
+ (if (openUnits.asKnown().isPresent) 1 else 0)
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) {
+ return true
+ }
+
+ return other is AdditionalInfo &&
+ closeUnits == other.closeUnits &&
+ openUnits == other.openUnits &&
+ additionalProperties == other.additionalProperties
+ }
+
+ private val hashCode: Int by lazy {
+ Objects.hash(closeUnits, openUnits, additionalProperties)
+ }
+
+ override fun hashCode(): Int = hashCode
+
+ override fun toString() =
+ "AdditionalInfo{closeUnits=$closeUnits, openUnits=$openUnits, additionalProperties=$additionalProperties}"
+ }
+
+ /**
+ * Unified transaction schema for all holding types (MF folios, equities, bonds,
+ * etc.)
+ */
+ class Transaction
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
+ private constructor(
+ private val additionalInfo: JsonField,
+ private val amount: JsonField,
+ private val balance: JsonField,
+ private val date: JsonField,
+ private val description: JsonField,
+ private val dividendRate: JsonField,
+ private val nav: JsonField,
+ private val type: JsonField,
+ private val units: JsonField,
+ private val additionalProperties: MutableMap,
+ ) {
+
+ @JsonCreator
+ private constructor(
+ @JsonProperty("additional_info")
+ @ExcludeMissing
+ additionalInfo: JsonField = JsonMissing.of(),
+ @JsonProperty("amount")
+ @ExcludeMissing
+ amount: JsonField = JsonMissing.of(),
+ @JsonProperty("balance")
+ @ExcludeMissing
+ balance: JsonField = JsonMissing.of(),
+ @JsonProperty("date")
+ @ExcludeMissing
+ date: JsonField = JsonMissing.of(),
+ @JsonProperty("description")
+ @ExcludeMissing
+ description: JsonField = JsonMissing.of(),
+ @JsonProperty("dividend_rate")
+ @ExcludeMissing
+ dividendRate: JsonField = JsonMissing.of(),
+ @JsonProperty("nav")
+ @ExcludeMissing
+ nav: JsonField = JsonMissing.of(),
+ @JsonProperty("type")
+ @ExcludeMissing
+ type: JsonField = JsonMissing.of(),
+ @JsonProperty("units")
+ @ExcludeMissing
+ units: JsonField = JsonMissing.of(),
+ ) : this(
+ additionalInfo,
+ amount,
+ balance,
+ date,
+ description,
+ dividendRate,
+ nav,
+ type,
+ units,
+ mutableMapOf(),
+ )
/**
- * Sets [Builder.isin] to an arbitrary JSON value.
+ * Additional transaction-specific fields that vary by source
*
- * You should usually call [Builder.isin] with a well-typed [String] value
- * instead. This method is primarily for setting the field to an undocumented or
- * not yet supported value.
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected
+ * type (e.g. if the server responded with an unexpected value).
*/
- fun isin(isin: JsonField) = apply { this.isin = isin }
+ fun additionalInfo(): Optional =
+ additionalInfo.getOptional("additional_info")
- /** Name of the corporate bond */
- fun name(name: String) = name(JsonField.of(name))
+ /**
+ * Transaction amount in currency (computed from units × price/NAV)
+ *
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected
+ * type (e.g. if the server responded with an unexpected value).
+ */
+ fun amount(): Optional = amount.getOptional("amount")
/**
- * Sets [Builder.name] to an arbitrary JSON value.
+ * Balance units after transaction
*
- * You should usually call [Builder.name] with a well-typed [String] value
- * instead. This method is primarily for setting the field to an undocumented or
- * not yet supported value.
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected
+ * type (e.g. if the server responded with an unexpected value).
*/
- fun name(name: JsonField) = apply { this.name = name }
+ fun balance(): Optional = balance.getOptional("balance")
- /** Number of units held */
- fun units(units: Float) = units(JsonField.of(units))
+ /**
+ * Transaction date (YYYY-MM-DD)
+ *
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected
+ * type (e.g. if the server responded with an unexpected value).
+ */
+ fun date(): Optional = date.getOptional("date")
/**
- * Sets [Builder.units] to an arbitrary JSON value.
+ * Transaction description/particulars
*
- * You should usually call [Builder.units] with a well-typed [Float] value
- * instead. This method is primarily for setting the field to an undocumented or
- * not yet supported value.
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected
+ * type (e.g. if the server responded with an unexpected value).
*/
- fun units(units: JsonField) = apply { this.units = units }
+ fun description(): Optional = description.getOptional("description")
- /** Current market value of the holding */
- fun value(value: Float) = value(JsonField.of(value))
+ /**
+ * Dividend rate (for DIVIDEND_PAYOUT transactions)
+ *
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected
+ * type (e.g. if the server responded with an unexpected value).
+ */
+ fun dividendRate(): Optional = dividendRate.getOptional("dividend_rate")
/**
- * Sets [Builder.value] to an arbitrary JSON value.
+ * NAV/price per unit on transaction date
*
- * You should usually call [Builder.value] with a well-typed [Float] value
- * instead. This method is primarily for setting the field to an undocumented or
- * not yet supported value.
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected
+ * type (e.g. if the server responded with an unexpected value).
*/
- fun value(value: JsonField) = apply { this.value = value }
+ fun nav(): Optional = nav.getOptional("nav")
- fun additionalProperties(additionalProperties: Map) = apply {
- this.additionalProperties.clear()
- putAllAdditionalProperties(additionalProperties)
- }
+ /**
+ * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION,
+ * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER, DIVIDEND_PAYOUT,
+ * DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX, STT_TAX, MISC,
+ * REVERSAL, UNKNOWN.
+ *
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected
+ * type (e.g. if the server responded with an unexpected value).
+ */
+ fun type(): Optional = type.getOptional("type")
- fun putAdditionalProperty(key: String, value: JsonValue) = apply {
+ /**
+ * Number of units involved in transaction
+ *
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected
+ * type (e.g. if the server responded with an unexpected value).
+ */
+ fun units(): Optional = units.getOptional("units")
+
+ /**
+ * Returns the raw JSON value of [additionalInfo].
+ *
+ * Unlike [additionalInfo], this method doesn't throw if the JSON field has an
+ * unexpected type.
+ */
+ @JsonProperty("additional_info")
+ @ExcludeMissing
+ fun _additionalInfo(): JsonField = additionalInfo
+
+ /**
+ * Returns the raw JSON value of [amount].
+ *
+ * Unlike [amount], this method doesn't throw if the JSON field has an
+ * unexpected type.
+ */
+ @JsonProperty("amount") @ExcludeMissing fun _amount(): JsonField = amount
+
+ /**
+ * Returns the raw JSON value of [balance].
+ *
+ * Unlike [balance], this method doesn't throw if the JSON field has an
+ * unexpected type.
+ */
+ @JsonProperty("balance")
+ @ExcludeMissing
+ fun _balance(): JsonField = balance
+
+ /**
+ * Returns the raw JSON value of [date].
+ *
+ * Unlike [date], this method doesn't throw if the JSON field has an unexpected
+ * type.
+ */
+ @JsonProperty("date") @ExcludeMissing fun _date(): JsonField = date
+
+ /**
+ * Returns the raw JSON value of [description].
+ *
+ * Unlike [description], this method doesn't throw if the JSON field has an
+ * unexpected type.
+ */
+ @JsonProperty("description")
+ @ExcludeMissing
+ fun _description(): JsonField = description
+
+ /**
+ * Returns the raw JSON value of [dividendRate].
+ *
+ * Unlike [dividendRate], this method doesn't throw if the JSON field has an
+ * unexpected type.
+ */
+ @JsonProperty("dividend_rate")
+ @ExcludeMissing
+ fun _dividendRate(): JsonField = dividendRate
+
+ /**
+ * Returns the raw JSON value of [nav].
+ *
+ * Unlike [nav], this method doesn't throw if the JSON field has an unexpected
+ * type.
+ */
+ @JsonProperty("nav") @ExcludeMissing fun _nav(): JsonField = nav
+
+ /**
+ * Returns the raw JSON value of [type].
+ *
+ * Unlike [type], this method doesn't throw if the JSON field has an unexpected
+ * type.
+ */
+ @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type
+
+ /**
+ * Returns the raw JSON value of [units].
+ *
+ * Unlike [units], this method doesn't throw if the JSON field has an unexpected
+ * type.
+ */
+ @JsonProperty("units") @ExcludeMissing fun _units(): JsonField = units
+
+ @JsonAnySetter
+ private fun putAdditionalProperty(key: String, value: JsonValue) {
additionalProperties.put(key, value)
}
- fun putAllAdditionalProperties(additionalProperties: Map) =
- apply {
- this.additionalProperties.putAll(additionalProperties)
+ @JsonAnyGetter
+ @ExcludeMissing
+ fun _additionalProperties(): Map =
+ Collections.unmodifiableMap(additionalProperties)
+
+ fun toBuilder() = Builder().from(this)
+
+ companion object {
+
+ /**
+ * Returns a mutable builder for constructing an instance of [Transaction].
+ */
+ @JvmStatic fun builder() = Builder()
+ }
+
+ /** A builder for [Transaction]. */
+ class Builder internal constructor() {
+
+ private var additionalInfo: JsonField = JsonMissing.of()
+ private var amount: JsonField = JsonMissing.of()
+ private var balance: JsonField = JsonMissing.of()
+ private var date: JsonField = JsonMissing.of()
+ private var description: JsonField = JsonMissing.of()
+ private var dividendRate: JsonField = JsonMissing.of()
+ private var nav: JsonField = JsonMissing.of()
+ private var type: JsonField = JsonMissing.of()
+ private var units: JsonField = JsonMissing.of()
+ private var additionalProperties: MutableMap =
+ mutableMapOf()
+
+ @JvmSynthetic
+ internal fun from(transaction: Transaction) = apply {
+ additionalInfo = transaction.additionalInfo
+ amount = transaction.amount
+ balance = transaction.balance
+ date = transaction.date
+ description = transaction.description
+ dividendRate = transaction.dividendRate
+ nav = transaction.nav
+ type = transaction.type
+ units = transaction.units
+ additionalProperties = transaction.additionalProperties.toMutableMap()
}
- fun removeAdditionalProperty(key: String) = apply {
- additionalProperties.remove(key)
+ /** Additional transaction-specific fields that vary by source */
+ fun additionalInfo(additionalInfo: AdditionalInfo) =
+ additionalInfo(JsonField.of(additionalInfo))
+
+ /**
+ * Sets [Builder.additionalInfo] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.additionalInfo] with a well-typed
+ * [AdditionalInfo] value instead. This method is primarily for setting the
+ * field to an undocumented or not yet supported value.
+ */
+ fun additionalInfo(additionalInfo: JsonField) = apply {
+ this.additionalInfo = additionalInfo
+ }
+
+ /** Transaction amount in currency (computed from units × price/NAV) */
+ fun amount(amount: Float?) = amount(JsonField.ofNullable(amount))
+
+ /**
+ * Alias for [Builder.amount].
+ *
+ * This unboxed primitive overload exists for backwards compatibility.
+ */
+ fun amount(amount: Float) = amount(amount as Float?)
+
+ /** Alias for calling [Builder.amount] with `amount.orElse(null)`. */
+ fun amount(amount: Optional) = amount(amount.getOrNull())
+
+ /**
+ * Sets [Builder.amount] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.amount] with a well-typed [Float] value
+ * instead. This method is primarily for setting the field to an
+ * undocumented or not yet supported value.
+ */
+ fun amount(amount: JsonField) = apply { this.amount = amount }
+
+ /** Balance units after transaction */
+ fun balance(balance: Float) = balance(JsonField.of(balance))
+
+ /**
+ * Sets [Builder.balance] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.balance] with a well-typed [Float] value
+ * instead. This method is primarily for setting the field to an
+ * undocumented or not yet supported value.
+ */
+ fun balance(balance: JsonField) = apply { this.balance = balance }
+
+ /** Transaction date (YYYY-MM-DD) */
+ fun date(date: LocalDate) = date(JsonField.of(date))
+
+ /**
+ * Sets [Builder.date] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.date] with a well-typed [LocalDate]
+ * value instead. This method is primarily for setting the field to an
+ * undocumented or not yet supported value.
+ */
+ fun date(date: JsonField) = apply { this.date = date }
+
+ /** Transaction description/particulars */
+ fun description(description: String) =
+ description(JsonField.of(description))
+
+ /**
+ * Sets [Builder.description] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.description] with a well-typed [String]
+ * value instead. This method is primarily for setting the field to an
+ * undocumented or not yet supported value.
+ */
+ fun description(description: JsonField) = apply {
+ this.description = description
+ }
+
+ /** Dividend rate (for DIVIDEND_PAYOUT transactions) */
+ fun dividendRate(dividendRate: Float?) =
+ dividendRate(JsonField.ofNullable(dividendRate))
+
+ /**
+ * Alias for [Builder.dividendRate].
+ *
+ * This unboxed primitive overload exists for backwards compatibility.
+ */
+ fun dividendRate(dividendRate: Float) = dividendRate(dividendRate as Float?)
+
+ /**
+ * Alias for calling [Builder.dividendRate] with
+ * `dividendRate.orElse(null)`.
+ */
+ fun dividendRate(dividendRate: Optional) =
+ dividendRate(dividendRate.getOrNull())
+
+ /**
+ * Sets [Builder.dividendRate] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.dividendRate] with a well-typed [Float]
+ * value instead. This method is primarily for setting the field to an
+ * undocumented or not yet supported value.
+ */
+ fun dividendRate(dividendRate: JsonField) = apply {
+ this.dividendRate = dividendRate
+ }
+
+ /** NAV/price per unit on transaction date */
+ fun nav(nav: Float?) = nav(JsonField.ofNullable(nav))
+
+ /**
+ * Alias for [Builder.nav].
+ *
+ * This unboxed primitive overload exists for backwards compatibility.
+ */
+ fun nav(nav: Float) = nav(nav as Float?)
+
+ /** Alias for calling [Builder.nav] with `nav.orElse(null)`. */
+ fun nav(nav: Optional) = nav(nav.getOrNull())
+
+ /**
+ * Sets [Builder.nav] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.nav] with a well-typed [Float] value
+ * instead. This method is primarily for setting the field to an
+ * undocumented or not yet supported value.
+ */
+ fun nav(nav: JsonField) = apply { this.nav = nav }
+
+ /**
+ * Transaction type. Possible values are PURCHASE, PURCHASE_SIP, REDEMPTION,
+ * SWITCH_IN, SWITCH_IN_MERGER, SWITCH_OUT, SWITCH_OUT_MERGER,
+ * DIVIDEND_PAYOUT, DIVIDEND_REINVEST, SEGREGATION, STAMP_DUTY_TAX, TDS_TAX,
+ * STT_TAX, MISC, REVERSAL, UNKNOWN.
+ */
+ fun type(type: Type) = type(JsonField.of(type))
+
+ /**
+ * Sets [Builder.type] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.type] with a well-typed [Type] value
+ * instead. This method is primarily for setting the field to an
+ * undocumented or not yet supported value.
+ */
+ fun type(type: JsonField) = apply { this.type = type }
+
+ /** Number of units involved in transaction */
+ fun units(units: Float) = units(JsonField.of(units))
+
+ /**
+ * Sets [Builder.units] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.units] with a well-typed [Float] value
+ * instead. This method is primarily for setting the field to an
+ * undocumented or not yet supported value.
+ */
+ fun units(units: JsonField) = apply { this.units = units }
+
+ 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 [Transaction].
+ *
+ * Further updates to this [Builder] will not mutate the returned instance.
+ */
+ fun build(): Transaction =
+ Transaction(
+ additionalInfo,
+ amount,
+ balance,
+ date,
+ description,
+ dividendRate,
+ nav,
+ type,
+ units,
+ additionalProperties.toMutableMap(),
+ )
}
- fun removeAllAdditionalProperties(keys: Set) = apply {
- keys.forEach(::removeAdditionalProperty)
+ private var validated: Boolean = false
+
+ fun validate(): Transaction = apply {
+ if (validated) {
+ return@apply
+ }
+
+ additionalInfo().ifPresent { it.validate() }
+ amount()
+ balance()
+ date()
+ description()
+ dividendRate()
+ nav()
+ type().ifPresent { it.validate() }
+ units()
+ validated = true
}
+ fun isValid(): Boolean =
+ try {
+ validate()
+ true
+ } catch (e: CasParserInvalidDataException) {
+ false
+ }
+
/**
- * Returns an immutable instance of [CorporateBond].
+ * Returns a score indicating how many valid values are contained in this object
+ * recursively.
*
- * Further updates to this [Builder] will not mutate the returned instance.
+ * Used for best match union deserialization.
*/
- fun build(): CorporateBond =
- CorporateBond(
- additionalInfo,
- isin,
- name,
- units,
- value,
- additionalProperties.toMutableMap(),
+ @JvmSynthetic
+ internal fun validity(): Int =
+ (additionalInfo.asKnown().getOrNull()?.validity() ?: 0) +
+ (if (amount.asKnown().isPresent) 1 else 0) +
+ (if (balance.asKnown().isPresent) 1 else 0) +
+ (if (date.asKnown().isPresent) 1 else 0) +
+ (if (description.asKnown().isPresent) 1 else 0) +
+ (if (dividendRate.asKnown().isPresent) 1 else 0) +
+ (if (nav.asKnown().isPresent) 1 else 0) +
+ (type.asKnown().getOrNull()?.validity() ?: 0) +
+ (if (units.asKnown().isPresent) 1 else 0)
+
+ /** Additional transaction-specific fields that vary by source */
+ class AdditionalInfo
+ @JsonCreator(mode = JsonCreator.Mode.DISABLED)
+ private constructor(
+ private val capitalWithdrawal: JsonField,
+ private val credit: JsonField,
+ private val debit: JsonField,
+ private val incomeDistribution: JsonField,
+ private val orderNo: JsonField,
+ private val price: JsonField,
+ private val stampDuty: JsonField,
+ private val additionalProperties: MutableMap,
+ ) {
+
+ @JsonCreator
+ private constructor(
+ @JsonProperty("capital_withdrawal")
+ @ExcludeMissing
+ capitalWithdrawal: JsonField = JsonMissing.of(),
+ @JsonProperty("credit")
+ @ExcludeMissing
+ credit: JsonField = JsonMissing.of(),
+ @JsonProperty("debit")
+ @ExcludeMissing
+ debit: JsonField = JsonMissing.of(),
+ @JsonProperty("income_distribution")
+ @ExcludeMissing
+ incomeDistribution: JsonField = JsonMissing.of(),
+ @JsonProperty("order_no")
+ @ExcludeMissing
+ orderNo: JsonField = JsonMissing.of(),
+ @JsonProperty("price")
+ @ExcludeMissing
+ price: JsonField = JsonMissing.of(),
+ @JsonProperty("stamp_duty")
+ @ExcludeMissing
+ stampDuty: JsonField = JsonMissing.of(),
+ ) : this(
+ capitalWithdrawal,
+ credit,
+ debit,
+ incomeDistribution,
+ orderNo,
+ price,
+ stampDuty,
+ mutableMapOf(),
)
- }
- private var validated: Boolean = false
+ /**
+ * Capital withdrawal amount (CDSL MF transactions)
+ *
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected
+ * type (e.g. if the server responded with an unexpected value).
+ */
+ fun capitalWithdrawal(): Optional =
+ capitalWithdrawal.getOptional("capital_withdrawal")
+
+ /**
+ * Units credited (demat transactions)
+ *
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected
+ * type (e.g. if the server responded with an unexpected value).
+ */
+ fun credit(): Optional = credit.getOptional("credit")
+
+ /**
+ * Units debited (demat transactions)
+ *
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected
+ * type (e.g. if the server responded with an unexpected value).
+ */
+ fun debit(): Optional = debit.getOptional("debit")
+
+ /**
+ * Income distribution amount (CDSL MF transactions)
+ *
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected
+ * type (e.g. if the server responded with an unexpected value).
+ */
+ fun incomeDistribution(): Optional =
+ incomeDistribution.getOptional("income_distribution")
+
+ /**
+ * Order/transaction reference number (demat transactions)
+ *
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected
+ * type (e.g. if the server responded with an unexpected value).
+ */
+ fun orderNo(): Optional = orderNo.getOptional("order_no")
+
+ /**
+ * Price per unit (NSDL/CDSL MF transactions)
+ *
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected
+ * type (e.g. if the server responded with an unexpected value).
+ */
+ fun price(): Optional = price.getOptional("price")
+
+ /**
+ * Stamp duty charged
+ *
+ * @throws CasParserInvalidDataException if the JSON field has an unexpected
+ * type (e.g. if the server responded with an unexpected value).
+ */
+ fun stampDuty(): Optional = stampDuty.getOptional("stamp_duty")
+
+ /**
+ * Returns the raw JSON value of [capitalWithdrawal].
+ *
+ * Unlike [capitalWithdrawal], this method doesn't throw if the JSON field
+ * has an unexpected type.
+ */
+ @JsonProperty("capital_withdrawal")
+ @ExcludeMissing
+ fun _capitalWithdrawal(): JsonField = capitalWithdrawal
+
+ /**
+ * Returns the raw JSON value of [credit].
+ *
+ * Unlike [credit], this method doesn't throw if the JSON field has an
+ * unexpected type.
+ */
+ @JsonProperty("credit")
+ @ExcludeMissing
+ fun _credit(): JsonField = credit
+
+ /**
+ * Returns the raw JSON value of [debit].
+ *
+ * Unlike [debit], this method doesn't throw if the JSON field has an
+ * unexpected type.
+ */
+ @JsonProperty("debit")
+ @ExcludeMissing
+ fun _debit(): JsonField = debit
+
+ /**
+ * Returns the raw JSON value of [incomeDistribution].
+ *
+ * Unlike [incomeDistribution], this method doesn't throw if the JSON field
+ * has an unexpected type.
+ */
+ @JsonProperty("income_distribution")
+ @ExcludeMissing
+ fun _incomeDistribution(): JsonField = incomeDistribution
+
+ /**
+ * Returns the raw JSON value of [orderNo].
+ *
+ * Unlike [orderNo], this method doesn't throw if the JSON field has an
+ * unexpected type.
+ */
+ @JsonProperty("order_no")
+ @ExcludeMissing
+ fun _orderNo(): JsonField = orderNo
+
+ /**
+ * Returns the raw JSON value of [price].
+ *
+ * Unlike [price], this method doesn't throw if the JSON field has an
+ * unexpected type.
+ */
+ @JsonProperty("price")
+ @ExcludeMissing
+ fun _price(): JsonField = price
+
+ /**
+ * Returns the raw JSON value of [stampDuty].
+ *
+ * Unlike [stampDuty], this method doesn't throw if the JSON field has an
+ * unexpected type.
+ */
+ @JsonProperty("stamp_duty")
+ @ExcludeMissing
+ fun _stampDuty(): JsonField = stampDuty
+
+ @JsonAnySetter
+ private fun putAdditionalProperty(key: String, value: JsonValue) {
+ additionalProperties.put(key, value)
+ }
- fun validate(): CorporateBond = apply {
- if (validated) {
- return@apply
- }
+ @JsonAnyGetter
+ @ExcludeMissing
+ fun _additionalProperties(): Map =
+ Collections.unmodifiableMap(additionalProperties)
- isin()
- name()
- units()
- value()
- validated = true
- }
+ fun toBuilder() = Builder().from(this)
- fun isValid(): Boolean =
- try {
- validate()
- true
- } catch (e: CasParserInvalidDataException) {
- false
- }
+ companion object {
- /**
- * 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 (isin.asKnown().isPresent) 1 else 0) +
- (if (name.asKnown().isPresent) 1 else 0) +
- (if (units.asKnown().isPresent) 1 else 0) +
- (if (value.asKnown().isPresent) 1 else 0)
+ /**
+ * Returns a mutable builder for constructing an instance of
+ * [AdditionalInfo].
+ */
+ @JvmStatic fun builder() = Builder()
+ }
- override fun equals(other: Any?): Boolean {
- if (this === other) {
- return true
+ /** A builder for [AdditionalInfo]. */
+ class Builder internal constructor() {
+
+ private var capitalWithdrawal: JsonField = JsonMissing.of()
+ private var credit: JsonField = JsonMissing.of()
+ private var debit: JsonField = JsonMissing.of()
+ private var incomeDistribution: JsonField = JsonMissing.of()
+ private var orderNo: JsonField = JsonMissing.of()
+ private var price: JsonField = JsonMissing.of()
+ private var stampDuty: JsonField = JsonMissing.of()
+ private var additionalProperties: MutableMap =
+ mutableMapOf()
+
+ @JvmSynthetic
+ internal fun from(additionalInfo: AdditionalInfo) = apply {
+ capitalWithdrawal = additionalInfo.capitalWithdrawal
+ credit = additionalInfo.credit
+ debit = additionalInfo.debit
+ incomeDistribution = additionalInfo.incomeDistribution
+ orderNo = additionalInfo.orderNo
+ price = additionalInfo.price
+ stampDuty = additionalInfo.stampDuty
+ additionalProperties =
+ additionalInfo.additionalProperties.toMutableMap()
+ }
+
+ /** Capital withdrawal amount (CDSL MF transactions) */
+ fun capitalWithdrawal(capitalWithdrawal: Float) =
+ capitalWithdrawal(JsonField.of(capitalWithdrawal))
+
+ /**
+ * Sets [Builder.capitalWithdrawal] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.capitalWithdrawal] with a well-typed
+ * [Float] value instead. This method is primarily for setting the field
+ * to an undocumented or not yet supported value.
+ */
+ fun capitalWithdrawal(capitalWithdrawal: JsonField) = apply {
+ this.capitalWithdrawal = capitalWithdrawal
+ }
+
+ /** Units credited (demat transactions) */
+ fun credit(credit: Float) = credit(JsonField.of(credit))
+
+ /**
+ * Sets [Builder.credit] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.credit] with a well-typed [Float]
+ * value instead. This method is primarily for setting the field to an
+ * undocumented or not yet supported value.
+ */
+ fun credit(credit: JsonField) = apply { this.credit = credit }
+
+ /** Units debited (demat transactions) */
+ fun debit(debit: Float) = debit(JsonField.of(debit))
+
+ /**
+ * Sets [Builder.debit] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.debit] with a well-typed [Float]
+ * value instead. This method is primarily for setting the field to an
+ * undocumented or not yet supported value.
+ */
+ fun debit(debit: JsonField) = apply { this.debit = debit }
+
+ /** Income distribution amount (CDSL MF transactions) */
+ fun incomeDistribution(incomeDistribution: Float) =
+ incomeDistribution(JsonField.of(incomeDistribution))
+
+ /**
+ * Sets [Builder.incomeDistribution] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.incomeDistribution] with a
+ * well-typed [Float] value instead. This method is primarily for
+ * setting the field to an undocumented or not yet supported value.
+ */
+ fun incomeDistribution(incomeDistribution: JsonField) = apply {
+ this.incomeDistribution = incomeDistribution
+ }
+
+ /** Order/transaction reference number (demat transactions) */
+ fun orderNo(orderNo: String) = orderNo(JsonField.of(orderNo))
+
+ /**
+ * Sets [Builder.orderNo] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.orderNo] with a well-typed [String]
+ * value instead. This method is primarily for setting the field to an
+ * undocumented or not yet supported value.
+ */
+ fun orderNo(orderNo: JsonField) = apply {
+ this.orderNo = orderNo
+ }
+
+ /** Price per unit (NSDL/CDSL MF transactions) */
+ fun price(price: Float) = price(JsonField.of(price))
+
+ /**
+ * Sets [Builder.price] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.price] with a well-typed [Float]
+ * value instead. This method is primarily for setting the field to an
+ * undocumented or not yet supported value.
+ */
+ fun price(price: JsonField) = apply { this.price = price }
+
+ /** Stamp duty charged */
+ fun stampDuty(stampDuty: Float) = stampDuty(JsonField.of(stampDuty))
+
+ /**
+ * Sets [Builder.stampDuty] to an arbitrary JSON value.
+ *
+ * You should usually call [Builder.stampDuty] with a well-typed [Float]
+ * value instead. This method is primarily for setting the field to an
+ * undocumented or not yet supported value.
+ */
+ fun stampDuty(stampDuty: JsonField) = apply {
+ this.stampDuty = stampDuty
+ }
+
+ fun additionalProperties(additionalProperties: Map