ProtoBeanUtil.java 5.63 KB
package com.tianting.infoloop.utils;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import com.google.protobuf.Message;
import com.google.protobuf.MessageOrBuilder;
import com.google.protobuf.util.JsonFormat;
import lombok.SneakyThrows;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class ProtoBeanUtil {

    /**
     * protoBean -> string
     *
     * @param sourceMessage protoBean
     * @return string
     */
    public static String protoToJson(MessageOrBuilder sourceMessage) {
        try {
            return JsonFormat.printer().print(sourceMessage);
        } catch (Exception e) {
            throw new IllegalArgumentException("ProtoBeanUtil->toJson->errorMessage:proto序列化string异常", e);
        }
    }

    private static Gson gson = getGson();

    /**
     * @desc: String 转 Builder对象
     */
    private static <M extends Message.Builder> void jsonToBuilder(M targetBuilder, String json) {
        try {
            JsonFormat.parser().ignoringUnknownFields().merge(json, targetBuilder);
        } catch (Exception e) {
            throw new IllegalArgumentException("ProtoBeanUtil->JsonToBuilder->errorMessage:json 转 Builder对象异常", e);
        }
    }

    /**
     * @desc: JavaBean 转 Builder对象
     */
    private static <M extends Message.Builder, T> M beanToBuilder(T beanSource, Class<M> targetBuilderClass) {
        try {
            Constructor<M> declaredConstructor = targetBuilderClass.getDeclaredConstructor((Class<?>[]) null);

            declaredConstructor.setAccessible(Boolean.TRUE);

            M instance = declaredConstructor.newInstance();

            Gson gson = getGson();

            String json = gson.toJson(beanSource);

            jsonToBuilder(instance, json);

            return instance;
        } catch (Exception e) {
            throw new IllegalArgumentException("ProtoBeanUtil->beanToBuilder->errorMessage:JavaBean 转 Builder对象异常", e);
        }
    }

    /**
     * @desc: javaBean 转 Proto
     */
    @SneakyThrows
    @SuppressWarnings("unchecked")
    public static <M extends Message, T> M beanToProto(T bean, Class<M> targetProtoClass) {

        Constructor<M> declaredConstructor = targetProtoClass.getDeclaredConstructor((Class<?>[]) null);

        declaredConstructor.setAccessible(Boolean.TRUE);

        M instance = declaredConstructor.newInstance();

        Gson gson = getGson();

        String json = gson.toJson(bean);

        Message.Builder builder = instance.toBuilder();

        jsonToBuilder(builder, json);

        return (M) builder.build();
    }

    /**
     * @desc: javaBean 列表 转 ProtoBean 列表
     */
    @SuppressWarnings("unchecked")
    public static <M, T extends Message> List<T> beanListToProtoList(Collection<M> beanSourceList, Class<T> protoBean) {
        try {
            List<T> resultList = new ArrayList<>();
            for (Object bean : beanSourceList) {

                Constructor<T> declaredConstructor = protoBean.getDeclaredConstructor((Class<?>[]) null);

                declaredConstructor.setAccessible(Boolean.TRUE);

                T instance = declaredConstructor.newInstance();

                Class<? extends Message.Builder> aClass = instance.toBuilder().getClass();

                Message.Builder builder = beanToBuilder(bean, aClass);

                resultList.add((T) builder.build());
            }
            return resultList;
        } catch (Exception e) {
            throw new IllegalArgumentException("ProtoBeanUtil->beanListToProtoList->errorMessage:javaBean 列表 转 ProtoBean 列表异常", e);
        }
    }

    private static Gson getGson() {
        if (gson != null) {
            return gson;
        }
        gson = new GsonBuilder()
                .registerTypeAdapter(LocalDateTime.class, new TypeAdapter<LocalDateTime>() {
                    @Override
                    public void write(JsonWriter out, LocalDateTime value) throws IOException {
                        if (value != null) {
                            out.value(LocalDateTimeUtil.toEpochMilli(value));
                        } else {
                            out.nullValue();
                        }
                    }

                    @Override
                    public LocalDateTime read(JsonReader in) throws IOException {
                        return LocalDateTimeUtil.of(Long.parseLong(in.nextString()));
                    }
                })
                .registerTypeAdapter(LocalDate.class, new TypeAdapter<LocalDate>() {
                            @Override
                            public void write(JsonWriter out, LocalDate value) throws IOException {
                                if (value != null) {
                                    out.value(LocalDateTimeUtil.toEpochMilli(value));
                                } else {
                                    out.nullValue();
                                }
                            }

                            @Override
                            public LocalDate read(JsonReader in) throws IOException {
                                return LocalDate.ofInstant(Instant.ofEpochMilli(Long.parseLong(in.nextString())), ZoneId.of("Asia/Shanghai"));
                            }
                        }
                ).create();
        return gson;
    }

}