diff --git a/CHANGELOG.md b/CHANGELOG.md index a6db8bdb..a4fd62e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,15 @@ - Add `tarantool-spring-data-40` module with support for Spring Boot 4.0.x and Spring Data 4.0.x +### Testcontainers + +- Add constructor/builder parameters to supply the initial Lua script as a string or as a file path, and optional additional script paths copied into the container data directory (`Tarantool2Container`, `CartridgeClusterContainer`, `VshardClusterContainer`); simplify bundled `server.lua` accordingly. + +### Documentation + +- Document supported Java types for Tarantool data mapping in `tuple_pojo_mapping` docs (RU/EN), including Tarantool extension types (`decimal`, `uuid`, `datetime`, `interval`, `tuple`) and related mapping notes. +- Document Jackson MsgPack deserialization: integers, `bin`/`str` vs `byte[]`/`String`, floating-point vs `decimal`; reference `jackson-dataformat-msgpack` for defaults and type coercion. + ## [1.6.0] - 2026-04-01 ### BOM Module diff --git a/documentation/doc-src/pages/client/arch/tuple_pojo_mapping.en.md b/documentation/doc-src/pages/client/arch/tuple_pojo_mapping.en.md index 2a215c29..2553cbcb 100644 --- a/documentation/doc-src/pages/client/arch/tuple_pojo_mapping.en.md +++ b/documentation/doc-src/pages/client/arch/tuple_pojo_mapping.en.md @@ -25,6 +25,75 @@ guide, but will help you understand the principles of interaction. Mastering the efficiently with the database in any scenarios, whether it's a cluster or a single instance, and with any POJO objects. +## Supported Java Types for Mapping + +The SDK uses `Jackson + jackson-dataformat-msgpack`, so: + +- standard Java/Jackson types (primitives and wrappers, `String`, `byte[]`, `List`, `Map`, nested POJOs) + are supported by default; +- Tarantool extension types are additionally supported. + +Below are the types that have explicit Tarantool extension-type mapping in the SDK: + +| Tarantool type | Java type | Comment | +| --- | --- | --- | +| `decimal` | `java.math.BigDecimal` | Uses MsgPack `decimal` extension; scale with absolute value up to and including `38` is supported. | +| `uuid` | `java.util.UUID` | Uses MsgPack `uuid` extension. | +| `datetime` | `java.time.Instant`, `java.time.LocalDateTime`, `java.time.LocalDate`, `java.time.LocalTime`, `java.time.OffsetDateTime`, `java.time.ZonedDateTime` | Uses MsgPack `datetime` extension. | +| `interval` | `io.tarantool.mapping.Interval` | Uses MsgPack `interval` extension. | +| `tuple` (Tarantool 3.x, `TUPLE_EXT`) | `io.tarantool.mapping.Tuple` | Uses MsgPack `tuple` extension; useful when tuple format is returned with tuple data. | + +???+ note "Note" + + If you read data as `Object` (without an explicit target type), extension values are + deserialized to SDK Java objects automatically: + `decimal -> BigDecimal`, `uuid -> UUID`, `datetime -> ZonedDateTime`, + `interval -> Interval`, `tuple -> Tuple`. + +## Jackson MsgPack: defaults and deserialization + +POJO mapping uses **Jackson** and the [**jackson-dataformat-msgpack**](https://github.com/FasterXML/jackson-dataformats-binary/tree/2.18/msg-pack) module. +Handling of **missing properties**, **default values**, and **type coercion** on deserialization is defined by Jackson configuration and API (`DeserializationFeature`, constructors, `@JsonCreator`, etc.) and by the actual MsgPack value type on the wire. Authoritative specification is in the `jackson-dataformat-msgpack` documentation and release notes for the Jackson line in use. + +### Integers + +MsgPack encodes integers with variable width (fixint, int8/16/32/64, uint*). The deserializer coerces them to the declared Java type (`int`, `long`, `Integer`, `BigInteger`, ...). +If the target type is **narrower** than the wire value allows, deserialization may fail or lose precision; the Java field type must match the value range stored in Tarantool (including large `unsigned` values). + +### Deserialization into `Object` (untyped) + +If the target type is `java.lang.Object` (including elements of `List`, values in `Map`, and raw `Object` fields), Jackson uses `UntypedObjectDeserializer` and, for numbers, `JsonParser.getNumberValue()`. The SDK depends on **`org.msgpack:jackson-dataformat-msgpack`**; scalar shapes are determined by its `MessagePackParser` (integers are **not** mapped to `Byte`/`Short` just because the wire encoding is small). + +| MsgPack on the wire | Java type when binding to `Object` (default `ObjectMapper` in the SDK) | +| --- | --- | +| **Signed** integer (fixint, int8, int16, int32, int64) | `Integer` if the value fits in `int`; otherwise `Long` | +| **uint64** | `Long` if the value fits in signed `long`; otherwise `BigInteger` | +| **float32** / **float64** | `Double` (both are read as double-precision) | +| **nil** | `null` | +| **boolean** | `Boolean` | +| **binary** (`bin`) | `byte[]` | +| **string** (`str`) | `String` | +| **map** | `LinkedHashMap` | +| **array** | `ArrayList` | +| Tarantool/SDK **extensions** (`decimal`, `uuid`, `datetime`, …) | `BigDecimal`, `UUID`, `ZonedDateTime`, `Interval`, `Tuple`, … (see the Tarantool/SDK type table and the `Object` note at the start of the POJO section) | + +With `DeserializationFeature.USE_BIG_INTEGER_FOR_INTS` enabled on the `ObjectMapper`, untyped integers may always deserialize as `BigInteger` — see Jackson Javadoc. `BaseTarantoolJacksonMapping` does **not** enable this flag. + +### `byte[]` and `String` (`bin` and `str` families) + +In MsgPack, **binary** (`bin` family) and **string** (`str` family) are distinct. Default mapping: + +- **`byte[]`** — **binary** payload; +- **`String`** — **string** payload (UTF-8). + +A mismatch between the MsgPack format and the Java field type (for example, **string** on the wire and **`byte[]`** in the POJO) does not guarantee successful deserialization with the module defaults. Alternatives: aligned storage schema and POJO types, an intermediate type with conversion, **`@JsonDeserialize`**, or a custom `JsonDeserializer` (see `jackson-dataformat-msgpack` documentation). + +### `float` / `double` and `decimal` + +Non-extension floating-point values in MsgPack are **float32** / **float64**. Tarantool **`decimal`** is transmitted as a **MsgPack extension** in this SDK and maps to **`java.math.BigDecimal`** (table above). + +Pairing **float32/float64** on the wire with a **`BigDecimal`** field, or a **decimal extension** with **`float`** / **`double`**, follows Jackson type-coercion rules and the module version; an explicit field type or a boundary deserializer may be required. + ## Efficient Mapping (Flatten input, Flatten output) By default, field mapping in any of the clients (CrudClient, BoxClient) is performed in the most diff --git a/documentation/doc-src/pages/client/arch/tuple_pojo_mapping.md b/documentation/doc-src/pages/client/arch/tuple_pojo_mapping.md index 4c53bf08..d36e4f04 100644 --- a/documentation/doc-src/pages/client/arch/tuple_pojo_mapping.md +++ b/documentation/doc-src/pages/client/arch/tuple_pojo_mapping.md @@ -27,6 +27,75 @@ tarantool-java-sdk SDK есть модуль, который будет сери работать с базой данных в любых сценариях, будь то кластер или одиночный экземпляр, и с любыми POJO объектами. +## Поддерживаемые Java-типы при маппинге + +SDK использует `Jackson + jackson-dataformat-msgpack`, поэтому: + +- базовые типы Java/Jackson (примитивы и их обертки, `String`, `byte[]`, `List`, `Map`, вложенные POJO) + поддерживаются по умолчанию; +- дополнительно поддерживаются extension-типы Tarantool. + +Ниже приведены типы, для которых в SDK есть явный маппинг из/в Tarantool extension types: + +| Tarantool type | Java type | Комментарий | +| --- | --- | --- | +| `decimal` | `java.math.BigDecimal` | Используется MsgPack extension `decimal`; поддерживается scale по модулю до `38` включительно. | +| `uuid` | `java.util.UUID` | Используется MsgPack extension `uuid`. | +| `datetime` | `java.time.Instant`, `java.time.LocalDateTime`, `java.time.LocalDate`, `java.time.LocalTime`, `java.time.OffsetDateTime`, `java.time.ZonedDateTime` | Используется MsgPack extension `datetime`. | +| `interval` | `io.tarantool.mapping.Interval` | Используется MsgPack extension `interval`. | +| `tuple` (Tarantool 3.x, `TUPLE_EXT`) | `io.tarantool.mapping.Tuple` | Используется MsgPack extension `tuple`; полезно, когда вместе с данными приходит формат кортежа. | + +???+ note "Заметка" + + Если вы читаете данные как `Object` (без явного целевого класса), extension-типы будут + десериализованы в Java-объекты SDK автоматически: + `decimal -> BigDecimal`, `uuid -> UUID`, `datetime -> ZonedDateTime`, + `interval -> Interval`, `tuple -> Tuple`. + +## Jackson MsgPack: значения по умолчанию и десериализация + +Маппинг POJO выполняется через **Jackson** и модуль [**jackson-dataformat-msgpack**](https://github.com/FasterXML/jackson-dataformats-binary/tree/2.18/msg-pack). +Обработка **отсутствующих свойств**, **значений по умолчанию** и **приведения типов** при десериализации определяется настройками и API Jackson (`DeserializationFeature`, конструкторы, `@JsonCreator` и др.) и фактическим типом значения в MsgPack. Нормативное описание — в документации и release notes `jackson-dataformat-msgpack` для используемой линии Jackson. + +### Целые числа + +В MsgPack целые значения кодируются с переменной шириной (fixint, int8/16/32/64, uint*). Десериализатор приводит их к объявленному типу Java (`int`, `long`, `Integer`, `BigInteger` и т.д.). +При **более узком** целевом типе, чем допускает значение на wire, возможны ошибка десериализации или потеря точности; тип поля в Java должен соответствовать диапазону данных на стороне Tarantool (в том числе для больших `unsigned`). + +### Десериализация в `Object` (без явного типа) + +Если целевой тип — `java.lang.Object` (в т.ч. элементы `List`, значения в `Map` и поля с сырым `Object`), Jackson использует `UntypedObjectDeserializer`, а для чисел вызывает `JsonParser.getNumberValue()`. В SDK подключается **`org.msgpack:jackson-dataformat-msgpack`**; фактические классы для скаляров задаёт его `MessagePackParser` (целые не становятся `Byte`/`Short` только из‑за «малого» значения на wire). + +| Что приходит в MsgPack | Тип в Java при десериализации в `Object` (настройки `ObjectMapper` по умолчанию в SDK) | +| --- | --- | +| Целое **signed** (fixint, int8, int16, int32, int64) | `Integer`, если значение в диапазоне `int`; иначе `Long` | +| **uint64** | `Long`, если значение помещается в диапазон signed `long`; иначе `BigInteger` | +| **float32** / **float64** | `Double` (оба формата читаются как double-precision) | +| **nil** | `null` | +| **boolean** | `Boolean` | +| **binary** (`bin`) | `byte[]` | +| **string** (`str`) | `String` | +| **map** | `LinkedHashMap` | +| **array** | `ArrayList` | +| **extension** Tarantool/SDK (`decimal`, `uuid`, `datetime`, …) | `BigDecimal`, `UUID`, `ZonedDateTime`, `Interval`, `Tuple`, … (таблица типов и заметка про чтение как `Object` — в начале раздела про POJO) | + +Если на `ObjectMapper` включён `DeserializationFeature.USE_BIG_INTEGER_FOR_INTS`, целые в контексте «untyped» могут стабильно приходить как `BigInteger` — см. Javadoc Jackson. В `BaseTarantoolJacksonMapping` этот флаг **не** включается. + +### `byte[]` и `String` (семейства `bin` и `str`) + +В MsgPack типы **binary** (семейство `bin`) и **string** (семейство `str`) различны. Сопоставление по умолчанию: + +- **`byte[]`** — полезная нагрузка в формате **binary**; +- **`String`** — полезная нагрузка в формате **string** (UTF-8). + +Несовпадение формата MsgPack и типа поля Java (например, **string** на wire и **`byte[]`** в POJO) не гарантирует успешную десериализацию стандартными средствами модуля. Альтернативы: согласованный тип в схеме хранения и в POJO, промежуточный тип с последующим преобразованием, **`@JsonDeserialize`** или пользовательский `JsonDeserializer` (см. документацию `jackson-dataformat-msgpack`). + +### `float` / `double` и `decimal` + +В MsgPack значения с плавающей точкой без extension — **float32** / **float64**. Значение **`decimal`** Tarantool в SDK передаётся как **MsgPack extension** и мапится на **`java.math.BigDecimal`** (таблица выше). + +Сочетание **float32/float64** на wire с полем **`BigDecimal`**, либо **decimal extension** с полем **`float`** / **`double`**, задаётся правилами приведения типов Jackson и версией модуля; при необходимости используется явный тип поля или десериализатор на границе. + ## Эффективный Маппинг (Flatten input, Flatten output) По умолчанию маппинг полей в любом из клиентов(CrudClient, BoxClient), выполняется наиболее