Protoc plugin to generate polyglot message validators for protocol buffers
—
The code generation template system provides language-specific templates for generating validation code from protocol buffer files with validation rules. It uses Go's text/template package with custom functions for multi-language code generation.
type RegisterFn func(tpl *template.Template, params pgs.Parameters)Function type for registering language-specific template functions and helpers.
Parameters:
tpl *template.Template: Template instance to register functions withparams pgs.Parameters: PGS parameters for configurationtype FilePathFn func(f pgs.File, ctx pgsgo.Context, tpl *template.Template) *pgs.FilePathFunction type for generating output file paths for templates.
Parameters:
f pgs.File: Source proto filectx pgsgo.Context: Go language contexttpl *template.Template: Template being processedReturns: *pgs.FilePath - Output file path for generated code
func Template(params pgs.Parameters) map[string][]*template.TemplateCreates template map for all supported languages with registered functions.
Parameters:
params pgs.Parameters: PGS parameters for template configurationReturns: map[string][]*template.Template - Map of language to templates
Supported languages and their templates:
"go": Single Go template with validation methods"java": Single Java template with validation classes"cc": Header (.h) and implementation (.cc) templates"ccnop": No-op C++ templates for compatibilityfunc FilePathFor(tpl *template.Template) FilePathFnReturns appropriate file path generation function for template type.
Parameters:
tpl *template.Template: Template to get path function forReturns: FilePathFn - File path generation function
Behavior:
"h" templates → C++ header file paths"cc" templates → C++ implementation file paths"java" templates → Java file paths with package structure.validate.{ext} extension patternGo templates generate validation methods directly on protobuf message types.
Template Name: "go"
Registration: golang.Register(tpl, params)
Output Extension: .pb.validate.go
Generated code pattern:
func (m *Message) Validate() error {
// validation logic
return nil
}
func (m *Message) ValidateAll() error {
// collect all validation errors
return errors
}Features:
Validate) or all errors (ValidateAll)Java templates generate validation classes with reflection-based validation.
Template Name: "java"
Registration: java.Register(tpl, params)
Output Extension: .java
Generated code pattern:
public class MessageValidator implements Validator<Message> {
public void assertValid(Message message) throws ValidationException {
// validation logic
}
}func Register(tpl *template.Template, params pgs.Parameters)Main Java template registration function with full validation template functions.
func RegisterIndex(tpl *template.Template, params pgs.Parameters)Index template registration for validator discovery and caching functionality.
func JavaMultiFilePath(f pgs.File, m pgs.Message) pgs.FilePathGenerates file paths for multi-file Java generation when java_multiple_files = true option is set.
Parameters:
f pgs.File: Source proto filem pgs.Message: Message to generate validator forReturns: pgs.FilePath - Path for individual message validator class
Features:
C++ templates generate header and implementation files.
Template Names: "h", "cc"
Registration: cc.RegisterHeader(tpl, params), cc.RegisterModule(tpl, params)
Output Extensions: .pb.validate.h, .pb.validate.cc
Generated code pattern:
// Header
namespace validate {
bool Validate(const Message& msg, std::string* error);
}
// Implementation
bool Validate(const Message& msg, std::string* error) {
// validation logic
return true;
}Features:
C++ no-op templates generate stub validation functions that always return valid.
Template Names: "h", "cc" (ccnop variant)
Registration: ccnop.RegisterHeader(tpl, params), ccnop.RegisterModule(tpl, params)
Output Extensions: .pb.validate.h, .pb.validate.cc
Generated code pattern:
// No-op validation - always returns true
bool Validate(const Message& msg, std::string* error) {
return true;
}Use Cases:
Features:
Python uses runtime code generation rather than compile-time templates.
Module: protoc_gen_validate.validator
Approach: JIT code generation with caching
Generated functions are created dynamically:
def validate_Message(msg):
# dynamically generated validation logic
passFeatures:
exec()All templates have access to shared utility functions:
func RegisterFunctions(tpl *template.Template, params pgs.Parameters)Registers common template functions for:
Common template functions include:
Templates receive PGS parameters for configuration:
Common Parameters:
lang: Target languagemodule: Go module path for importspaths: Path configuration for outputLanguage-Specific Parameters:
Execute() on validator moduleCheckRules() to validate rule consistencyFilePathFor()Java supports multi-file generation for better organization:
func JavaMultiFilePath(f pgs.File, msg pgs.Message) *pgs.FilePathGenerates separate Java files for each message with validation rules.
Parameters:
f pgs.File: Source proto filemsg pgs.Message: Message to generate validator forReturns: *pgs.FilePath - Path for message-specific validator file
Templates can be customized through:
RegisterFn implementationsTemplate processing includes comprehensive error handling:
All errors are reported through the PGS framework and cause protoc to exit with appropriate error codes.
Templates are created once per invocation and reused across files for performance.
Templates are designed to minimize memory usage during generation:
Install with Tessl CLI
npx tessl i tessl/go-protoc-gen-validate