【发布时间】:2017-05-09 11:51:34
【问题描述】:
我正在使用 Avro,我正在尝试以通用方式从中提取几个字段。我有一个来自 avro 的 GenericRecord 对象,我想从中提取一些字段。
下面是做所有事情的方法:
public static Object extract(GenericRecord genericRecord, String fieldName) {
Object result = new Object();
for (Field field : genericRecord.getSchema().getFields()) {
if (field.name().equalsIgnoreCase(fieldName))
return fromAvro(genericRecord.get(field.name()), field.schema());
}
return result;
}
private static Object fromAvro(Object obj, Schema schema) {
if (obj == null)
return null;
switch (schema.getType()) {
case UNION:
return fromAvroUnion(obj, schema);
case ARRAY:
return fromAvroArray(obj, schema);
case STRING:
if (obj.equals("null") || obj.toString().equals("null"))
return null;
else
return obj.toString();
case MAP:
return fromAvroMap(obj, schema);
case NULL:
return obj;
case BOOLEAN:
return Boolean.valueOf(obj.toString());
case DOUBLE:
return Double.valueOf(obj.toString());
case FLOAT:
return Float.valueOf(obj.toString());
case INT:
return Integer.valueOf(obj.toString());
case LONG:
return Long.valueOf(obj.toString());
}
}
private static Object fromAvroArray(Object obj, Schema schema) {
List<Object> array = new ArrayList<Object>();
for (Object element : (GenericData.Array) obj) {
array.add(fromAvro(element, schema.getElementType()));
}
return array;
}
private static Object fromAvroMap(Object obj, Schema schema) {
Map<String, Object> convertedMap = new HashMap<>();
// CharSequence because the string can be configured as either Utf8 or String.
for (Entry<CharSequence, Object> e : ((Map<CharSequence, Object>) obj).entrySet()) {
convertedMap.put(e.getKey().toString(), fromAvro(e.getValue(), schema.getValueType()));
}
return convertedMap;
}
private static Object fromAvroUnion(Object obj, Schema schema) {
List<Schema> types = schema.getTypes();
if (types.size() < 1) {
throw new AvroRuntimeException("Union has no types");
}
if (types.size() == 1) {
return fromAvro(obj, types.get(0));
} else if (types.size() > 2) {
throw new AvroRuntimeException(
"Unions may only consist of a concrete type and null in cascading.avro");
} else if (!types.get(0).getType().equals(Type.NULL)
&& !types.get(1).getType().equals(Type.NULL)) {
throw new AvroRuntimeException(
"Unions may only consist of a concrete type and null in cascading.avro");
} else {
Integer concreteIndex = (types.get(0).getType() == Type.NULL) ? 1 : 0;
return fromAvro(obj, types.get(concreteIndex));
}
}
以下是我如何使用上述extract 方法从GenericRecord 对象中提取单个字段。现在我只是在提取 String Integer 数据类型字段,但我可能还需要提取其他数据类型字段。
现在我的问题是。有什么方法可以避免强制转换,因为现在我在从中提取字段的同时强制转换每种数据类型。我认为只要有演员表,就必须有更好的方法来做可以避免演员表的事情。
Map<String, String> payload = (Map<String, String>) extract(genericRecord, "payload");
String clientId = (String) extract(genericRecord, "clientId");
Integer deviceId = (Integer) extract(genericRecord, "deviceId");
【问题讨论】:
-
为什么不使用
SpecificRecord?
标签: java casting type-conversion avro