This page describes the code generated by ScalaPB and how to use it.
The generator will create a Scala file for each top-level message and enum in your proto file. Using multiple files results in a better incremental compilation performance.
The Scala package of the generated files will be determined as follows:
- If the
java_packageoption is defined, then the Scala package will be
base_nameis the name of the proto file without the
- If the
java_packageis undefined, but the file specifies a package name via the
packagekeyword then the Scala package will be
- If neither
packageare specified, the Scala package will be just
From version 0.4.2, there is a way to customize the package name by using file-level options.
Each message corresponds to a final case class and a companion object.
Optional fields are wrapped in an
Option, repeated fields are given as
Seq, and required fields (which you should not use, see "Required is
forever" in the Language
Note that in proto3, scalar (non-message) fields are not wrapped in
For example, if your protocol buffer looks like this:
...then the compiler will generate code that looks like this:
The case class contains various methods for serialization, and the companion
object contains method for parsing. See the source code for
to see what methods are available
Create a new instance of a message by calling the constructor (as you normally would for a case class):
When constructing messages, it is advised to use named arguments Person(name = x, age = y) to ensure your code does not rely on the order of the fields in the protocol buffer definition.
Messages are immutables: once you created a message instance it can not be changed. Messages are thread-safe: you can access the same message instance from multiple threads.
When you want to modify a message, simply create a new one based on the
original. You can use the
copy() method Scala provides for all case classes,
however ScalaPB provides additional methods to make it even easier.
The first method is using a
withX() method, where
X is a name of a field.
Note that when using the
withX() method on an optional field, you do not
need to provide the
Another way to update a message is using the
update() method takes "mutations" (like the assignments above), and
applies them on the object. Using the
update() method, as we will see
below, usually results in a more concise code, especially when your fields are
Optional fields are wrapped inside an
Option. The compiler will generate a
getX() method that will return the option's value if it is set, or a
default value for the field if it is unset (that is, if it is
There are two ways to update an optional field using the
The first way sets the field with a value, the second way lets you pass an
Option so it is possible to set the field to
For each optional field
X, the compiler also generates a
that returns a new instance of the message which is identical to the original
one except that the field is assigned the value
Required fields have no default value in the generated constructor, so you must specify them when you instantiate a new message. Differences from optional fields:
- The value of the field is not wrapped inside an
- There is no
getXmethod (you can always use
- There is no
clearXmethod (since that will result in an invalid message)
- There is no
_.optionalXlens for the
Repeated fields are provided as a
Seq[T]. The compiler will generate the
addFoo(f1, [f2, f3, ...]: Foo): returns a copy with the given elements added to the original list.
addAllFoo(fs: Seq[Foo]): returns a copy with the given sequence of elements added to the original list.
withX(otherList): replace the sequence with another.
clearX: replace with the sequence with an empty one.
update() is especially fun with repeated fields:
Oneofs are great when you model a message that has multiple disjoint cases. An example use case would be:
The compiler will generate code that looks like this:
This enables writing coding like this:
Enumerations are implemented using sealed traits that extend
This approach, rather than using Scala's standard Enumeration type, allows
getting a warning from the Scala compiler when a pattern match is incomplete.
For a definition like:
The compiler will generate:
And we can write:
Each message case-class has
toProtoString method that returns a string
representation of the message in an ASCII format. The ASCII format can be
parsed back by the
fromAscii() method available on the companion object.
That format is not officially documented, but at least the standard Python,
Java and C++ implementations of protobuf attempt to generate (and be able to parse)
compatible ASCII representations. ScalaPB's
follow the Java implementation.
The format looks like this:
This format can be useful for debugging or for transient data processing, but beware of persisting these ASCII representations: unknown fields throw an exception, and unlike the binary format, the ASCII format is senstitive to renames.
If you are dealing with legacy Java protocol buffer code, while still wanting
to write new code using ScalaPB, it can be useful to generate converters
to/from the Java protocol buffers. To do this, set
Compile / PB.targets
like this in your
This will result in the following changes:
- The companion object for each message will have
- The companion object for enums will have