protobuf-java中的一些小技巧

公羊嘉
2023-12-01

1、json字符串和pb对象之间的转换:

1)pom.xml

<dependency>
			<groupId>com.google.protobuf</groupId>
			<artifactId>protobuf-java</artifactId>
			<version>2.5.0</version>
</dependency>
<dependency>  
			<groupId>com.googlecode.protobuf-java-format</groupId>  
			<artifactId>protobuf-java-format</artifactId>  
			<version>1.2</version>  
</dependency>

2)pb消息定义:

option java_package = "com.abc.proto";
option java_outer_classname="HelloWordPB";

message HelloWord {
    optional int64 id = 1;
    optional string name = 2;
    repeated string recId = 3;
}

3)java代码:

public class PBTest {
	public static void main(String[] args) {
		JSONObject jo = new JSONObject();
		JSONArray ja = new JSONArray();
		ja.add("1");
		ja.add("2");
		
		jo.put("id", 123456);//这里不能是字符串类型,否则pb会报错
		jo.put("name", "test");
		jo.put("recId", ja);
		
		String jsonStr = jo.toJSONString();
		System.out.println(jsonStr);
		
		//json > pb
		Builder newBuilder = HelloWordPB.HelloWord.newBuilder();
		try {
			JsonFormat.merge(jsonStr, newBuilder);
			System.out.println(newBuilder.build().toString());
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		//pb > json
		String printToString = JsonFormat.printToString(newBuilder.build());
		System.out.println(printToString);
	}
}

输出:

{"name":"test","id":123456,"recId":["1","2"]}
id: 123456
name: "test"
recId: "1"
recId: "2"
{"id": 123456,"name": "test","recId": ["1","2"]}

2、toString于pb对象之间转换:

public static void main(String...strings) {
		
		Builder newBuilder = ApiLogPB.ApiLog.newBuilder();
		newBuilder.setCost(10);
		newBuilder.setChId("default");
		newBuilder.setReqId("reqid");
		newBuilder.setFNum(12);
		newBuilder.setPuid("puid");
		newBuilder.setUId("uid");
		
		ApiLog apiLog = newBuilder.build();
		String string = apiLog.toString();
		System.out.println(string);
		
		System.out.println("--------------------------");
		Builder newBuilder2 = ApiLogPB.ApiLog.newBuilder();
		try {
			TextFormat.merge(string, newBuilder2);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		String chId = newBuilder2.getChId();
		System.out.println(chId);
	}

输出:

puid: "puid"
uId: "uid"
reqId: "reqid"
fNum: 12
cost: 10
chId: "default"

--------------------------
default

3、从文件中构建pb对象:

1)pb结构

option java_package="com.lanjingling.cinema";
 
 enum MovieType{
     CHILDREN=1;
     ADULT=2;
     NORMAL=3;
     OHTER=4;
 }
 
 message Movie{
     required string name=1;
     required MovieType type=2;
     optional int32 releaseTimeStamp=3;
     optional string description=4;
 }
 
 message Ticket{
     required int32 id=1;
     repeated Movie movie=2;
     optional Customer customer=3;
 }

2)构建pb对象,tostring输出到文件:

public class Test {

	public static void main(String[] args) throws Exception {
		Cinema.Movie.Builder movieBuilder = Cinema.Movie.newBuilder();
        movieBuilder.setName("The Shining");
        movieBuilder.setType(Cinema.MovieType.ADULT);
        movieBuilder.setReleaseTimeStamp(327859200);
        Movie movie = movieBuilder.build();
        
        Cinema.Movie.Builder movieBuilder1 = Cinema.Movie.newBuilder();
        movieBuilder1.setName("The Shining1");
        movieBuilder1.setType(Cinema.MovieType.CHILDREN);
        movieBuilder1.setReleaseTimeStamp(327859201);
        Movie movie1 = movieBuilder1.build();
        
        Cinema.Ticket.Builder ticketBuilder = Cinema.Ticket.newBuilder();
        ticketBuilder.setId(1);
        ticketBuilder.addMovie(movie);
        ticketBuilder.addMovie(movie1);
        Ticket ticket = ticketBuilder.build();
        System.out.println(ticket.toString());
    }
}

将输出保存到cineme.txt文件。内容如下:

id: 1
movie {
  name: "The Shining"
  type: ADULT
  releaseTimeStamp: 327859200
}
movie {
  name: "The Shining1"
  type: CHILDREN
  releaseTimeStamp: 327859201
}

3)从文件中读取数据,反序列化:

public class Test2 {

	public static void main(String[] args) throws Exception {
        Cinema.Ticket.Builder ticketBuilder = Cinema.Ticket.newBuilder();
        InputStream inputStream = new FileInputStream("D://cinema.txt");
        TextFormat.merge(new InputStreamReader(inputStream), ticketBuilder);
        
        Ticket ticket = ticketBuilder.build();
        System.out.println(ticket);
	}

}

4、pb在构造Builder的时候可以传入一个pb对象:

 

1)假设我们从redis中读取了一个pb二进制数据,然后反序列化成pb对象:

com.abc.proto.UserRecHistoryPB.UserRecHistory userRecHistory = null;
String KEY = MessageFormat.format(CacheConstants.CACHE_KEY_USER_HISTORY_PERF, deviceId);
byte[] bs = couchbaseHistoryDao.get(KEY);
if (bs != null) {
	userRecHistory = UserRecHistoryPB.UserRecHistory.parseFrom(bs);
}

2)接下来对userRecHistory进行修改,修改完毕后需要再保存到redis中:

Builder recHistoryBuilder = UserRecHistoryPB.UserRecHistory.newBuilder(userRecHistory);
//修改
UserRecHistory build = recHistoryBuilder.build();
String KEY = MessageFormat.format(CacheConstants.CACHE_KEY_USER_HISTORY_PERF, deviceId);
		int ttl = (int)(System.currentTimeMillis()/1000)+CacheConstants.CACHE_TIME_QUARTER;
		couchbaseHistoryDao.set(KEY, 
				ttl, 
				build.toByteArray());

4、pb克隆:

pb的newBuilder就是一个深拷贝,类似于thrift的deepCopy();

Builder newBuilder = ApiLogPB.ApiLog.newBuilder();
newBuilder.setCost(10);
newBuilder.setChId("default");
newBuilder.setReqId("reqid");
newBuilder.setFNum(12);
newBuilder.setPuid("puid");
newBuilder.setUId("uid");

ApiLog apiLog = newBuilder.build();
//-----------
Builder newBuilder22 = apiLog.newBuilder();//深拷贝

类似于thtrift的:
InnerRequest pbdReq = innerRequest.deepCopy();

 

 类似资料: