Calling parseFrom() method for generic protobuffer class in java

时光怂恿深爱的人放手 提交于 2019-12-04 03:44:35

Every generated protobuf type contains a static member called PARSER which is an implementation of the com.google.protobuf.Parser<T> interface. Your getObject method simply needs to take a Parser<T> as a parameter. So then you'd call it like:

Foo foo = getObject(Foo.PARSER);

If you want to do this for T, it's easier and more natural to pass the Class<T> (i.e. the class of the Proto type) into the constructor of your class, and then obtain the Parser from that like this:

public class Thing<T extends Message> {
    final Parser<T> parser;

    Thing(Class<T> cls) {
        parser = (Parser<T>) cls.getMethod("parser").invoke(null);
    }

    T deserialize(byte[] bytes) {
        parser.parseFrom(bytes);  // try/catch etc
    }
}

To expand on Kenton Varda's answer:

First I'd refactor your method into separate methods for getting the input stream and parsing it. Only the latter has any reason to be generic.

public InputStream getInputStream() {
  // get it
}

Now you intend to parse the input stream and build a POJO from the protobuf. It's reasonable IMO to expect that at this point your code must be aware of what type of object you're going to get, because otherwise how would you do something intelligent with it next? E.g.

InputStream is = getInputStream();
Object o = parseGenericInputStream(is);
doSomethingWithParsedObject(o); // how to do this if you don't know o's type?

You reasonably must know o's type once you've parsed it (and therefore before you parse it), otherwise you can't do anything meaningful with it that I can think of.

So... again with credit to Kenton Varda:

public void doStuff() {
  ...
  InputStream is = getInputStream();
  MyProtobufClass pojo = parseGenericInputStream(MyProtobufClass.PARSER, is);
  doSomethingWithParsedObject(pojo);
  ...
}

private <T> T parseGenericInputStream(Parser<T> parser, InputStream inputStream)
    throws InvalidProtocolBufferException {
  return parser.parseFrom(inputStream);
}

At this point though you're writing a generic method for one line of code, which is kind of not worth it if you ask me.

No, there is not; you cannot deserialize a proto without knowing its type.

If you do know its type, then you can pass in a Builder for its type, however.

(Additionally, you can't call static methods on a type variable like T.)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!