如何在java中将协议缓冲区消息转换为HashMap?

tuk*_*tuk 5 java protocol-buffers java-8

我有一个形式的 protobuf 消息

enum PolicyValidationType {
    Number = 0;
}


message NumberPolicyValidation {
    optional int64 maxValue = 1;
    optional int64 minValue = 2;
}

message PolicyObject {
    required string key = 1;
    optional string value = 2;
    optional string name = 3;
    optional PolicyValidationType validationType = 4;
    optional NumberPolicyValidation numberPolicyValidation = 5;
}
Run Code Online (Sandbox Code Playgroud)

例如

policyObject {
      key: "sessionIdleTimeoutInSecs"
      value: "1800"
      name: "Session Idle Timeout"
      validationType: Number
      numberPolicyValidation {
        maxValue: 3600
        minValue: 5
      }
}
Run Code Online (Sandbox Code Playgroud)

有人可以让我知道如何将其转换为Map如下所示:-

{validationType=Number, name=Session Idle Timeout, numberPolicyValidation={maxValue=3600.0, minValue=5.0}, value=1800, key=sessionIdleTimeoutInSecs}
Run Code Online (Sandbox Code Playgroud)

我能想到的一种方法是将其转换为 json,然后将 json 转换为映射?

PolicyObject policyObject;
...
JsonFormat jsonFormat = new JsonFormat();
final String s = jsonFormat.printToString(policyObject);
Type objectMapType = new TypeToken<HashMap<String, Object>>() {}.getType();
Gson gson = new GsonBuilder().registerTypeAdapter(new TypeToken<HashMap<String,Object>>(){}.getType(), new PrimitiveDeserializer()).create();
Map<String, Object> mappedObject = gson.fromJson(s, objectMapType);
Run Code Online (Sandbox Code Playgroud)

我想一定有更好的方法。有人可以提出更好的方法吗?

小智 8

我创建了小的专用类来将任何 Google 协议缓冲区消息一般转换为 Java Map。

public class ProtoUtil {

@NotNull
public Map<String, Object> protoToMap(Message proto) {
    final Map<Descriptors.FieldDescriptor, Object> allFields = proto.getAllFields();
    Map<String, Object> map = new LinkedHashMap<>();
    for (Map.Entry<Descriptors.FieldDescriptor, Object> entry : allFields.entrySet()) {
        final Descriptors.FieldDescriptor fieldDescriptor = entry.getKey();
        final Object requestVal = entry.getValue();
        final Object mapVal = convertVal(proto, fieldDescriptor, requestVal);
        if (mapVal != null) {
            final String fieldName = fieldDescriptor.getName();
            map.put(fieldName, mapVal);
        }
    }
    return map;
}


@Nullable
/*package*/ Object convertVal(@NotNull Message proto, @NotNull Descriptors.FieldDescriptor fieldDescriptor, @Nullable Object protoVal) {
    Object result = null;
    if (protoVal != null) {
        if (fieldDescriptor.isRepeated()) {
            if (proto.getRepeatedFieldCount(fieldDescriptor) > 0) {
                final List originals = (List) protoVal;
                final List copies = new ArrayList(originals.size());
                for (Object original : originals) {
                    copies.add(convertAtomicVal(fieldDescriptor, original));
                }
                result = copies;
            }
        } else {
            result = convertAtomicVal(fieldDescriptor, protoVal);
        }
    }
    return result;
}


@Nullable
/*package*/ Object convertAtomicVal(@NotNull Descriptors.FieldDescriptor fieldDescriptor, @Nullable Object protoVal) {
    Object result = null;
    if (protoVal != null) {
        switch (fieldDescriptor.getJavaType()) {
            case INT:
            case LONG:
            case FLOAT:
            case DOUBLE:
            case BOOLEAN:
            case STRING:
                result = protoVal;
                break;
            case BYTE_STRING:
            case ENUM:
                result = protoVal.toString();
                break;
            case MESSAGE:
                result = protoToMap((Message) protoVal);
                break;
        }
    }
    return result;
}


}
Run Code Online (Sandbox Code Playgroud)

希望有帮助!分享和享受。