在java中为泛型protobuffer类调用parseFrom()方法

在java中为泛型protobuffer类调用parseFrom()方法,java,generics,protocol-buffers,Java,Generics,Protocol Buffers,我正在调用一个api来获取输入流,然后调用静态方法parseFrom(inputstream)将其转换为protobuffclass 如果我使用特定的类进行此操作,它将起作用: public CustomerDTOOuterClass.CustomerDTO GetCustomer() { CustomerDTOOuterClass.CustomerDTO customer = null; try { URL url = new URL("https://

我正在调用一个api来获取输入流,然后调用静态方法parseFrom(inputstream)将其转换为protobuffclass

如果我使用特定的类进行此操作,它将起作用:

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;
}
但是如果我将其更改为泛型类型,它会失败,因为T没有parseFrom方法,那么是否有任何接口可以在T中实现,以便调用parseFrom方法

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;
}
这是我得到的错误:
错误:(68,27)错误:找不到符号方法parseFrom(InputStream)

否,没有;如果不知道proto的类型,则无法反序列化它

但是,如果您确实知道其类型,则可以为其类型传入生成器


(此外,不能对类型变量(如
t
)调用静态方法)

每个生成的protobuf类型都包含一个名为
PARSER
的静态成员,它是接口的实现。您的
getObject
方法只需要将
解析器
作为参数。那么你可以这样称呼它:

Foo foo = getObject(Foo.PARSER);

要扩展Kenton Varda的答案:

首先,我要将您的方法重构为不同的方法,以获取输入流并对其进行解析。只有后者才有理由成为泛型

public InputStream getInputStream() {
  // get it
}
现在您打算解析输入流并从protobuf构建一个POJO。依我看,在这一点上,您的代码必须知道您将得到什么类型的对象是合理的,因为否则您接下来将如何使用它来做一些智能化的事情?例如

InputStream is = getInputStream();
Object o = parseGenericInputStream(is);
doSomethingWithParsedObject(o); // how to do this if you don't know o's type?
一旦解析了
o
,您就必须知道它的类型(因此在解析它之前),否则您就不能用它做任何我能想到的有意义的事情

所以。。。再次感谢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);
}
public void doStuff(){
...
InputStream=getInputStream();
MyProtobufClass pojo=parseGenericInputStream(MyProtobufClass.PARSER,is);
doSomethingWithParsedObject(pojo);
...
}
私有T parseGenericInputStream(解析器解析器,InputStream InputStream)
抛出无效的ProtocolBufferException{
返回parser.parseFrom(inputStream);
}

在这一点上,尽管您正在为一行代码编写一个通用方法,但如果您问我,这是不值得的。

如果您想为
T
这样做,将
类(即原型的类)传递到类的构造函数中会更容易、更自然,然后从中获得
解析器
,如下所示:

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
    }
}
公共类的东西{
最终解析器;
事物(类别cls){
parser=(parser)cls.getMethod(“parser”).invoke(null);
}
T反序列化(字节[]字节){
parser.parseFrom(字节);//try/catch等
}
}

快速搜索可以找到两件事,也许其中一件有帮助:你能告诉我们你想要实现什么吗。如果您的处理非常通用,您可以查看DynamicMessage。或者,您可以将生成器类传递给getObject()方法,并使用生成器类的mergeFrom方法。您真的不能这样做吗?序列化的protos不知道它们自己的类型。回答得好,我对它的结果很感兴趣,所以我对它进行了一些修改,并在一个单独的答案中进行了扩展,希望你不介意!