Я хочу использовать Apache Avro для сериализации моих данных, мой клиент написан на C ++, а мой сервер написан на Java.
Мой серверный Java-код выглядит так:
Schema scm = new Schema.Parser().parse("....shcema String.....");
ByteArrayInputStream inputStream = new ByteArrayInputStream(record.array());
Decoder coder = new DecoderFactory().directBinaryDecoder(inputStream, null);
GenericDatumReader<GenericRecord> reDatumReader = new GenericDatumReader<GenericRecord>(scm);
try {
GenericRecord result = (GenericRecord)reDatumReader.read(null, coder);
//here! the result "name", "num_groups" is empty!
System.out.println(result.get("name")+" "+result.get("num_groups"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
И мой код клиента:
std::string schemaDescript ="....shcema String.....";
std::stringstream rsStream(schemaDescript);
avro::ValidSchema rSchema;
avro::compileJsonSchema(rsStream, rSchema);
avro::EncoderPtr encoder = avro::binaryEncoder();
std::auto_ptr<avro::OutputStream> oStream = avro::memoryOutputStream();
encoder->init(*oStream);
avro::GenericDatum rData(rSchema);
avro::GenericRecord sReord = rData.value<avro::GenericRecord>();
sReord.setFieldAt(0, avro::GenericDatum("i am nice"));
sReord.setFieldAt(1, avro::GenericDatum(1));
sReord.setFieldAt(2, avro::GenericDatum(12));
sReord.setFieldAt(3, avro::GenericDatum(13));
avro::GenericWriter gwriter(rSchema, encoder);
gwriter.write(rData);
oStream->flush();
std::auto_ptr<avro::InputStream> inSt = avro::memoryInputStream(*oStream);
avro::StreamReader instReader(*inSt);
size_t outputLen = oStream->byteCount();
uint8_t* theByteData = new uint8_t[outputLen];
instReader.hasMore();
instReader.readBytes(theByteData, outputLen);
Я отправляю theByteData
на сервер, код работает (без исключения), но результат пуст, может кто-нибудь сказать мне, что не так?
И почему в Java мы получаем значение с ключом: result.get("name")
; но в C ++ мы получаем значение с индексом: record.fieldAt(0).value<string>()
, Если я не могу получить значение с помощью строкового ключа, как сопоставить индекс с строковым ключом?
У меня была та же проблема этим утром, и я нашел решение в файле Cpp Avro Test («DataFileTests.cc») с функцией «testWriteGeneric».
Например:
Файл моей схемы (cpx.json):
{
"type": "record",
"name": "cpx",
"fields" : [
{"name": "re", "type": "double"},
{"name": "im", "type" : "int"}
]
}
Мой Cpp файл:
typedef std::pair<avro::ValidSchema, avro::GenericDatum> Pair;
int main(int ac, char **av)
{
// encode
std::ifstream ifs(cpx.json);
avro::ValidSchema schema;
avro::compileJsonSchema(ifs, schema);
// I create a pair of validSchema and GenericDatum
Pair p(schema, avro::GenericDatum());
avro::GenericDatum &Data = p.second;
Data = avro::GenericDatum(schema);
avro::GenericRecord &sReord = Data.value<avro::GenericRecord>();
// I set my values
sReord.setFieldAt(sReord.fieldIndex("re"), avro::GenericDatum(42.5));
sReord.setFieldAt(sReord.fieldIndex("im"), avro::GenericDatum(24));// I create a DataFileWriter and i write my pair of ValidSchema and GenericValue
avro::DataFileWriter<Pair> dataFileWriter("test.bin", schema);
dataFileWriter.write(p);
dataFileWriter.close();
}
В следующих утверждениях есть 2 проблемы с клиентским кодом
avro::GenericRecord sReord = rData.value<avro::GenericRecord>();
sReord.setFieldAt(0, avro::GenericDatum("i am nice"));
Второе утверждение приведет к вызову avro::GenericDatum(bool)
и не GenericDatum(const std::string&)
как предполагалось.
Из-за этого строковое поле остается пустым и, следовательно, когда вы попытаетесь его прочитать, будет возвращена пустая строка. Таким образом, замена вышеуказанного утверждения на следующее должно работать
std::string s("i am nice");
sReord.setFieldAt(0, avro::GenericDatum(s));
В первом утверждении sRecord должен быть объявлен как ссылка, поскольку это то, что возвращается функцией rData.value (). Не принимая в качестве ссылки, просто заменяет его новой копией, и поэтому любое значение, записанное в нем, на самом деле не записывается в основной поток. Так и должно быть
avro::GenericRecord& sReord = rData.value<avro::GenericRecord>();
Кроме того, вам не нужен GenericWriter и вы можете писать, используя сам объект Encoder как
avro::encode(*encoder, rData);