Я поддерживаю небольшой REST-ful API на основе protobuf, используя Джерси. Я работаю над небольшим проектом, который может вызывать protobuf api через конечную точку прокси-сервера json. Чтобы проиллюстрировать мою идею, вот список ресурсов и конечных точек:

PersonResource
    GET /getPerson -> @returns instance of PersonProto
    POST /person -> create person and @returns instance of PersonProto
SubscriptionResource
    GET /getSubscriptions(personId) -> @returns List<SubscriptionProto>
etc     

Теперь, используя почтовый клиент, пользователь может отправить запрос protobuf через конечную точку прокси-сервера json, передав запрос json вместо сообщения protobuf. Поэтому мне бы хотелось, чтобы конечная точка прокси-сервера обрабатывала обратное преобразование между json и protobuf. Есть ли надежный способ сделать это с помощью Java 11 и Protocol-buffers версии 3? Если да, не могли бы вы поделиться некоторыми примерами?

0
Rustem K 1 Окт 2022 в 20:11

2 ответа

Вы можете использовать отражение для доступа к объектам protobuf и создания сопоставления между protobuf и json.

0
talex 1 Окт 2022 в 20:29
Спасибо @talex. Что вы имеете в виду под картированием? Не могли бы вы привести пример? Да, я думал использовать JSONFormat с отражением.
 – 
Rustem K
1 Окт 2022 в 20:36
Вы в основном перебираете свойства json, находите соответствующие свойства protobuf с помощью отражения и присваиваете им значения.
 – 
talex
1 Окт 2022 в 21:34
Да, это то, что делает JSONFormat. Спасибо, если найдёте примеры, с удовольствием посмотрю
 – 
Rustem K
2 Окт 2022 в 03:42

Я знал, что мы можем использовать отражение с самого начала, но я думал, что может существовать более простой способ сделать то же самое. Вот вспомогательный класс, который я создал для такого варианта использования:

Если вы знаете путь к классу сообщений или каким-то образом имеете ссылку на класс сообщений, вы можете использовать утилиту JsonFormat protobuf.

package com.apple.amp.commerce.support.protodive.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;
import com.google.protobuf.util.JsonFormat;

import java.io.UncheckedIOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ProtoBufJsonSerializer {

    private static final JsonFormat.Parser JSON_FORMAT_PARSER = JsonFormat.parser().ignoringUnknownFields();
    private static final JsonFormat.Printer JSON_FORMAT_PRINTER = JsonFormat.printer().includingDefaultValueFields();
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    public JsonNode getJsonNodeFromMessage(Message message) {
        final String jsonString = getJsonStringMessage(message);
        try {
            return OBJECT_MAPPER.readTree(jsonString);
        } catch (JsonProcessingException e) {
            throw new UncheckedIOException(e);
        }
    }

    private String getJsonStringMessage(Message message) {
        try {
            return JSON_FORMAT_PRINTER.print(message);
        } catch (InvalidProtocolBufferException e) {
            throw new IllegalStateException("Unable to transform message to json", e);
        }
    }

    public Message getMessageFromJson(String messageClassName, JsonNode requestPayload) {
        Message.Builder msgBuilder = getMessageBuilder(messageClassName);
        try {
            String jsonString = requestPayload.toString();
            JSON_FORMAT_PARSER.merge(jsonString, msgBuilder);
            return msgBuilder.build();
        } catch (InvalidProtocolBufferException e) {
            throw new IllegalStateException(e);
        }
    }

    private Message.Builder getMessageBuilder(String messageClassName) {
        try{
            Class<? extends Message> msgClass = (Class<? extends Message>) Class.forName(messageClassName);
            Method toBuilderMethod = msgClass.getMethod("getDefaultInstance");
            Message msg = (Message) toBuilderMethod.invoke(null);
            return msg.toBuilder();
        } catch(IllegalAccessException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException e){
            throw new IllegalStateException("Unable to transform json into message", e);
        }
    }
}
0
Rustem K 3 Ноя 2022 в 21:06