Java中的通用protobuf解串器

maj*_*aja 6 java generics protocol-buffers proto3

我正在尝试编写一个通用的Java类,该类可用于反序列化/解析任何protobuf消息。

以下是代码在理想环境中的外观:

public abstract class ProtoDeserializer<T extends Message> {

    public T deserialize(final byte[] bytes) throws Exception {     
        Parser<T> parser = T.getParserForType(); // Syntax Error: this method is not static!

        T message = parser.parseFrom(bytes);
        validate(message);
        return message;
    }

    public abstract void validate(final T message) throws Exception;
}
Run Code Online (Sandbox Code Playgroud)

但是,我无法获得通用protobuf消息的正确解析器。实现此类泛型类的正确方法是什么?

Jor*_*nee 6

最简单的方法是将解析器作为参数传递给构造函数:

public abstract class ProtoDeserializer<T extends Message> {

    private final Parser<T> parser;

    public ProtoDeserializer(Parser<T> parser) {
        this.parser = parser;
    }

    public T deserialize(final byte[] bytes) throws Exception {    
        T message = parser.parseFrom(bytes);
        validate(message);
        return message;
    }

    public abstract void validate(final T message) throws Exception;
}
Run Code Online (Sandbox Code Playgroud)

通过解析器是我当前的解决方法。但是最好避免使用它,因为它是多余的信息。

这对您可能是多余的,但对编译器/运行时却不是多余的。

如果您认为可以创建类的原始实现:

ProtoDeserializer proto = new ProtoDeserializer() {
    ...
};
Run Code Online (Sandbox Code Playgroud)

该类型T必须来自某个地方

这只是已删除的泛型的事实。如果需要通用参数的类型信息,则必须手动提供它。


另一个黑客可以尝试是从一个执行子类得到具体的类型参数:

private final Parser<T> parser; 

public ProtoDeserializer() {
    Class<?> subclass = this.getClass();

    try {
        ParameterizedType pType = (ParameterizedType) subclass.getGenericSuperclass();
        Class<T> tClass = (Class<T>) pType.getActualTypeArguments()[0];
        // In the case where the constructor for `T` takes no arguments.
        parser = tClass.newInstance().getParserForType();
    } catch(Throwable t) {
        throw new RuntimeException("Subclass not compatible", t);
    }
}
Run Code Online (Sandbox Code Playgroud)

只要子类直接ProtoDeserializer使用具体的类型实参实现,此方法就可以工作。即:

class MyDeserializer extends ProtoDeserializer<MyMessage> {...}
Run Code Online (Sandbox Code Playgroud)