Call parseFrom () method for generic protobuffer class in java

I call api to get the input stream, and then call the static parseFrom method (input stream) to convert it to the protobuff class.

If I do this with a specific class, it works:

public CustomerDTOOuterClass.CustomerDTO GetCustomer() { CustomerDTOOuterClass.CustomerDTO customer = null; try { URL url = new URL("https://localhost:44302/Api/customer/1?"); HttpsURLConnection conn = (HttpsURLConnection)url.openConnection(); conn.setRequestMethod("GET"); conn.setRequestProperty("Content-Type", "application/x-protobuf"); conn.connect(); InputStream is = conn.getInputStream(); CustomerDTOOuterClass.CustomerDTO customer = CustomerDTOOuterClass.CustomerDTO.parseFrom(is); conn.disconnect(); } catch(Exception ex) { System.out.println("[ "+ex.getMessage()+" ]"); } return customer; } 

but if I change it to a generic type, it fails because T does not have a parseFrom method, is there any interface that I could implement in T so that I can call the parseFrom method?

 public T GetObject() { T object = null; try { URL url = new URL("https://localhost:44302/Api/customer/1?"); HttpsURLConnection conn = (HttpsURLConnection)url.openConnection(); conn.setRequestMethod("GET"); conn.setRequestProperty("Content-Type", "application/x-protobuf"); conn.connect(); InputStream is = conn.getInputStream(); T object = T.parseFrom(is); conn.disconnect(); } catch(Exception ex) { System.out.println("[ "+ex.getMessage()+" ]"); } return object; } 

this is the error i get: Error: (68, 27) error: cannot find parseFrom character method (InputStream)

+6
source share
4 answers

Each child type protobuf contains a static member named PARSER , which is an implementation of the com.google.protobuf.Parser<T> interface. Your getObject method just needs to take Parser<T> as a parameter. So you would call it that:

 Foo foo = getObject(Foo.PARSER); 
+7
source

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

 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 } } 
+3
source

No no; you cannot deserialize a proto without knowing its type.

If you know its type, you can pass it to your Builder for your type.

(In addition, you cannot call static methods on a variable of type type T )

+1
source

To expand Kenton Varda's answer:

First, I would reorganize your method into separate methods to get the input stream and parse it. Only the latter has reason to be generic.

 public InputStream getInputStream() { // get it } 

Now you intend to parse the input stream and build the POJO from protobuf. Of course, IMO expects that at this moment your code should know what type of object you are going to receive, because otherwise how would you do something clever with it further? For instance.

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

You should reasonably know the type o after you have taken it apart (and therefore before analyzing it), otherwise you cannot do anything with it that I can think of.

So ... again with thanks to Kenton Warde:

 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, although you are writing a general method for a single line of code, that is not worth it if you ask me.

+1
source

Source: https://habr.com/ru/post/980135/


All Articles