J'ai un système existant, qui utilise le protocole de communication basé sur protobuf entre l'interface graphique et le serveur. J'aimerais maintenant ajouter un peu de persistance, mais pour le moment, les messages protobuf sont directement convertis en objets personnalisés tiers.
Y at-il un moyen de convertir proto messages en json , ce qui pourrait être ensuite persisté à la base de données.
N.B.: Je n'aime pas trop l'idée d'écrire protobuf binaire dans une base de données, car il pourrait un jour devenir non compatible avec les versions les plus récentes et casser le système de cette façon.
Nous utilisons actuellement format Java-protobuf pour convertir nos messages Protobuf (toute sous-classe de Message
) en un format JSON à envoyer via notre API Web.
Faites simplement:
JsonFormat.printToString(protoMessage)
Comme mentionné dans réponse à une question similaire , puisque v3.1. , il s'agit d'une fonctionnalité prise en charge de ProtocolBuffers. Pour Java, incluez le module d'extension (com.google.protobuf: protobuf-Java-util et utilisez JsonFormat comme suit:
JsonFormat.parser().ignoringUnknownFields().merge(json, yourObjectBuilder);
YourObject value = yourObjectBuilder.build();
Je n'aime pas beaucoup l'idée d'écrire protobuf binaire dans une base de données, car il pourrait un jour devenir rétro-compatible avec les versions les plus récentes et casser le système de cette façon.
La conversion de protobuf en JSON pour le stockage, puis de nouveau en protobuf au chargement est beaucoup plus susceptible de créer des problèmes de compatibilité, car:
Cela dit, il existe de nombreuses bibliothèques pour la conversion de protobufs en JSON, généralement construites sur l’interface de réflexion Protobuf (à ne pas confondre avec l’interface de réflexion Java; la réflexion Protobuf est proposée par le com.google.protobuf.Message
interface).
Ajoutant à la réponse de Ophir , JsonFormat est disponible même avant le lancement de protobuf 3.0. Cependant, la façon de le faire diffère un peu.
Dans Protobuf 3.0+, la classe JsonFormat est un singleton et fait donc quelque chose comme ci-dessous.
String jsonString = "";
JsonFormat.parser().ignoringUnknownFields().merge(json,yourObjectBuilder);
Dans Protobuf 2.5+, ce qui suit devrait fonctionner
String jsonString = "";
JsonFormat jsonFormat = new JsonFormat();
jsonString = jsonFormat.printToString(yourProtobufMessage);
Voici un lien vers un tutoriel que j'ai écrit et qui utilise la classe JsonFormat dans un TypeAdapter pouvant être inscrit dans un objet GsonBuilder. Vous pouvez ensuite utiliser les méthodes toJson et fromJson de Gson pour convertir les données proto en Java et inversement.
Répondre à jean . Si nous avons les données protobuf dans un fichier et que nous souhaitons les analyser dans un objet de message protobuf, utilisez la méthode de fusion TextFormat class. Voir l'extrait ci-dessous:
// Let your proto text data be in a file MessageDataAsProto.prototxt
// Read it into string
String protoDataAsString = FileUtils.readFileToString(new File("MessageDataAsProto.prototxt"));
// Create an object of the message builder
MyMessage.Builder myMsgBuilder = MyMessage.newBuilder();
// Use text format to parse the data into the message builder
TextFormat.merge(protoDataAsString, ExtensionRegistry.getEmptyRegistry(), myMsgBuilder);
// Build the message and return
return myMsgBuilder.build();
Essayez JsonFormat.printer().print(MessageOrBuilder)
, ça a l'air bien pour proto3. Cependant, il est difficile de savoir comment convertir le message protobuf
réel (fourni sous la forme du package Java de mon choix défini dans le fichier .proto) en un fichier com.google. Objet protbuf.Message.
Pour protobuf 2.5, utilisez la dépendance:
"com.googlecode.protobuf-Java-format" % "protobuf-Java-format" % "1.2"
Ensuite, utilisez le code:
com.googlecode.protobuf.format.JsonFormat.merge(json, builder)
com.googlecode.protobuf.format.JsonFormat.printToString(proto)
Eh bien, il n'y a pas de raccourci pour le faire selon mes conclusions, mais de toute façon vous
et y parvenir en quelques étapes simples
Vous devez d'abord déclarer un bean de type 'ProtobufJsonFormatHttpMessageConverter'
@Bean
@Primary
public ProtobufJsonFormatHttpMessageConverter protobufHttpMessageConverter() {
return new ProtobufJsonFormatHttpMessageConverter(JsonFormat.parser(), JsonFormat.printer());
}
Ensuite, vous pouvez simplement écrire une classe Utility telle que ResponseBuilder, car elle peut analyser la demande par défaut, mais sans ces modifications, elle ne peut pas produire de réponse Json. Vous pouvez ensuite écrire quelques méthodes pour convertir les types de réponse en type d'objet associé.
public static <T> T build(Message message, Class<T> type) {
Printer printer = JsonFormat.printer();
Gson gson = new Gson();
try {
return gson.fromJson(printer.print(message), type);
} catch (JsonSyntaxException | InvalidProtocolBufferException e) {
throw new ApiException(HttpStatus.INTERNAL_SERVER_ERROR, "Response conversion Error", e);
}
}
Ensuite, vous pouvez appeler cette méthode depuis votre classe de contrôleur en dernière ligne, par exemple -
return ResponseBuilder.build(<returned_service_object>, <Type>);
J'espère que cela vous aidera à implémenter protobuf au format json.
Voici une version générique du convertisseur Json
package com.intuit.platform.util;
import Java.io.IOException;
import Java.lang.reflect.InvocationTargetException;
import com.google.protobuf.AbstractMessage.Builder;
import com.google.protobuf.Message;
import com.google.protobuf.MessageOrBuilder;
import com.google.protobuf.util.JsonFormat;
/**
* Generic ProtoJsonUtil to be used to serialize and deserialize Proto to json
*
* @author [email protected]
*
*/
public final class ProtoJsonUtil {
/**
* Makes a Json from a given message or builder
*
* @param messageOrBuilder is the instance
* @return The string representation
* @throws IOException if any error occurs
*/
public static String toJson(MessageOrBuilder messageOrBuilder) throws IOException {
return JsonFormat.printer().print(messageOrBuilder);
}
/**
* Makes a new instance of message based on the json and the class
* @param <T> is the class type
* @param json is the json instance
* @param clazz is the class instance
* @return An instance of T based on the json values
* @throws IOException if any error occurs
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public static <T extends Message> T fromJson(String json, Class<T> clazz) throws IOException {
// https://stackoverflow.com/questions/27642021/calling-parsefrom-method-for-generic-protobuffer-class-in-Java/33701202#33701202
Builder builder = null;
try {
// Since we are dealing with a Message type, we can call newBuilder()
builder = (Builder) clazz.getMethod("newBuilder").invoke(null);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
return null;
}
// The instance is placed into the builder values
JsonFormat.parser().ignoringUnknownFields().merge(json, builder);
// the instance will be from the build
return (T) builder.build();
}
}
Son utilisation est aussi simple que suit:
GetAllGreetings.Builder allGreetingsBuilder = GetAllGreetings.newBuilder();
allGreetingsBuilder.addGreeting(makeNewGreeting("Marcello", "Hi %s, how are you", Language.EN))
.addGreeting(makeNewGreeting("John", "Today is hot, %s, get some ice", Language.ES))
.addGreeting(makeNewGreeting("Mary", "%s, summer is here! Let's go surfing!", Language.PT));
GetAllGreetings allGreetings = allGreetingsBuilder.build();
String json = ProtoJsonUtil.toJson(allGreetingsLoaded);
log.info("Json format: " + json);
GetAllGreetings parsed = ProtoJsonUtil.fromJson(json, GetAllGreetings.class);
log.info("The Proto deserialized from Json " + parsed);