Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "4.26.0"
".": "4.27.0"
}
6 changes: 3 additions & 3 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 145
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-31abe25287f6885a9e18e84b9317abcb36a9fff5f694feb7a4353c5622d93730.yml
openapi_spec_hash: 65d48382e29817ef7b89e70b20bf8d4d
config_hash: 3eb0070d128aef7a6da16173f7050177
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-82881993f19c5fac9ac662f1a516e5b54bd7c6655d07f29a3779dfb0286cafd3.yml
openapi_spec_hash: 92f4c510a5a15d091036d70caa8ee573
config_hash: 768b0f5ada2bf01cf2659d5dbbad1fa0
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 4.27.0 (2026-08-10)

Full Changelog: [v4.26.0...v4.27.0](https://github.com/trycourier/courier-java/compare/v4.26.0...v4.27.0)

### Features

* Merge pull request [#185](https://github.com/trycourier/courier-java/issues/185) from trycourier/geraldosilva/c-19821-notifications-alias-v2 ([cd5d43a](https://github.com/trycourier/courier-java/commit/cd5d43ae82d645c083527d1a81de4a513c446e8e))

## 4.26.0 (2026-08-04)

Full Changelog: [v4.25.0...v4.26.0](https://github.com/trycourier/courier-java/compare/v4.25.0...v4.26.0)
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ repositories {

allprojects {
group = "com.courier"
version = "4.26.0" // x-release-please-version
version = "4.27.0" // x-release-please-version
}

subprojects {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ private constructor(

/**
* Request body for replacing a notification template. Same shape as create. All fields required
* (PUT = full replacement).
* (PUT = full replacement), except `alias`, whose omission means "leave the existing aliases
* alone".
*/
fun notificationTemplateUpdateRequest(): NotificationTemplateUpdateRequest =
notificationTemplateUpdateRequest
Expand Down Expand Up @@ -80,7 +81,8 @@ private constructor(

/**
* Request body for replacing a notification template. Same shape as create. All fields
* required (PUT = full replacement).
* required (PUT = full replacement), except `alias`, whose omission means "leave the
* existing aliases alone".
*/
fun notificationTemplateUpdateRequest(
notificationTemplateUpdateRequest: NotificationTemplateUpdateRequest
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
// File generated from our OpenAPI spec by Stainless.

package com.courier.models.notifications

import com.courier.core.BaseDeserializer
import com.courier.core.BaseSerializer
import com.courier.core.JsonValue
import com.courier.core.allMaxBy
import com.courier.core.getOrThrow
import com.courier.core.toImmutable
import com.courier.errors.CourierInvalidDataException
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.ObjectCodec
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.databind.annotation.JsonSerialize
import com.fasterxml.jackson.module.kotlin.jacksonTypeRef
import java.util.Objects
import java.util.Optional

/**
* A template's send-time alias as returned by a read, omitted entirely when it has none. Usually a
* single string; an array for a template that resolves from several aliases, which writes through
* this API can no longer produce — only templates predating that restriction, or aliases attached
* outside this API, hold more than one.
*/
@JsonDeserialize(using = NotificationTemplateAlias.Deserializer::class)
@JsonSerialize(using = NotificationTemplateAlias.Serializer::class)
class NotificationTemplateAlias
private constructor(
private val string: String? = null,
private val strings: List<String>? = null,
private val _json: JsonValue? = null,
) {

fun string(): Optional<String> = Optional.ofNullable(string)

fun strings(): Optional<List<String>> = Optional.ofNullable(strings)

fun isString(): Boolean = string != null

fun isStrings(): Boolean = strings != null

fun asString(): String = string.getOrThrow("string")

fun asStrings(): List<String> = strings.getOrThrow("strings")

fun _json(): Optional<JsonValue> = Optional.ofNullable(_json)

/**
* Maps this instance's current variant to a value of type [T] using the given [visitor].
*
* Note that this method is _not_ forwards compatible with new variants from the API, unless
* [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of the
* SDK gracefully, consider overriding [Visitor.unknown]:
* ```java
* import com.courier.core.JsonValue;
* import java.util.Optional;
*
* Optional<String> result = notificationTemplateAlias.accept(new NotificationTemplateAlias.Visitor<Optional<String>>() {
* @Override
* public Optional<String> visitString(String string) {
* return Optional.of(string.toString());
* }
*
* // ...
*
* @Override
* public Optional<String> unknown(JsonValue json) {
* // Or inspect the `json`.
* return Optional.empty();
* }
* });
* ```
*
* @throws CourierInvalidDataException if [Visitor.unknown] is not overridden in [visitor] and
* the current variant is unknown.
*/
fun <T> accept(visitor: Visitor<T>): T =
when {
string != null -> visitor.visitString(string)
strings != null -> visitor.visitStrings(strings)
else -> visitor.unknown(_json)
}

private var validated: Boolean = false

/**
* Validates that the types of all values in this object match their expected types recursively.
*
* This method is _not_ forwards compatible with new types from the API for existing fields.
*
* @throws CourierInvalidDataException if any value type in this object doesn't match its
* expected type.
*/
fun validate(): NotificationTemplateAlias = apply {
if (validated) {
return@apply
}

accept(
object : Visitor<Unit> {
override fun visitString(string: String) {}

override fun visitStrings(strings: List<String>) {}
}
)
validated = true
}

fun isValid(): Boolean =
try {
validate()
true
} catch (e: CourierInvalidDataException) {
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 =
accept(
object : Visitor<Int> {
override fun visitString(string: String) = 1

override fun visitStrings(strings: List<String>) = strings.size

override fun unknown(json: JsonValue?) = 0
}
)

override fun equals(other: Any?): Boolean {
if (this === other) {
return true
}

return other is NotificationTemplateAlias &&
string == other.string &&
strings == other.strings
}

override fun hashCode(): Int = Objects.hash(string, strings)

override fun toString(): String =
when {
string != null -> "NotificationTemplateAlias{string=$string}"
strings != null -> "NotificationTemplateAlias{strings=$strings}"
_json != null -> "NotificationTemplateAlias{_unknown=$_json}"
else -> throw IllegalStateException("Invalid NotificationTemplateAlias")
}

companion object {

@JvmStatic fun ofString(string: String) = NotificationTemplateAlias(string = string)

@JvmStatic
fun ofStrings(strings: List<String>) =
NotificationTemplateAlias(strings = strings.toImmutable())
}

/**
* An interface that defines how to map each variant of [NotificationTemplateAlias] to a value
* of type [T].
*/
interface Visitor<out T> {

fun visitString(string: String): T

fun visitStrings(strings: List<String>): T

/**
* Maps an unknown variant of [NotificationTemplateAlias] to a value of type [T].
*
* An instance of [NotificationTemplateAlias] can contain an unknown variant if it was
* deserialized from data that doesn't match any known variant. For example, if the SDK is
* on an older version than the API, then the API may respond with new variants that the SDK
* is unaware of.
*
* @throws CourierInvalidDataException in the default implementation.
*/
fun unknown(json: JsonValue?): T {
throw CourierInvalidDataException("Unknown NotificationTemplateAlias: $json")
}
}

internal class Deserializer :
BaseDeserializer<NotificationTemplateAlias>(NotificationTemplateAlias::class) {

override fun ObjectCodec.deserialize(node: JsonNode): NotificationTemplateAlias {
val json = JsonValue.fromJsonNode(node)

val bestMatches =
sequenceOf(
tryDeserialize(node, jacksonTypeRef<String>())?.let {
NotificationTemplateAlias(string = it, _json = json)
},
tryDeserialize(node, jacksonTypeRef<List<String>>())?.let {
NotificationTemplateAlias(strings = it, _json = json)
},
)
.filterNotNull()
.allMaxBy { it.validity() }
.toList()
return when (bestMatches.size) {
// This can happen if what we're deserializing is completely incompatible with all
// the possible variants (e.g. deserializing from boolean).
0 -> NotificationTemplateAlias(_json = json)
1 -> bestMatches.single()
// If there's more than one match with the highest validity, then use the first
// completely valid match, or simply the first match if none are completely valid.
else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first()
}
}
}

internal class Serializer :
BaseSerializer<NotificationTemplateAlias>(NotificationTemplateAlias::class) {

override fun serialize(
value: NotificationTemplateAlias,
generator: JsonGenerator,
provider: SerializerProvider,
) {
when {
value.string != null -> generator.writeObject(value.string)
value.strings != null -> generator.writeObject(value.strings)
value._json != null -> generator.writeObject(value._json)
else -> throw IllegalStateException("Invalid NotificationTemplateAlias")
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import kotlin.jvm.optionals.getOrNull
class NotificationTemplateCreateRequest
@JsonCreator(mode = JsonCreator.Mode.DISABLED)
private constructor(
private val notification: JsonField<NotificationTemplatePayload>,
private val notification: JsonField<NotificationTemplateWritePayload>,
private val state: JsonField<State>,
private val additionalProperties: MutableMap<String, JsonValue>,
) {
Expand All @@ -31,18 +31,17 @@ private constructor(
private constructor(
@JsonProperty("notification")
@ExcludeMissing
notification: JsonField<NotificationTemplatePayload> = JsonMissing.of(),
notification: JsonField<NotificationTemplateWritePayload> = JsonMissing.of(),
@JsonProperty("state") @ExcludeMissing state: JsonField<State> = JsonMissing.of(),
) : this(notification, state, mutableMapOf())

/**
* Core template fields used in POST and PUT request bodies (nested under a `notification` key)
* and returned at the top level in responses.
* Template fields accepted in POST and PUT request bodies, nested under a `notification` key.
*
* @throws CourierInvalidDataException 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 notification(): NotificationTemplatePayload = notification.getRequired("notification")
fun notification(): NotificationTemplateWritePayload = notification.getRequired("notification")

/**
* Template state after creation. Case-insensitive input, normalized to uppercase in the
Expand All @@ -60,7 +59,7 @@ private constructor(
*/
@JsonProperty("notification")
@ExcludeMissing
fun _notification(): JsonField<NotificationTemplatePayload> = notification
fun _notification(): JsonField<NotificationTemplateWritePayload> = notification

/**
* Returns the raw JSON value of [state].
Expand Down Expand Up @@ -98,7 +97,7 @@ private constructor(
/** A builder for [NotificationTemplateCreateRequest]. */
class Builder internal constructor() {

private var notification: JsonField<NotificationTemplatePayload>? = null
private var notification: JsonField<NotificationTemplateWritePayload>? = null
private var state: JsonField<State> = JsonMissing.of()
private var additionalProperties: MutableMap<String, JsonValue> = mutableMapOf()

Expand All @@ -112,20 +111,20 @@ private constructor(
}

/**
* Core template fields used in POST and PUT request bodies (nested under a `notification`
* key) and returned at the top level in responses.
* Template fields accepted in POST and PUT request bodies, nested under a `notification`
* key.
*/
fun notification(notification: NotificationTemplatePayload) =
fun notification(notification: NotificationTemplateWritePayload) =
notification(JsonField.of(notification))

/**
* Sets [Builder.notification] to an arbitrary JSON value.
*
* You should usually call [Builder.notification] with a well-typed
* [NotificationTemplatePayload] value instead. This method is primarily for setting the
* field to an undocumented or not yet supported value.
* [NotificationTemplateWritePayload] value instead. This method is primarily for setting
* the field to an undocumented or not yet supported value.
*/
fun notification(notification: JsonField<NotificationTemplatePayload>) = apply {
fun notification(notification: JsonField<NotificationTemplateWritePayload>) = apply {
this.notification = notification
}

Expand Down
Loading
Loading