So far, we have modeled single objects in Protocol Buffers, such as a Person, Address, or Student. However, real-world systems often need to handle collections of items, such as a list of books in a library, a list of orders in an e-commerce system, or a list of messages in a chat application.
In this tutorial, we learn how to model collections in Protobuf using repeated fields, which allow a message to contain multiple values of the same type.
1. Why Do We Need Collections in Protobuf?
Sometimes a single value is not enough.
- A library contains many books, not just one.
- A student can have multiple phone numbers.
- An order can contain multiple products.
So we need a way to represent a list (or collection) of items in a message.
In Protobuf, this is done using the repeated keyword.
2. Defining the .proto File
Create a file collection.proto. Use Proto3 syntax and standard options
collection.proto
syntax = "proto3";
package example03;
option java_multiple_files = true;
option java_package = "com.learnitweb.example03";
option java_outer_classname = "CollectionProto";
// Book message
message Book {
string title = 1;
string author = 2;
int32 publication_year = 3;
}
// Library message
message Library {
string name = 1;
repeated Book books = 2;
}
3. Understanding repeated
The key line is:
repeated Book books = 2;
This means:
booksis a collection (list) of Book messages.- You can add zero, one, or many Book objects.
- Internally, this behaves like a list.
You can think of it as:
List<Book> books;
So the Library message contains a collection of Book objects.
4. Compile the Protobuf
After creating the .proto file, run:
mvn clean compile
This generates the Java classes from the .proto definition.
5. Java Example: Creating Books and a Library
package org.learnitweb;
import com.learnitweb.example03.Book;
import com.learnitweb.example03.Library;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
public class Main {
private static final Logger logger = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
// Book 1
Book book1 = Book.newBuilder()
.setTitle("Harry Potter Part 1")
.setAuthor("J.K. Rowling")
.setPublicationYear(1997)
.build();
// Book 2
Book book2 = Book.newBuilder()
.setTitle("Harry Potter Part 2")
.setAuthor("J.K. Rowling")
.setPublicationYear(1998)
.build();
// Book 3
Book book3 = Book.newBuilder()
.setTitle("Harry Potter Part 3")
.setAuthor("J.K. Rowling")
.setPublicationYear(1999)
.build();
// Library
Library library = Library.newBuilder()
.setName("Fantasy Library")
.addBooks(book1)
.addBooks(book2)
.addBooks(book3)
.build();
System.out.println(library);
}
}
This prints the library with all its books.
Output
name: "Fantasy Library"
books {
title: "Harry Potter Part 1"
author: "J.K. Rowling"
publication_year: 1997
}
books {
title: "Harry Potter Part 2"
author: "J.K. Rowling"
publication_year: 1998
}
books {
title: "Harry Potter Part 3"
author: "J.K. Rowling"
publication_year: 1999
}
6. Adding Items One by One vs Bulk Add
Adding One by One
.addBooks(book1) .addBooks(book2) .addBooks(book3)
This works well for a small number of items.
But what if you have hundreds of books?
Adding a List (Bulk Add)
If you already have a list:
List<Book> bookList = List.of(book1, book2, book3);
Library library = Library.newBuilder()
.setName("Fantasy Library")
.addAllBooks(bookList)
.build();
This is much cleaner and more scalable.
So:
- Use
addBooks()for single items. - Use
addAllBooks()for collections.
7. Getter Methods for Repeated Fields
Repeated fields generate slightly different getters compared to normal fields.
Assume:
repeated Book books = 2;
7.1 Get Book by Index
library.getBooks(0);
This returns the book at index 0.
7.2 Get Count
library.getBooksCount();
This returns how many books exist.
7.3 Get All Books as List
library.getBooksList();
This returns:
List<Book>
This is how you access all books.
8. Why Not Just getBooks()?
Many developers expect:
getBooks();
But Protobuf does not generate this for repeated fields.
Instead:
getBooks(index)getBooksCount()getBooksList()
This naming is intentional and consistent in Protobuf.
9. Field Name Matters
Method names are derived from the field name.
If your field is:
repeated Book items = 2;
You would get:
getItems(index)getItemsCount()getItemsList()
So choose field names carefully.
