1. 程式人生 > >protobuf-java中的一些小技巧

protobuf-java中的一些小技巧

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