Skip to content
Open
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
200 changes: 200 additions & 0 deletions sdk-core/api/sdk-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -2260,6 +2260,42 @@ public final class org/dexpace/sdk/core/pipeline/step/retry/RetryStep : org/dexp
public final class org/dexpace/sdk/core/pipeline/step/retry/RetryStep$Companion {
}

public final class org/dexpace/sdk/core/serde/AdditionalProperties {
public static final field Companion Lorg/dexpace/sdk/core/serde/AdditionalProperties$Companion;
public static final field EMPTY Lorg/dexpace/sdk/core/serde/AdditionalProperties;
public synthetic fun <init> (Ljava/util/Map;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public static final fun builder ()Lorg/dexpace/sdk/core/serde/AdditionalProperties$Builder;
public final fun contains (Ljava/lang/String;)Z
public static final fun empty ()Lorg/dexpace/sdk/core/serde/AdditionalProperties;
public fun equals (Ljava/lang/Object;)Z
public final fun get (Ljava/lang/String;)Lorg/dexpace/sdk/core/serde/RawJson;
public final fun getEntries ()Ljava/util/Map;
public final fun getKeys ()Ljava/util/Set;
public final fun getSize ()I
public fun hashCode ()I
public final fun isEmpty ()Z
public final fun newBuilder ()Lorg/dexpace/sdk/core/serde/AdditionalProperties$Builder;
public static final fun of (Ljava/util/Map;)Lorg/dexpace/sdk/core/serde/AdditionalProperties;
public final fun toRawJson ()Lorg/dexpace/sdk/core/serde/RawJson$Obj;
public fun toString ()Ljava/lang/String;
}

public final class org/dexpace/sdk/core/serde/AdditionalProperties$Builder : org/dexpace/sdk/core/generics/Builder {
public fun <init> ()V
public synthetic fun build ()Ljava/lang/Object;
public fun build ()Lorg/dexpace/sdk/core/serde/AdditionalProperties;
public final fun clear ()Lorg/dexpace/sdk/core/serde/AdditionalProperties$Builder;
public final fun put (Ljava/lang/String;Lorg/dexpace/sdk/core/serde/RawJson;)Lorg/dexpace/sdk/core/serde/AdditionalProperties$Builder;
public final fun putAll (Ljava/util/Map;)Lorg/dexpace/sdk/core/serde/AdditionalProperties$Builder;
public final fun remove (Ljava/lang/String;)Lorg/dexpace/sdk/core/serde/AdditionalProperties$Builder;
}

public final class org/dexpace/sdk/core/serde/AdditionalProperties$Companion {
public final fun builder ()Lorg/dexpace/sdk/core/serde/AdditionalProperties$Builder;
public final fun empty ()Lorg/dexpace/sdk/core/serde/AdditionalProperties;
public final fun of (Ljava/util/Map;)Lorg/dexpace/sdk/core/serde/AdditionalProperties;
}

public class org/dexpace/sdk/core/serde/DeserializationException : org/dexpace/sdk/core/serde/SerdeException {
public fun <init> ()V
public fun <init> (Ljava/lang/String;)V
Expand All @@ -2273,6 +2309,170 @@ public abstract interface class org/dexpace/sdk/core/serde/Deserializer {
public abstract fun deserialize ([BLjava/lang/Class;)Ljava/lang/Object;
}

public abstract class org/dexpace/sdk/core/serde/JsonField {
public static final field Companion Lorg/dexpace/sdk/core/serde/JsonField$Companion;
public final fun fold (Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun fromTristate (Lorg/dexpace/sdk/core/serde/Tristate;)Lorg/dexpace/sdk/core/serde/JsonField;
public final fun getOrNull ()Ljava/lang/Object;
public final fun isKnown ()Z
public final fun isMissing ()Z
public final fun isNull ()Z
public final fun isRaw ()Z
public static final fun known (Ljava/lang/Object;)Lorg/dexpace/sdk/core/serde/JsonField;
public static final fun missing ()Lorg/dexpace/sdk/core/serde/JsonField;
public static final fun nullValue ()Lorg/dexpace/sdk/core/serde/JsonField;
public static final fun ofNullable (Ljava/lang/Object;)Lorg/dexpace/sdk/core/serde/JsonField;
public static final fun raw (Lorg/dexpace/sdk/core/serde/RawJson;)Lorg/dexpace/sdk/core/serde/JsonField;
public final fun toTristate ()Lorg/dexpace/sdk/core/serde/Tristate;
}

public final class org/dexpace/sdk/core/serde/JsonField$Companion {
public final fun fromTristate (Lorg/dexpace/sdk/core/serde/Tristate;)Lorg/dexpace/sdk/core/serde/JsonField;
public final fun known (Ljava/lang/Object;)Lorg/dexpace/sdk/core/serde/JsonField;
public final fun missing ()Lorg/dexpace/sdk/core/serde/JsonField;
public final fun nullValue ()Lorg/dexpace/sdk/core/serde/JsonField;
public final fun ofNullable (Ljava/lang/Object;)Lorg/dexpace/sdk/core/serde/JsonField;
public final fun raw (Lorg/dexpace/sdk/core/serde/RawJson;)Lorg/dexpace/sdk/core/serde/JsonField;
}

public final class org/dexpace/sdk/core/serde/JsonField$Known : org/dexpace/sdk/core/serde/JsonField {
public fun <init> (Ljava/lang/Object;)V
public final fun component1 ()Ljava/lang/Object;
public final fun copy (Ljava/lang/Object;)Lorg/dexpace/sdk/core/serde/JsonField$Known;
public static synthetic fun copy$default (Lorg/dexpace/sdk/core/serde/JsonField$Known;Ljava/lang/Object;ILjava/lang/Object;)Lorg/dexpace/sdk/core/serde/JsonField$Known;
public fun equals (Ljava/lang/Object;)Z
public final fun getValue ()Ljava/lang/Object;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class org/dexpace/sdk/core/serde/JsonField$Missing : org/dexpace/sdk/core/serde/JsonField {
public static final field INSTANCE Lorg/dexpace/sdk/core/serde/JsonField$Missing;
public fun toString ()Ljava/lang/String;
}

public final class org/dexpace/sdk/core/serde/JsonField$Null : org/dexpace/sdk/core/serde/JsonField {
public static final field INSTANCE Lorg/dexpace/sdk/core/serde/JsonField$Null;
public fun toString ()Ljava/lang/String;
}

public final class org/dexpace/sdk/core/serde/JsonField$Raw : org/dexpace/sdk/core/serde/JsonField {
public fun <init> (Lorg/dexpace/sdk/core/serde/RawJson;)V
public final fun component1 ()Lorg/dexpace/sdk/core/serde/RawJson;
public final fun copy (Lorg/dexpace/sdk/core/serde/RawJson;)Lorg/dexpace/sdk/core/serde/JsonField$Raw;
public static synthetic fun copy$default (Lorg/dexpace/sdk/core/serde/JsonField$Raw;Lorg/dexpace/sdk/core/serde/RawJson;ILjava/lang/Object;)Lorg/dexpace/sdk/core/serde/JsonField$Raw;
public fun equals (Ljava/lang/Object;)Z
public final fun getJson ()Lorg/dexpace/sdk/core/serde/RawJson;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public abstract class org/dexpace/sdk/core/serde/RawJson {
public static final field Companion Lorg/dexpace/sdk/core/serde/RawJson$Companion;
public final fun isNull ()Z
}

public final class org/dexpace/sdk/core/serde/RawJson$Arr : org/dexpace/sdk/core/serde/RawJson {
public static final field Companion Lorg/dexpace/sdk/core/serde/RawJson$Arr$Companion;
public static final field EMPTY Lorg/dexpace/sdk/core/serde/RawJson$Arr;
public synthetic fun <init> (Ljava/util/List;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun equals (Ljava/lang/Object;)Z
public final fun get (I)Lorg/dexpace/sdk/core/serde/RawJson;
public final fun getSize ()I
public final fun getValues ()Ljava/util/List;
public fun hashCode ()I
public final fun isEmpty ()Z
public static final fun of (Ljava/util/List;)Lorg/dexpace/sdk/core/serde/RawJson$Arr;
public fun toString ()Ljava/lang/String;
}

public final class org/dexpace/sdk/core/serde/RawJson$Arr$Companion {
public final fun of (Ljava/util/List;)Lorg/dexpace/sdk/core/serde/RawJson$Arr;
}

public final class org/dexpace/sdk/core/serde/RawJson$Bool : org/dexpace/sdk/core/serde/RawJson {
public static final field Companion Lorg/dexpace/sdk/core/serde/RawJson$Bool$Companion;
public static final field FALSE Lorg/dexpace/sdk/core/serde/RawJson$Bool;
public static final field TRUE Lorg/dexpace/sdk/core/serde/RawJson$Bool;
public fun <init> (Z)V
public final fun component1 ()Z
public final fun copy (Z)Lorg/dexpace/sdk/core/serde/RawJson$Bool;
public static synthetic fun copy$default (Lorg/dexpace/sdk/core/serde/RawJson$Bool;ZILjava/lang/Object;)Lorg/dexpace/sdk/core/serde/RawJson$Bool;
public fun equals (Ljava/lang/Object;)Z
public final fun getValue ()Z
public fun hashCode ()I
public static final fun of (Z)Lorg/dexpace/sdk/core/serde/RawJson$Bool;
public fun toString ()Ljava/lang/String;
}

public final class org/dexpace/sdk/core/serde/RawJson$Bool$Companion {
public final fun of (Z)Lorg/dexpace/sdk/core/serde/RawJson$Bool;
}

public final class org/dexpace/sdk/core/serde/RawJson$Companion {
}

public final class org/dexpace/sdk/core/serde/RawJson$Null : org/dexpace/sdk/core/serde/RawJson {
public static final field INSTANCE Lorg/dexpace/sdk/core/serde/RawJson$Null;
public fun toString ()Ljava/lang/String;
}

public final class org/dexpace/sdk/core/serde/RawJson$Num : org/dexpace/sdk/core/serde/RawJson {
public static final field Companion Lorg/dexpace/sdk/core/serde/RawJson$Num$Companion;
public fun <init> (Ljava/lang/String;)V
public final fun component1 ()Ljava/lang/String;
public final fun copy (Ljava/lang/String;)Lorg/dexpace/sdk/core/serde/RawJson$Num;
public static synthetic fun copy$default (Lorg/dexpace/sdk/core/serde/RawJson$Num;Ljava/lang/String;ILjava/lang/Object;)Lorg/dexpace/sdk/core/serde/RawJson$Num;
public fun equals (Ljava/lang/Object;)Z
public final fun getLiteral ()Ljava/lang/String;
public fun hashCode ()I
public static final fun of (I)Lorg/dexpace/sdk/core/serde/RawJson$Num;
public static final fun of (J)Lorg/dexpace/sdk/core/serde/RawJson$Num;
public static final fun of (Ljava/math/BigDecimal;)Lorg/dexpace/sdk/core/serde/RawJson$Num;
public final fun toBigDecimal ()Ljava/math/BigDecimal;
public final fun toDouble ()D
public final fun toIntOrNull ()Ljava/lang/Integer;
public final fun toLongOrNull ()Ljava/lang/Long;
public fun toString ()Ljava/lang/String;
}

public final class org/dexpace/sdk/core/serde/RawJson$Num$Companion {
public final fun of (I)Lorg/dexpace/sdk/core/serde/RawJson$Num;
public final fun of (J)Lorg/dexpace/sdk/core/serde/RawJson$Num;
public final fun of (Ljava/math/BigDecimal;)Lorg/dexpace/sdk/core/serde/RawJson$Num;
}

public final class org/dexpace/sdk/core/serde/RawJson$Obj : org/dexpace/sdk/core/serde/RawJson {
public static final field Companion Lorg/dexpace/sdk/core/serde/RawJson$Obj$Companion;
public static final field EMPTY Lorg/dexpace/sdk/core/serde/RawJson$Obj;
public synthetic fun <init> (Ljava/util/Map;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun contains (Ljava/lang/String;)Z
public fun equals (Ljava/lang/Object;)Z
public final fun get (Ljava/lang/String;)Lorg/dexpace/sdk/core/serde/RawJson;
public final fun getEntries ()Ljava/util/Map;
public final fun getKeys ()Ljava/util/Set;
public final fun getSize ()I
public fun hashCode ()I
public final fun isEmpty ()Z
public static final fun of (Ljava/util/Map;)Lorg/dexpace/sdk/core/serde/RawJson$Obj;
public fun toString ()Ljava/lang/String;
}

public final class org/dexpace/sdk/core/serde/RawJson$Obj$Companion {
public final fun of (Ljava/util/Map;)Lorg/dexpace/sdk/core/serde/RawJson$Obj;
}

public final class org/dexpace/sdk/core/serde/RawJson$Str : org/dexpace/sdk/core/serde/RawJson {
public fun <init> (Ljava/lang/String;)V
public final fun component1 ()Ljava/lang/String;
public final fun copy (Ljava/lang/String;)Lorg/dexpace/sdk/core/serde/RawJson$Str;
public static synthetic fun copy$default (Lorg/dexpace/sdk/core/serde/RawJson$Str;Ljava/lang/String;ILjava/lang/Object;)Lorg/dexpace/sdk/core/serde/RawJson$Str;
public fun equals (Ljava/lang/Object;)Z
public final fun getValue ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public abstract interface class org/dexpace/sdk/core/serde/Serde {
public abstract fun getDeserializer ()Lorg/dexpace/sdk/core/serde/Deserializer;
public abstract fun getSerializer ()Lorg/dexpace/sdk/core/serde/Serializer;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* Copyright (c) 2026 dexpace and Omar Aljarrah
*
* Licensed under the MIT License. See LICENSE in the project root.
* SPDX-License-Identifier: MIT
*/

package org.dexpace.sdk.core.serde

/**
* An immutable, insertion-ordered snapshot of the unknown ("additional") JSON properties a model
* carried on the wire — the runtime primitive behind lossless `additionalProperties` pass-through.
*
* The SDK's default mapper does **not** fail on unknown fields (forward compatibility), but Jackson's
* default binding then *drops* them: a read-modify-write loop silently discards any property the
* client model has no field for, including server-added fields the client never meant to touch. A
* generated DTO that mixes [AdditionalProperties] in captures those leftover keys into this holder at
* deserialization and re-emits them on serialization, so the round-trip is lossless.
*
* Values are [RawJson] trees, so the holder stays dependency-free and preserves the exact JSON shape
* — including types the model would not otherwise understand. The map is insertion-ordered so a
* round-trip is byte-stable with respect to key order, and immutable so a built model cannot be
* mutated after the fact; use [newBuilder] to derive a modified copy.
*
* This is a hand-written runtime base usable today; it is also the exact shape a generator would
* target for `@JsonAnySetter`/`@JsonAnyGetter`-style pass-through. The adapter
* (`sdk-serde-jackson`'s `JsonFieldModule`) supplies the Jackson capture/emit wiring; this type
* holds no library dependency.
*/
public class AdditionalProperties private constructor(
private val properties: Map<String, RawJson>,
) {
/** The captured unknown properties as an insertion-ordered, read-only map. */
public val entries: Map<String, RawJson>
get() = properties

/** The captured property names, in insertion order. */
public val keys: Set<String>
get() = properties.keys

/** Returns the captured value for [key], or `null` if no such property was present. */
public operator fun get(key: String): RawJson? = properties[key]

/** Returns `true` if a property named [key] was captured. */
public operator fun contains(key: String): Boolean = properties.containsKey(key)

/** Returns `true` if no additional properties were captured. */
public fun isEmpty(): Boolean = properties.isEmpty()

/** The number of captured properties. */
public val size: Int
get() = properties.size

/** Renders the captured properties as a [RawJson.Obj] for emission. */
public fun toRawJson(): RawJson.Obj = RawJson.Obj.of(properties)

/** Returns a [Builder] pre-filled with this snapshot's properties, for deriving a modified copy. */
public fun newBuilder(): Builder = Builder(properties)

override fun equals(other: Any?): Boolean = other is AdditionalProperties && other.properties == properties

override fun hashCode(): Int = properties.hashCode()

override fun toString(): String = "AdditionalProperties(${toRawJson()})"

/**
* Builder for [AdditionalProperties]. Insertion order of [put] calls is preserved. Implements
* [Builder]<[AdditionalProperties]> per the SDK's immutable-type convention.
*/
public class Builder internal constructor(
initial: Map<String, RawJson>,
) : org.dexpace.sdk.core.generics.Builder<AdditionalProperties> {
private val properties: LinkedHashMap<String, RawJson> = LinkedHashMap(initial)

/** Creates an empty builder. */
public constructor() : this(emptyMap())

/** Records the additional property [key] → [value], replacing any prior value for [key]. */
public fun put(
key: String,
value: RawJson,
): Builder =
apply {
properties[key] = value
}

/** Records every entry of [values], in iteration order. */
public fun putAll(values: Map<String, RawJson>): Builder =
apply {
properties.putAll(values)
}

/** Removes the captured property [key], if present. */
public fun remove(key: String): Builder =
apply {
properties.remove(key)
}

/** Removes all captured properties. */
public fun clear(): Builder =
apply {
properties.clear()
}

override fun build(): AdditionalProperties =
if (properties.isEmpty()) EMPTY else AdditionalProperties(LinkedHashMap(properties))
}

public companion object {
/** An empty snapshot singleton. */
@JvmField
public val EMPTY: AdditionalProperties = AdditionalProperties(emptyMap())

/** Returns the [EMPTY] snapshot. Convenience factory for default field values. */
@JvmStatic
public fun empty(): AdditionalProperties = EMPTY

/** Builds a snapshot from [properties], defensively copied and insertion-ordered. */
@JvmStatic
public fun of(properties: Map<String, RawJson>): AdditionalProperties =
if (properties.isEmpty()) EMPTY else AdditionalProperties(LinkedHashMap(properties))

/** Creates an empty [Builder]. */
@JvmStatic
public fun builder(): Builder = Builder()
}
}
Loading
Loading