0
# Code Generation Templates
1
2
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.
3
4
## Template System Architecture
5
6
### Template Registration
7
8
```go { .api }
9
type RegisterFn func(tpl *template.Template, params pgs.Parameters)
10
```
11
12
Function type for registering language-specific template functions and helpers.
13
14
**Parameters:**
15
- `tpl *template.Template`: Template instance to register functions with
16
- `params pgs.Parameters`: PGS parameters for configuration
17
18
### File Path Generation
19
20
```go { .api }
21
type FilePathFn func(f pgs.File, ctx pgsgo.Context, tpl *template.Template) *pgs.FilePath
22
```
23
24
Function type for generating output file paths for templates.
25
26
**Parameters:**
27
- `f pgs.File`: Source proto file
28
- `ctx pgsgo.Context`: Go language context
29
- `tpl *template.Template`: Template being processed
30
31
**Returns:** `*pgs.FilePath` - Output file path for generated code
32
33
### Template Factory
34
35
```go { .api }
36
func Template(params pgs.Parameters) map[string][]*template.Template
37
```
38
39
Creates template map for all supported languages with registered functions.
40
41
**Parameters:**
42
- `params pgs.Parameters`: PGS parameters for template configuration
43
44
**Returns:** `map[string][]*template.Template` - Map of language to templates
45
46
Supported languages and their templates:
47
- `"go"`: Single Go template with validation methods
48
- `"java"`: Single Java template with validation classes
49
- `"cc"`: Header (.h) and implementation (.cc) templates
50
- `"ccnop"`: No-op C++ templates for compatibility
51
52
### File Path Resolution
53
54
```go { .api }
55
func FilePathFor(tpl *template.Template) FilePathFn
56
```
57
58
Returns appropriate file path generation function for template type.
59
60
**Parameters:**
61
- `tpl *template.Template`: Template to get path function for
62
63
**Returns:** `FilePathFn` - File path generation function
64
65
**Behavior:**
66
- `"h"` templates → C++ header file paths
67
- `"cc"` templates → C++ implementation file paths
68
- `"java"` templates → Java file paths with package structure
69
- Default → `.validate.{ext}` extension pattern
70
71
## Language-Specific Templates
72
73
### Go Templates
74
75
Go templates generate validation methods directly on protobuf message types.
76
77
**Template Name:** `"go"`
78
**Registration:** `golang.Register(tpl, params)`
79
**Output Extension:** `.pb.validate.go`
80
81
Generated code pattern:
82
```go
83
func (m *Message) Validate() error {
84
// validation logic
85
return nil
86
}
87
88
func (m *Message) ValidateAll() error {
89
// collect all validation errors
90
return errors
91
}
92
```
93
94
Features:
95
- Validates nested messages recursively
96
- Returns first error (`Validate`) or all errors (`ValidateAll`)
97
- Zero runtime dependencies
98
- Full integration with existing protobuf Go code
99
100
### Java Templates
101
102
Java templates generate validation classes with reflection-based validation.
103
104
**Template Name:** `"java"`
105
**Registration:** `java.Register(tpl, params)`
106
**Output Extension:** `.java`
107
108
Generated code pattern:
109
```java
110
public class MessageValidator implements Validator<Message> {
111
public void assertValid(Message message) throws ValidationException {
112
// validation logic
113
}
114
}
115
```
116
117
#### Java Template Functions
118
119
```go { .api }
120
func Register(tpl *template.Template, params pgs.Parameters)
121
```
122
123
Main Java template registration function with full validation template functions.
124
125
```go { .api }
126
func RegisterIndex(tpl *template.Template, params pgs.Parameters)
127
```
128
129
Index template registration for validator discovery and caching functionality.
130
131
```go { .api }
132
func JavaMultiFilePath(f pgs.File, m pgs.Message) pgs.FilePath
133
```
134
135
Generates file paths for multi-file Java generation when `java_multiple_files = true` option is set.
136
137
**Parameters:**
138
- `f pgs.File`: Source proto file
139
- `m pgs.Message`: Message to generate validator for
140
141
**Returns:** `pgs.FilePath` - Path for individual message validator class
142
143
Features:
144
- ReflectiveValidatorIndex for validator discovery
145
- gRPC interceptor support
146
- Exception-based error reporting
147
- Multi-file generation support for large proto files
148
149
### C++ Templates
150
151
C++ templates generate header and implementation files.
152
153
**Template Names:** `"h"`, `"cc"`
154
**Registration:** `cc.RegisterHeader(tpl, params)`, `cc.RegisterModule(tpl, params)`
155
**Output Extensions:** `.pb.validate.h`, `.pb.validate.cc`
156
157
Generated code pattern:
158
```cpp
159
// Header
160
namespace validate {
161
bool Validate(const Message& msg, std::string* error);
162
}
163
164
// Implementation
165
bool Validate(const Message& msg, std::string* error) {
166
// validation logic
167
return true;
168
}
169
```
170
171
Features:
172
- Separate header and implementation files
173
- String-based error reporting
174
- Integration with existing C++ protobuf code
175
176
### C++ No-Op Templates
177
178
C++ no-op templates generate stub validation functions that always return valid.
179
180
**Template Names:** `"h"`, `"cc"` (ccnop variant)
181
**Registration:** `ccnop.RegisterHeader(tpl, params)`, `ccnop.RegisterModule(tpl, params)`
182
**Output Extensions:** `.pb.validate.h`, `.pb.validate.cc`
183
184
Generated code pattern:
185
```cpp
186
// No-op validation - always returns true
187
bool Validate(const Message& msg, std::string* error) {
188
return true;
189
}
190
```
191
192
**Use Cases:**
193
- Placeholder validation during development
194
- Disabling validation for performance-critical code
195
- Maintaining API compatibility while bypassing validation
196
197
Features:
198
- Same interface as full C++ templates
199
- Zero validation logic - always passes
200
- Minimal code generation overhead
201
202
### Python Runtime
203
204
Python uses runtime code generation rather than compile-time templates.
205
206
**Module:** `protoc_gen_validate.validator`
207
**Approach:** JIT code generation with caching
208
209
Generated functions are created dynamically:
210
```python
211
def validate_Message(msg):
212
# dynamically generated validation logic
213
pass
214
```
215
216
Features:
217
- JIT compilation of validation functions
218
- LRU cache for performance
219
- Dynamic code execution with `exec()`
220
- Exception-based error reporting
221
222
## Template Utilities
223
224
### Shared Functions
225
226
All templates have access to shared utility functions:
227
228
```go { .api }
229
func RegisterFunctions(tpl *template.Template, params pgs.Parameters)
230
```
231
232
Registers common template functions for:
233
- Type conversion and formatting
234
- Rule processing and validation
235
- Code generation helpers
236
- Language-specific formatting
237
238
Common template functions include:
239
- String manipulation functions
240
- Type checking functions
241
- Rule evaluation helpers
242
- Import path generation
243
244
### Template Parameters
245
246
Templates receive PGS parameters for configuration:
247
248
**Common Parameters:**
249
- `lang`: Target language
250
- `module`: Go module path for imports
251
- `paths`: Path configuration for output
252
253
**Language-Specific Parameters:**
254
- Go: Module path, import style
255
- Java: Package structure, multi-file options
256
- C++: Namespace configuration
257
- Python: Runtime validation options
258
259
## Code Generation Process
260
261
### Template Processing Flow
262
263
1. PGS framework calls `Execute()` on validator module
264
2. Module determines target language and gets templates
265
3. For each proto file with validation rules:
266
- Module calls `CheckRules()` to validate rule consistency
267
- Templates are applied to generate code
268
- File paths are determined using `FilePathFor()`
269
- Generated code is added as artifacts
270
271
### Multi-File Generation
272
273
Java supports multi-file generation for better organization:
274
275
```go { .api }
276
func JavaMultiFilePath(f pgs.File, msg pgs.Message) *pgs.FilePath
277
```
278
279
Generates separate Java files for each message with validation rules.
280
281
**Parameters:**
282
- `f pgs.File`: Source proto file
283
- `msg pgs.Message`: Message to generate validator for
284
285
**Returns:** `*pgs.FilePath` - Path for message-specific validator file
286
287
### Template Customization
288
289
Templates can be customized through:
290
- Custom `RegisterFn` implementations
291
- Parameter-based configuration
292
- Language-specific template extensions
293
- Custom file path generation
294
295
## Error Handling
296
297
Template processing includes comprehensive error handling:
298
299
- **Rule Validation Errors**: Inconsistent or contradictory rules
300
- **Template Processing Errors**: Syntax or execution errors
301
- **File Generation Errors**: Output path or permission issues
302
- **Language-Specific Errors**: Type incompatibilities or feature limitations
303
304
All errors are reported through the PGS framework and cause protoc to exit with appropriate error codes.
305
306
## Performance Considerations
307
308
### Template Caching
309
310
Templates are created once per invocation and reused across files for performance.
311
312
### Code Generation Optimization
313
314
- Go: Uses efficient validation patterns with early returns
315
- Java: Leverages reflection caching for performance
316
- C++: Generates optimized validation loops
317
- Python: Uses LRU caching for compiled validation functions
318
319
### Memory Management
320
321
Templates are designed to minimize memory usage during generation:
322
- Streaming code generation where possible
323
- Efficient data structures for rule processing
324
- Cleanup of temporary data structures