集成grpc,普通对象与grpc对象转换
分布式开发涉及到远程过程调用即RPC。需要集成grpc。但如果想无缝集成,则涉及到普通的请求对象转换为grpc请求对象。
由于null不能序列化,所以grpc的对象属性都会有默认值,这在开发中,很难区分,到底请求传的是默认值还是请求本身携带的值。所以使用protocol buffers 的oneof关键字,用于规避默认值。
新建员工类
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class EmpOne {
private Long empIdOne;
private String empNameOne;
private Boolean empSexOne;
private Long totalAssetOne;
private List<String> skills;
private Set<Integer> lucks;
private Map<String, String> relations;
private Date bornDate;
private Timestamp createTime;
private BigDecimal salary;
private DeptOne dept;
// ... 省略 get set
}
新建部门类
public class DeptOne {
private Long deptIdOne;
private String deptNameOne;
private Byte deptTypeOne;
// 省略 get set
}
proto文件
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.lyf.grpc";
option java_outer_classname = "EmpProto";
message EmpOne {
oneof oneof_empId {
int64 empIdOne = 4;
}
oneof oneof_totalAssetOne {
int64 totalAssetOne = 8;
}
oneof oneof_empName {
string empNameOne = 5;
}
oneof oneof_empSex {
bool empSexOne = 6;
}
DeptOne dept = 7;
repeated string skills = 9;
repeated int32 lucks = 10;
map<string, string> relations = 11;
oneof oneof_bornDate {
string bornDate = 12;
}
oneof oneof_createTime {
string createTime = 13;
}
oneof oneof_salary {
string salary = 14;
}
}
message DeptOne {
oneof oneof_deptId {
int32 deptIdOne = 4;
}
oneof oneof_deptName {
string deptNameOne = 5;
}
oneof oneof_deptType {
int32 deptTypeOne = 6;
}
}
单元测试代码
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.protobuf.util.JsonFormat;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @Author
* @Date 2019/8/12 0012 上午 11:40
*/
public class EmpOneTest {
/**
* oneof 普通请求转grpc请求,再转普通请求
* @throws IOException
*/
@Test
public void testOneCommonRequestTransformToGrpcRequest() throws IOException {
oneCommonRequestTransformToGrpcRequest();
}
public static void oneCommonRequestTransformToGrpcRequest() throws IOException {
DeptOne dept = new DeptOne();
dept.setDeptIdOne(0L);
dept.setDeptNameOne(StringUtils.EMPTY);
dept.setDeptTypeOne((byte)0);
List<String> skills = new ArrayList<>();
skills.add("EDVSD");
Set<Integer> lucks = new HashSet<>();
EmpOne emp = new EmpOne();
emp.setEmpIdOne(0L);
emp.setEmpNameOne(StringUtils.EMPTY);
emp.setEmpSexOne(false);
emp.setDept(dept);
emp.setSkills(skills);
emp.setLucks(lucks);
emp.setBornDate(new java.sql.Date(System.currentTimeMillis()));
emp.setCreateTime(new java.sql.Timestamp(System.currentTimeMillis()));
emp.setSalary(new BigDecimal("22.33"));
Gson gson = new GsonBuilder().serializeNulls()
.setPrettyPrinting()
.registerTypeAdapter(java.sql.Timestamp.class, new TimeStampGSON())
.registerTypeAdapter(java.sql.Date.class, new SqlDateGSON())
.create();
String empJson = gson.toJson(emp);
System.out.println("普通对象json==============");
System.out.println(empJson);
EmpOne.Builder builder = EmpOne.newBuilder();
JsonFormat.parser().merge(empJson, builder);
EmpOne empOneGrpc = builder.build();
StringBuilder sb = new StringBuilder();
JsonFormat.printer()
.includingDefaultValueFields() // 设置采用默认值,当集合为空的时候会使用[]表示,map为空的时候采用{},这样可能有效防止直接使用而遇到的空指针
.appendTo(empOneGrpc, sb);
System.out.println("grpc对象Json==============");
// 可以观察到普通对象json与grpcJson的区别,grpcJson对象字段为null的字段不显示,集合或map为空,则使用以上规则处理了
System.out.println(sb);
Gson gson2 = new GsonBuilder()
.setPrettyPrinting()
.serializeNulls()
.registerTypeAdapter(java.sql.Timestamp.class, new TimeStampGSON())
.registerTypeAdapter(java.sql.Date.class, new SqlDateGSON())
.create();
EmpOne vo = gson2.fromJson(sb.toString(), EmpOne.class);
System.out.println("普通对象json==============");
System.out.println(gson2.toJson(vo));
}
}
自定义TypeAdapter,需要实现JsonSerializer<T>, JsonDeserializer<T>两个接口
import com.google.gson.*;
import java.lang.reflect.Type;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TimeStampGSON implements JsonSerializer<Timestamp>, JsonDeserializer<Timestamp> {
private final DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public JsonElement serialize(Timestamp timestamp, Type type, JsonSerializationContext jsonSerializationContext) {
String dfString = format.format(new Date(timestamp.getTime()));
return new JsonPrimitive(dfString);
}
@Override
public Timestamp deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
if (!(jsonElement instanceof JsonPrimitive)) {
throw new JsonParseException("The date should be a string value");
}
try {
Date date = format.parse(jsonElement.getAsString());
return new Timestamp(date.getTime());
} catch (ParseException e) {
throw new JsonParseException(e);
}
}
}
import com.google.gson.*;
import java.lang.reflect.Type;
import java.sql.Date;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class SqlDateGSON implements JsonSerializer<Date>, JsonDeserializer<Date> {
private final DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
@Override
public Date deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
if (!(jsonElement instanceof JsonPrimitive)) {
throw new JsonParseException("The date should be a string value");
}
System.out.println(jsonElement.getAsString());
java.util.Date date = null;
Date date1 = null;
try {
date = format.parse(jsonElement.getAsString());
date1 = new Date(date.getTime());
} catch (ParseException e) {
e.printStackTrace();
}
return date1;
}
@Override
public JsonElement serialize(Date date, Type type, JsonSerializationContext jsonSerializationContext) {
String dateFormatAsString = format.format(new Date(date.getTime()));
return new JsonPrimitive(dateFormatAsString);
}
}
测试结果
普通对象json==============
{
"empIdOne": 0,
"empNameOne": "",
"empSexOne": false,
"totalAssetOne": null,
"skills": [
"EDVSD"
],
"lucks": [],
"relations": null,
"bornDate": "2019-08-12",
"createTime": "2019-08-12 13:39:14",
"salary": 22.33,
"dept": {
"deptIdOne": 0,
"deptNameOne": "",
"deptTypeOne": 0
}
}
grpc对象Json==============
{
"empIdOne": "0",
"empNameOne": "",
"empSexOne": false,
"dept": {
"deptIdOne": 0,
"deptNameOne": "",
"deptTypeOne": 0
},
"skills": ["EDVSD"],
"lucks": [],
"relations": {
},
"bornDate": "2019-08-12",
"createTime": "2019-08-12 13:39:14",
"salary": "22.33"
}
普通对象json==============
{
"empIdOne": 0,
"empNameOne": "",
"empSexOne": false,
"totalAssetOne": null,
"skills": [
"EDVSD"
],
"lucks": [],
"relations": {},
"bornDate": "2019-08-12",
"createTime": "2019-08-12 13:39:14",
"salary": 22.33,
"dept": {
"deptIdOne": 0,
"deptNameOne": "",
"deptTypeOne": 0
}
}