Scala
Bufrnix supports generating Scala code from Protocol Buffer definitions using ScalaPB, a protocol buffer compiler plugin for Scala.
Basic Configuration
Section titled “Basic Configuration”To enable Scala code generation, add the following to your flake.nix
:
protoGen = bufrnix.lib.mkBufrnixPackage { inherit pkgs;
config = { root = ./proto; languages = { scala = { enable = true; }; }; };};
Configuration Options
Section titled “Configuration Options”Basic Options
Section titled “Basic Options”Option | Type | Default | Description |
---|---|---|---|
enable | boolean | false | Enable Scala code generation |
package | package | pkgs.scalapb | The ScalaPB package to use |
outputPath | string | "gen/scala" | Output directory for generated Scala code |
options | list of strings | [] | Options to pass to ScalaPB |
scalaVersion | string | "3.3.3" | Scala version for generated build file |
scalapbVersion | string | "1.0.0-alpha.1" | ScalaPB version |
sbtVersion | string | "1.10.5" | SBT version for generated build file |
sbtProtocVersion | string | "1.0.7" | sbt-protoc plugin version |
projectName | string | "generated-protos" | Project name for generated build file |
projectVersion | string | "0.1.0" | Project version for generated build file |
organization | string | "com.example" | Organization for generated build file |
generateBuildFile | boolean | false | Generate build.sbt file |
generatePackageObject | boolean | false | Generate package objects for proto packages |
gRPC Support
Section titled “gRPC Support”To enable gRPC code generation:
scala = { enable = true; grpc = { enable = true; options = []; # Additional options for gRPC generation };};
JSON Support
Section titled “JSON Support”To enable JSON serialization support:
scala = { enable = true; json = { enable = true; json4sVersion = "0.7.0"; # scalapb-json4s version };};
Validation Support
Section titled “Validation Support”To enable validation support:
scala = { enable = true; validate = { enable = true; };};
ScalaPB Options
Section titled “ScalaPB Options”You can pass options to ScalaPB using the options
field:
scala = { enable = true; options = [ "flat_package" # Don't append file name to package "java_conversions" # Generate Java conversions "single_line_to_proto_string" # Single line toString ];};
Common ScalaPB options:
flat_package
- Don’t append file name to packagejava_conversions
- Generate converters to/from Java protosgrpc
- Generate gRPC service stubs (also available viagrpc.enable
)single_line_to_proto_string
- Generate single line toString methodsno_lenses
- Don’t generate lensesretain_source_code_info
- Retain source code info in descriptors
Generated Build File
Section titled “Generated Build File”When generateBuildFile
is enabled, bufrnix generates a complete SBT project structure:
scala = { enable = true; generateBuildFile = true; projectName = "MyProtoProject"; organization = "com.mycompany"; scalaVersion = "3.3.3";};
This generates:
build.sbt
- Main build file with ScalaPB dependenciesproject/plugins.sbt
- SBT plugins including sbt-protocproject/build.properties
- SBT version configuration
Example Usage
Section titled “Example Usage”Basic Example
Section titled “Basic Example”syntax = "proto3";
package example.v1;
option java_package = "com.example.v1";
message Person { int32 id = 1; string name = 2; string email = 3;}
Scala Code
Section titled “Scala Code”import com.example.v1.person._
// Create a personval person = Person( id = 1, name = "John Doe", email = "john@example.com")
// Serialize to bytesval bytes = person.toByteArray
// Parse from bytesval parsed = Person.parseFrom(bytes)
// Convert to JSON (if json support is enabled)import scalapb.json4s.JsonFormatval json = JsonFormat.toJsonString(person)
With gRPC
Section titled “With gRPC”syntax = "proto3";
package example.v1;
service Greeter { rpc SayHello (HelloRequest) returns (HelloReply);}
message HelloRequest { string name = 1;}
message HelloReply { string message = 1;}
import example.v1.greeter._import io.grpc.stub.StreamObserver
// Implement the serviceclass GreeterImpl extends GreeterGrpc.Greeter { override def sayHello( request: HelloRequest, responseObserver: StreamObserver[HelloReply] ): Unit = { val reply = HelloReply( message = s"Hello ${request.name}!" ) responseObserver.onNext(reply) responseObserver.onCompleted() }}
Development Shell
Section titled “Development Shell”Include necessary tools in your development shell:
devShells.default = pkgs.mkShell { buildInputs = with pkgs; [ jdk17 # or jdk21 sbt # Scala build tool scala_3 # or scala_2_13 protobuf # protoc compiler ];};
Tips and Best Practices
Section titled “Tips and Best Practices”- Package Names: Use
option java_package
in your proto files to control the generated package structure - Case Classes: ScalaPB generates immutable case classes by default
- Collections: Repeated fields become
Seq[T]
in Scala - Optionals: Proto3 optional fields become
Option[T]
in Scala - Enums: Proto enums become sealed traits with companion objects
- Unknown Fields: ScalaPB preserves unknown fields by default for forward compatibility
Troubleshooting
Section titled “Troubleshooting”Common Issues
Section titled “Common Issues”-
Missing Dependencies: Ensure your build.sbt includes the ScalaPB runtime:
libraryDependencies += "com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion % "protobuf" -
Import Errors: Make sure the generated code directory is added to your source paths:
Compile / sourceDirectories += file("gen/scala") -
Version Conflicts: Ensure your Scala version matches between ScalaPB and your project
Complete Flake Configuration Example
Section titled “Complete Flake Configuration Example”{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
bufrnix = {
url = "github:conneroisu/bufrnix";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {
nixpkgs,
flake-utils,
bufrnix,
...
}:
flake-utils.lib.eachDefaultSystem (
system: let
pkgs = nixpkgs.legacyPackages.${system};
# Generate protobuf code
protoGen = bufrnix.lib.mkBufrnixPackage {
inherit pkgs;
config = {
root = ./proto;
languages = {
scala = {
enable = true;
generateBuildFile = true;
projectName = "ScalaProtoExample";
organization = "com.example.protobuf";
};
};
};
};
in {
packages = {
default = protoGen;
proto = protoGen;
};
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
jdk17
sbt
scala_3
protobuf
];
shellHook = ''
echo "Scala Proto Example Development Shell"
echo "Run 'nix run' to generate proto code"
echo ""
echo "For development:"
echo " 1. Generate protos: nix run"
echo " 2. Compile: sbt compile"
echo " 3. Run: sbt run"
'';
};
apps = {
default = {
type = "app";
program = "${protoGen}/bin/bufrnix";
};
};
}
);
}