tarantool / cartridge-springdata

Spring Data Tarantool
Other
18 stars 7 forks source link

byte[] mapping problem #62

Open ArtDu opened 3 years ago

ArtDu commented 3 years ago

Добрый день. Средствами cartridge-springdata можно как-то сложить данные в бинарном виде? Пробовал менять поле на varbinary, говорит, что не может строку преобразовать в varbinary, хотя в сущности поле определено с типом byte[]. Пробовал в тарантуле поле оставлять строковым, а в сущности byte[], тоже не работает. В тестах репозитория не нашел примеров с вставкой бинарных данных в тарантул средствами java

To reproduce the problem, I took an existing test by adding a byte [] field to the entity

@Test
public void testSave() {
    BookTranslation translation = BookTranslation.builder()
            .bookId(2)
            .language("Russian")
            .edition(22)
            .translator("Ivan Ivanov")
            .comments("Some translation")
            .bytesString("Hello".getBytes())
            .build();
    BookTranslation newTranslation = bookTranslationRepository.save(translation);
    assertThat(newTranslation).isEqualTo(translation);
}
diff --git a/src/test/java/org/springframework/data/tarantool/entities/BookTranslation.java b/src/test/java/org/springframework/data/tarantool/entities/BookTranslation.java
index 7ea062d..6e573a7 100644
--- a/src/test/java/org/springframework/data/tarantool/entities/BookTranslation.java
+++ b/src/test/java/org/springframework/data/tarantool/entities/BookTranslation.java
@@ -33,4 +33,6 @@ public class BookTranslation {
     private String translator;

     private String comments;
+
+    private byte[] bytesString;
 }
diff --git a/src/test/java/org/springframework/data/tarantool/repository/support/CompositePkIntegrationTest.java b/src/test/java/org/springframework/data/tarantool/repository/support/CompositePkIntegrationTest.java
index 1b42bd1..b7c69ea 100644
--- a/src/test/java/org/springframework/data/tarantool/repository/support/CompositePkIntegrationTest.java
+++ b/src/test/java/org/springframework/data/tarantool/repository/support/CompositePkIntegrationTest.java
@@ -62,6 +62,7 @@ class CompositePkIntegrationTest extends BaseIntegrationTest {
                 .edition(22)
                 .translator("Ivan Ivanov")
                 .comments("Some translation")
+                .bytesString("Hello".getBytes())
                 .build();
         BookTranslation newTranslation = bookTranslationRepository.save(translation);
         assertThat(newTranslation).isEqualTo(translation);
diff --git a/src/test/resources/cartridge/app/roles/api_storage.lua b/src/test/resources/cartridge/app/roles/api_storage.lua
index cdc7fa6..3f1ad7f 100644
--- a/src/test/resources/cartridge/app/roles/api_storage.lua
+++ b/src/test/resources/cartridge/app/roles/api_storage.lua
@@ -86,6 +86,7 @@ local function init_space()
                     { name = 'edition', type = 'integer' },
                     { name = 'translator', type = 'string' },
                     { name = 'comments', type = 'string', is_nullable = true },
+                    { name = 'bytesString', type = 'string', is_nullable = true }
                 },
                 if_not_exists = true,
             }

Reproducer showed that data is written to tarantool normally, since messagePack binary is processed as a string in a tarantool. But we cannot get them back to java, since messagePack String comes and we are trying to convert it tobyte []

The problem is that byte [] is collection, and the code asks us to return list https://github.com/tarantool/cartridge-springdata/blob/5e06e8f9ff6f5311c3ed7641fb71f40fb36937e5/src/main/java/org/springframework/data/tarantool/core/convert/MappingTarantoolReadConverter.java#L200-L201

The workaround was to use a custom mapper:

MessagePackMapper defaultMapper =
                DefaultMessagePackMapperFactory.getInstance().defaultComplexTypesMapper();
        defaultMapper.registerValueConverter(
                ImmutableStringValueImpl.class, List.class, object -> {
                    final List<Byte> list = new ArrayList<>();
                    for (byte b : object.toString().getBytes()) {
                        list.add(b);
                    }
                    return list;
                });

Also globally the problem may be related to this: https://github.com/tarantool/tarantool/issues/1629

akudiyar commented 3 years ago

This bug must be fixed in the driver, I opened an issue https://github.com/tarantool/cartridge-java/issues/144.

Storing byte arrays in the fields of type string requires a custom string-to-byte-array conversion on the client level using SpringData's custom converters mechanism (see https://github.com/tarantool/cartridge-springdata/blob/d8d1e2b9dfbe9839c50a85b397a8633c4b9f7677/src/main/java/org/springframework/data/tarantool/config/AbstractTarantoolDataConfiguration.java#L220). It is a valid w/a for this case, although creating Strings and then converting them into byte arrays may result in a huge memory overhead on the client.

dkasimovskiy commented 1 year ago

Could be implrmrnted only for Tarantool 3.0