当前位置: 首页 > 知识库问答 >
问题:

如何从GenericRecord获取类型化值?

王兴庆
2023-03-14

我正在与Avro合作,我有一个通用记录。我想从中提取clientId、deviceName、holder。在Avro模式中,clientId是整数,deviceName是字符串,holder是映射。

avro模式中的clientId

{
    "name" : "clientId",
    "type" : [ "null", "int" ],
    "doc" : "hello"
}

avro架构中的设备名称:

{
    "name" : "deviceName",
    "type" : [ "null", "string" ],
    "doc" : "test"
}

avro模式中的持有人:

{
    "name" : "holder",
    "type" : {
      "type" : "map",
      "values" : "string"
    }
}

我的问题是-检索类型化值的推荐方法是什么,而不是对象?

在下面的代码中,有效负载是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作为字符串和持有者作为JavamapMap


共有2个答案

尉迟正平
2023-03-14

您可以尝试这种方法。对于健壮的实现,您应该考虑使用模式编译生成代码。

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;
        }
    }

}
施鸿
2023-03-14

您应该能够将您的string值转换为Utf8int转换为整数,以及mapMap

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");

    ...
}

总的来说,我相信你可以做这些演员:

  • 原语成为其装箱版本(整数、双精度等)
  • 字符串变为Utf8
  • 字节变为java。nio。ByteBuffer
  • 数组变为java。util。集合
  • 映射成为java。util。地图
 类似资料:
  • 给定GenericRecord,与对象相比,检索类型化值的推荐方法是什么?我们需要强制转换值吗?如果需要,从Avro类型到Java类型的映射是什么?例如,Avro数组==Java集合;和Avro String==Java UTF8。 由于每个GenericRecord都包含它的模式,所以我希望有一种类型安全的方法来检索值。

  • 问题内容: 给定GenericRecord,与对象相比,推荐的检索类型化值的方法是什么?我们是否应该强制转换值,如果是这样,从Avro类型到Java类型的映射是什么?例如,Avro Array == Java Collection ; 和Avro String == Java Utf8 。 由于每个GenericRecord都包含其架构,因此我希望找到一种类型安全的方法来检索值。 问题答案: 阿夫

  • 问题内容: 通常,我见过人们像这样使用类文字: 但是,如果类型是通用类型,例如List,该怎么办?这可以正常工作,但由于应将List参数化,因此发出警告: 那么为什么不添加一个<?>呢?好吧,这会导致类型不匹配错误: 我想像这样的事情会起作用,但这只是一个普通的语法错误: 如何获得Class >静态信息,例如使用类文字? 我可以使用,以摆脱在第一个例子中所造成的非参数使用列表,警告的,但我宁愿不要

  • 问题:我想知道是否可以从DocumentFilter获取JTextfield类型 我读过java文档,搜索了很多,但没有找到任何信息。 需要:我在两个JTextfields上设置了相同的DocumentFilter。当事件发生时,在DocumentFilter的“replace”方法中,我想知道哪个textfield导致了事件。 用例:我有大约15个文本字段(未来可能会增加),我希望对所有这些字段

  • 问题内容: 我使用PDO和MySQL,出于某种原因,当从数据库中获取int类型的值时,PDOStatement返回的是数字的字符串表示形式,而不是数字类型的值。如何防止这种情况发生? 我注意到有一个PDO类的属性:应该可以解决这个问题,但是在尝试修改它时,它抛出一个错误,指出该属性对MySQL驱动程序无效。 查询数据库时,获取字符串而不是数字是否正常? 问题答案: 我不认为可以在PHP 5.2中完

  • 问题内容: 该问题的可接受答案描述了如何在类中创建的实例。这涉及将参数传递给构造函数并从中调用方法。 然后创建的新实例,并传递参数。 如果新类的泛型类型参数不是某个已知类,但它本身是泛型类型参数,该怎么办?假设我还有其他班级,我想从该班级内部创建一个新实例。然后,如果尝试传递,则会收到以下编译器错误: 有没有办法解决? 对我来说触发错误的代码是: 发生错误,是因为我不会写。还有其他传递相同信息的方