Java: JSON -> Protobuf & back conversion

后端 未结 9 2095
隐瞒了意图╮
隐瞒了意图╮ 2020-12-02 10:59

I have an existing system, which is using protobuf-based communication protocol between GUI and server. Now I would like to add some persistence, but at the moment

9条回答
  •  孤街浪徒
    2020-12-02 11:43

    Generics Solution

    Here's a generic version of Json converter

    package com.github.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 Marcello.deeSales@gmail.com
     *
     */
    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  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 fromJson(String json, Class 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();
      }
    }
    
    

    Using it is as simple as follows:

    Message instance

    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();
    

    To Json Generic

    String json = ProtoJsonUtil.toJson(allGreetingsLoaded);
    log.info("Json format: " + json);
    

    From Json Generic

    GetAllGreetings parsed = ProtoJsonUtil.fromJson(json, GetAllGreetings.class);
    log.info("The Proto deserialized from Json " + parsed);
    

提交回复
热议问题