我正在与Avro合作,我有GenericRecord
。我想从中提取clientId
,deviceName
,holder
。在Avro架构中,clientId
为整数,deviceName
为字符串,holder
为地图。
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"
}
}
我的问题是 - 检索键入值的推荐方法是什么,而不是Object?
在下面的代码中,payload
是GenericRecord
,我们可以从中获取avro架构。这就是我现在正在做的事情,将所有内容都作为String提取。但是我怎样才能获得输入值。有什么办法吗?我的意思是无论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
为字符串,Map<String, String>
为Java地图GenericRecord
?最好的方法是什么?我们可以编写任何执行所有类型转换的实用程序给出通用记录和模式吗?
答案 0 :(得分:3)
您应该能够将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]>
答案 1 :(得分:1)
您可以尝试这种方法。为了实现强大的实施,您应该考虑代码generation using schema compilation.
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;
}
}
}