Тип карты Protobuf Формат JSON использует строковый литеральный ключ и значение, а не фактические значения

Я пытаюсь преобразовать объект protobuf в формат JSON, используя com.googlecode.protobuf.format.JsonFormat, но тип map получился неожиданным.

Мое сообщение такое

message Response {
   repeated Candidate candidates = 1;
   map<string, ErrorMessage> errors = 2;
}

message ErrorMessage {
   string message = 0;
   ErrorType type = 1;
}

enum ErrorType {
   ERROR = 0;
   WARNING = 1;
}

Проблема заключается в формате JSON объекта Response, который я создал.

Response response = ...
Return new ResponseEntity<>(new JsonFormat().printToString(response), HttpStatus.OK);

Я ожидаю, что ошибки будут отформатированы как карта с ключом строкового значения (ключа карты)

...
"errors": {
  "someID" : {
      "message": "blah blah",
      "type": "ERROR"
  }
}

Однако фактический вывод (я оценил только часть new JsonFormat().printToString(response) в intellij)

...
"errors": {
  "key": "someID",
  "value": {
      "message": "blah blah",
      "type": "ERROR"
  }
}

Я надеюсь, что это какая-то небольшая конфигурация, которую я пропустил, чтобы protobuf (или Джексон?) знал фактическое значение ключа? не используя «ключ» и «значение».

Кстати, какой смысл иметь буквальное поле «ключ» и «значение» в типе map? Вы не можете выполнять поиск составляющих с ним, и вы можете просто использовать пользовательский тип/объект.


person CrazyGreenHand    schedule 16.11.2018    source источник


Ответы (1)


Этот код отлично работает для меня:

test.proto

syntax = "proto2";
package by.dev.madhead;
option java_outer_classname = "SO";

message Candidate {

}

enum ErrorType {
    ERROR = 0;
    WARNING = 1;
}

message ErrorMessage {
    required string message = 1;
    required ErrorType type = 2;
}

message Response {
    repeated Candidate candidates = 1;
    map<string, ErrorMessage> errors = 2;
}

App.java

public class App {
    public static void main(String[] args) throws InvalidProtocolBufferException {
        SO.Response response = SO.Response.newBuilder()
            .addCandidates(SO.Candidate.newBuilder().build())
            .addCandidates(SO.Candidate.newBuilder().build())
            .addCandidates(SO.Candidate.newBuilder().build())
            .putErrors("error1", SO.ErrorMessage.newBuilder().setMessage("error1").setType(SO.ErrorType.ERROR).build())
            .putErrors("error2", SO.ErrorMessage.newBuilder().setMessage("error2").setType(SO.ErrorType.WARNING).build())
            .build();

        System.out.println(JsonFormat.printer().print(response));
    }
}

Результат:

{
    "candidates": [{
    }, {
    }, {
    }],
    "errors": {
        "error1": {
            "message": "error1",
            "type": "ERROR"
        },
        "error2": {
            "message": "error2",
            "type": "WARNING"
        }
    }
}

Который, как видите, не имеет keys и value. Убедитесь, что вы напечатали не само сообщение, а результат JsonFormat.printer().print(). По сути, key и value, которые вы видели, относятся к внутренней toString() реализации Protobuf Message.

И полное имя класса для JsonFormatcom.google.protobuf.util.JsonFormat, а не com.googlecode.protobuf.format.JsonFormat.

person madhead    schedule 16.11.2018
comment
Спасибо за помощь ! Действительно, я использовал com.googlecode.protobuf.format.JsonFormat вместо com.google.protobuf.util.JsonFormat, что было проблемой. Googlecode кажется устаревшим форматированием? - person CrazyGreenHand; 16.11.2018
comment
Думаю, да, он устарел. Все результаты Google относятся к com.google.protobuf.util.JsonFormat. - person madhead; 16.11.2018