繁体   English   中英

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

[英]Calling parseFrom() method for generic protobuffer class in java

我正在调用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)

每个生成的protobuf类型都包含一个名为PARSER的静态成员,它是com.google.protobuf.Parser<T>接口的一个实现。 您的getObject方法只需要将Parser<T>作为参数。 所以你会称之为:

Foo foo = getObject(Foo.PARSER);

如果你想为T做这个,那么将Class<T> (即Proto类的类)传递给你的类的构造函数会更容易,更自然,然后从中获取Parser

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

扩展Kenton Varda的答案:

首先,我将您的方法重构为单独的方法,以获取输入流并解析它。 只有后者有任何理由是通用的。

public InputStream getInputStream() {
  // get it
}

现在,您打算解析输入流并从protobuf构建POJO。 IMO理所当然地希望在这一点上你的代码必须知道你将要获得什么类型的对象,否则你将如何使用它来做一些聪明的事情呢? 例如

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

此时虽然您正在为一行代码编写通用方法,但如果您问我,这种方法是不值得的。

不,那里没有; 你不能在不知道它的类型的情况下反序列化原型。

如果您确实知道它的类型,那么您可以为其类型传入Builder。

(另外,你不能在像T这样的类型变量上调用静态方法。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM