Java로 Google Protocol Buffer 이용해보기
언어에 구애받지 않는 데이터 포맷인 Google Protocol Buffer
를 살펴보자. 프로토콜이 있는 파일을 정의하고 그 프로토콜을 이용해서, Java
, C++
, C#
, Go
, Python
과 같은 언어로 된 코드를 만들어낼 수 있다.
protobuf-java
의존성을 입력해준다.
protobuf
포맷에서 매우 간단한 프로토콜을 정의할 수 있다.
message Person {
required string name = 1;
}
위는 name
이라는 간단한 문자열 필드 하나를 가진 Person
타입의 간단한 메세지 프로토콜이다.
프로토콜 정의를 좀 더 복잡한 형태로 한 것을 한번 보자. 우리가 Person
의 상세한 정보를 protobuf
포맷으로 적용할 필요가 있을 때는 다음과 같다.
package protobuf;
option java_package = "com.jakeseo.protobuf";
option java_outer_classname = "AddressBookProtos";
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
repeated string numbers = 4;
}
message AddressBook {
repeated Person people = 1;
}
우리 프로토콜은 두개의 데이터 타입을 포함한다: Person
과 AddressBook
이다. 코드를 생성한 이후에, 위의 클래스들은 AddressBookProtos
라는 클래스의 하위 클래스로 들어갈 것이다.
필요로 되는 필드(없으면 Exception
을 일으키는)를 정의하고 싶을 때, 우리는 꼭 required
키워드를 사용해야 한다.
optional
키워드와 함께 필드를 만들면, 꼭 필요로 되지는 않는다는 의미가 된다. repeated
키워드는 배열 형태를 저장할 때 입력한다.
모든 필드는 인덱싱 된다. 1
로 표기된 필드는 바이너리 파일의 첫번째 필드로서 저장된다. 2
로 표기된 필드는 다음 필드가 된다. 이렇게 숫자를 표기하는 것은 우리 필드가 메모리에 어떻게 저장될지에 대해 제어할 수 있게 해준다.
일단 protobuf 파일을 작성하고 나면, 우리는 그 파일로부터 코드를 생성할 수 있다.
먼저 protobuf 설치 링크여기에서 protobuf
를 다운받고,
protoc -I=. --java_out=. addressbook.proto
와 같이 명령어를 입력하면 아래와 같이 자바 파일이 생성된다.
protoc 명령어가 addressbook.proto
파일로부터 Java 출력 파일을 만들어낸다. -option
을 이용하여 proto
파일이 어디에 위치할지 정할 수 있다. java-out
은 어디에 저장될지를 정하는 것을 도와준다.
생성된 클래스는 getter
, setter
, constructor
를 갖고 있다. 그리고 정의된 메세지를 위한 빌더도 갖고 있다. 또한 생성된 클래스는 protobuf
파일을 저장하기 위한 메소드와 binary
파일에서 자바 클래스 파일로 역직렬화 할 수 있는 메소드와 같은 유틸 메소드도 갖고 있다.
Builder
를 이용해서 테스트 해보았다. 메세지 타입에 있는 newBuilder()
라는 메소드를 이용해서 테스트해볼 수 있다. 모든 required
필드를 작성한 이후에 build()
메소드를 호출하면, Person
클래스를 만들수 있다.
일단 Person
클래스의 인스턴스를 만들면, 생성된 프로토콜과 호환되는 binary format으로 디스크에 저장을 하고 싶을 것이다. Addressbook
클래스의 인스턴스를 만들고, 해당 오브젝트에 Person
을 하나 추가하고 싶다고 가정해보자.
우리는 다음과 같은 코드로 객체를 디스크에 저장이 가능하다. 자동생성된 writeTo()
유틸 메소드가 있다.
AddressBookProtos.AddressBook addressBook
= AddressBookProtos.AddressBook.newBuilder().addPeople(person).build();
FileOutputStream fos = new FileOutputStream(filePath);
addressBook.writeTo(fos);
해당 메소드를 실행한 이후에, 오브젝트가 직렬화되어 binary format이 되고 디스크에 저장된다. 데이터를 다시 불러오고 싶다면, 역직렬화를 거쳐서 다시 AddressBook
오브젝트로 가져오면 되는데, 이 때 mergeFrom()
메소드를 사용할 수 있다.
난 다음과 같은 테스트 코드들을 작성했고, 잘 동작했다.
Google Proto Buffer를 사용해보았다.
간단한 프로토콜을 만들어보았고, 그 프로토콜을 이용해서 자바 인스턴스를 생성해보기도 했고, binary 파일로 직렬화도 해보고 그걸 다시 역직렬화도 해봤다.