Как установить массив записей с помощью GenericRecordBuilder

Я пытаюсь превратить объект Scala (т.е. класс case) в массив байтов.

Для этого я вставляю содержимое объекта в GenericRecordBuilder, используя его конкретную схему, и в конечном итоге с помощью GenericDatumWriter превращаю его в массив байтов.

У меня нет проблем с установкой примитивных типов и массива примитивных типов в GenericRecordBuilder.

Но мне нужна помощь с вставкой массива записей в GenericRecordBuilder и созданием из него массива байтов.

Как правильно вставить массив записей в GenericRecordBuilder?

Вот часть того, что я пытаюсь сделать:

Это схема:

{
    "type": "record",
    "name": "test1",
    "namespace": "ns",
    "fields": [
      {
        "name": "t_name",
        "type": "string",
        "default": "a"
      },
      {
        "name": "t_num",
        "type": "int",
        "default": 0
      },
      {"name" : "t_arr", "type":
        ["null",
         {"type": "array", "items": {
              "name": "t_arr_a",
              "type": "record",
              "fields": [
                {
                  "name": "t_arr_f1",
                  "type": "int",
                  "default": 0
                },
                {
                  "name": "t_arr_f2",
                  "type": "int",
                  "default": 0
                }
              ]
            }
            }
         ]
       }
    ]
}

Это класс Scala, который заполняет GenericRecordBuilder и преобразует его в массив байтов:

package utils

import java.io.ByteArrayOutputStream

import org.apache.avro.{Schema, generic}
import org.apache.avro.generic.{GenericData, GenericDatumWriter}
import org.apache.avro.io.EncoderFactory
import org.apache.avro.generic.GenericRecordBuilder

object CheckRecBuilder extends App {

  val avroSchema: Schema = new Schema.Parser().parse(this.getClass.getResourceAsStream("/data/myschema.avsc"))
  val recordBuilder = new GenericRecordBuilder(avroSchema)

  recordBuilder.set("t_name", "X")
  recordBuilder.set("t_num", 100)


  recordBuilder.set("t_arr", ???)

  val record = recordBuilder.build()


  val w = new GenericDatumWriter[GenericData.Record](avroSchema)
  val outputStream = new ByteArrayOutputStream()
  val e = EncoderFactory.get.binaryEncoder(outputStream, null)
  w.write(record, e)
  val barr =  outputStream.toByteArray

  println("End")

}

person Nir    schedule 27.05.2019    source источник


Ответы (1)


Мне удалось установить массив объектов.

Интересно, есть ли лучший или правильный способ сделать это.

Вот что я сделал:

  1. Создал класс случая:

case class t_arr_a(t_arr_f1:Int, t_arr_f2:Int)

  1. Создан метод, который преобразует класс case в GenericData.Record:

def caseClassToGenericDataRecord(cc:Product, schema:Schema): GenericData.Record = { val childRecord = new GenericData.Record(schema.getElementType)
val values = cc.productIterator cc.getClass.getDeclaredFields.map(f => childRecord.put(f.getName, values.next )) childRecord }

  1. Обновлен класс CheckRecBuilder выше:

заменены:

recordBuilder.set("t_arr", ???)

С:

  val childSchema = new GenericData.Record(avroSchema2).getSchema.getField("t_arr").schema().getTypes().get(1)
  val tArray = Array(t_arr_a(2,4), t_arr_a(25,14))
  val tArrayGRecords: util.List[GenericData.Record] 
    = Some(yy.map(x => caseClassToGenericDataRecord(x,childSchema))).map(arr => java.util.Arrays.asList(arr: _*)).orNull

  recordBuilder.set("t_arr", tArrayGRecords)
person Nir    schedule 27.05.2019