Рекурсивная схема с авро (SchemaBuilder) - PullRequest
0 голосов
/ 20 июня 2019

Возможно ли создать авро-схему, которая будет рекурсивной, например

Schema schema = SchemaBuilder
    .record("RecursiveItem")
    .namespace("com.example")
    .fields()
    .name("subItem")
    .type("RecursiveItem")
    .withDefault(null) // not sure about that too...
    .endRecord();

Я получаю StackOverflowError при его использовании так:

static class RecursiveItem {
  RecursiveItem subItem;
}

RecursiveItem item1 = new RecursiveItem();
RecursiveItem item2 = new RecursiveItem();
item1.subItem = item2;

final DatumWriter<RecursiveItem> writer = new SpecificDatumWriter<>(schema);

// note: I actually want a binary output, but I started with some json code I found
ByteArrayOutputStream stream = new ByteArrayOutputStream();
final JsonEncoder encoder = EncoderFactory.get().jsonEncoder(schema, stream);
writer.write(rec1, encoder);
String json = stream.toString();

Примечание: я также получаю StackOverflowError, если я создаю схему, используя:

Schema schema = ReflectData.get().getSchema(RecursiveItem.class);

1 Ответ

0 голосов
/ 20 июня 2019

Предупреждение: я нашел решение для записи, но не могу прочитать его: - \

Я не уверен, что действительно понимаю, но мне удается заставить его работать с:

  1. ReflectDatumWriter следует использовать вместо SpecificDatumWriter

  2. У меня все еще была проблема со схемой, не найденной из-за автоматического поиска схемы при кодировании. Он ищет схему с пространством имен + имя, полученным автоматически. И в моем случае, когда класс является статическим подклассом, следует использовать следующее:

    String cls = RecursiveItem.class.getSimpleName();
    String pck = RecursiveItem.class.getPackage().getName();
    if (RecursiveItem.class.getEnclosingClass() != null) // nested class
      pck = RecursiveItem.class.getEnclosingClass().getName() + "$";
    
  3. Для управления нулем следует использовать следующую схему

    Schema schema0 = SchemaBuilder
      .record(cls)
      .namespace(pck)
      .fields()
      .name("subItem")
      .type().unionOf().nullType().and().type("RecursiveItem").endUnion()
      .nullDefault()
      .endRecord();
    
...