私はAvroを使用しており、GenericRecord
を持っています。そこからclientId
、deviceName
、holder
を抽出したいと思います。 Avroスキーマでは、clientId
は整数、deviceName
は文字列、holder
はマップです。
avroスキーマのclientId
:
{
"name" : "clientId",
"type" : [ "null", "int" ],
"doc" : "hello"
}
avroスキーマのdeviceName
:
{
"name" : "deviceName",
"type" : [ "null", "string" ],
"doc" : "test"
}
avroスキーマのholder
:
{
"name" : "holder",
"type" : {
"type" : "map",
"values" : "string"
}
}
私の質問は、オブジェクトではなく、型付きの値を取得するための推奨される方法は何ですか?
以下のコードでは、payload
はGenericRecord
であり、そこからavroスキーマを取得できます。これは私が今やっていることで、すべてを文字列として抽出します。しかし、どうすれば代わりに型付きの値を取得できますか。方法はありますか?つまり、avroスキーマにあるデータ型が何であれ、それだけを抽出したいと思います。
public static void getData(GenericRecord payload) {
String id = String.valueOf(payload.get("clientId"));
String name = String.valueOf(payload.get("deviceName"));
// not sure how to get maps here
}
したがって、clientId
を整数、deviceName
を文字列、holder
をJava map Map<String, String>
from GenericRecord
?それを行うための最良の方法は何ですか?一般的なレコードとスキーマを指定して、型指定されたすべての変換を実行するユーティリティを作成できますか?
string
の値をUtf8
に、int
をInteger
に、map
をMap<Utf8, Utf8>
にキャストできるはずです。これは、ClassCastException
を発生させずに機能するはずです。
public static void getData(GenericRecord payload) {
int id = (Integer) payload.get("clientId");
String name = payload.get("deviceName").toString(); // calls Utf8.toString
Map<Utf8, Utf8> holder = (Map<Utf8, Utf8>) payload.get("holder");
...
}
一般的に、私はあなたがこれらのキャストを行うことができると信じています:
Integer
、Double
など)string
はUtf8
になりますbytes
はJava.nio.ByteBuffer
になりますarray
はJava.util.Collection
になりますmap
はJava.util.Map<Utf8, [value type]>
になりますこのアプローチを試すことができます。堅牢な実装のために、コードを検討する必要があります スキーマコンパイルを使用した生成
package stackoverflow;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import Java.util.Arrays;
import Java.util.HashMap;
import Java.util.Map;
import org.Apache.avro.AvroTypeException;
import org.Apache.avro.Schema;
import org.Apache.avro.Schema.Field;
import org.Apache.avro.Schema.Type;
import org.Apache.avro.generic.GenericData.Record;
import org.Apache.avro.generic.GenericRecord;
import org.Apache.avro.util.Utf8;
import org.junit.Test;
// Just for demonistration; not robust implementation
public class GenericRecordType {
@Test
public void testName() throws Exception {
Schema schema = buildSchema();
GenericRecord record = new Record(schema);
record.put("clientId", 12);
record.put("deviceName", "GlassScanner");
record.put("holder", new HashMap<>());
Integer value = IntField.clientId.getValue(record);
String deviceName = StringField.deviceName.getValue(record);
Map<String, String> mapString = MapOfStringField.holder.getValue(record);
assertThat(deviceName, is("GlassScanner"));
assertThat(value, is(12));
assertThat(mapString.size(), is(0));
}
private Schema buildSchema() {
Field clientId = new Field("clientId", Schema.create(Type.INT), "hello", (Object) null);
Field deviceName = new Field("deviceName", Schema.create(Type.STRING), "hello", (Object) null);
Field holder = new Field("holder", Schema.createMap(Schema.create(Type.STRING)), null, (Object) null);
Schema schema = Schema.createRecord(Arrays.asList(clientId, deviceName, holder));
return schema;
}
public static interface TypedField<T> {
String name();
public T getValue(GenericRecord record);
}
public static enum StringField implements TypedField<String> {
deviceName;
@Override
public String getValue(GenericRecord record) {
String typed = null;
Object raw = record.get(name());
if (raw != null) {
if (!(raw instanceof String || raw instanceof Utf8)) {
throw new AvroTypeException("string type was epected for field:" + name());
}
typed = raw.toString();
}
return typed;
}
}
public static enum IntField implements TypedField<Integer> {
clientId;
private IntField() {
}
@Override
public Integer getValue(GenericRecord record) {
Integer typed = null;
Object raw = record.get(name());
if (raw != null) {
if (!(raw instanceof Integer)) {
throw new AvroTypeException("int type was epected for field:" + name());
}
typed = (Integer) raw;
}
return typed;
}
}
public static enum MapOfStringField implements TypedField<Map<String, String>> {
holder;
@Override
@SuppressWarnings("unchecked")
public Map<String, String> getValue(GenericRecord record) {
Map<String, String> typed = null;
Object raw = record.get(name());
if (raw != null) {
if (!(raw instanceof Map)) {
throw new AvroTypeException("map type was epected for field:" + name());
}
typed = (Map<String, String>) raw;
}
return typed;
}
}
}