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

时间:2014-12-24 20:46:35

标签: java generics protocol-buffers

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

4 个答案:

答案 0 :(得分:11)

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

Foo foo = getObject(Foo.PARSER);

答案 1 :(得分:4)

如果你想为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
    }
}

答案 2 :(得分:1)

扩展Kenton Varda的答案:

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

public InputStream getInputStream() {
  // get it
}

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

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

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

答案 3 :(得分:0)

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

如果你知道它的类型,那么你可以传入一个类型的构建器。

(此外,您无法在T等类型变量上调用静态方法。)