0
# Path Templates
1
2
Path template functionality provides URL pattern matching, variable extraction, and path generation capabilities essential for Google API resource name handling. This system enables type-safe manipulation of REST API resource paths with variable substitution.
3
4
## Capabilities
5
6
### PathTemplate Class
7
8
Core class for representing and processing path templates. Supports variable extraction from paths, path generation from variables, and template validation.
9
10
```java { .api }
11
/**
12
* Represents a path template which can be used to parse and serialize resource names
13
*/
14
class PathTemplate {
15
/**
16
* Creates a template from the given pattern
17
* @param template The template pattern string (e.g., "projects/{project}/topics/{topic}")
18
* @return A PathTemplate instance
19
* @throws ValidationException If the template is invalid
20
*/
21
static PathTemplate create(String template);
22
23
/**
24
* Creates a template from the given pattern without URL encoding
25
* @param template The template pattern string
26
* @return A PathTemplate instance
27
* @throws ValidationException If the template is invalid
28
*/
29
static PathTemplate createWithoutUrlEncoding(String template);
30
31
/**
32
* Matches the given resource path against this template
33
* @param path The resource path to match
34
* @return True if the path matches this template
35
*/
36
boolean matches(String path);
37
38
/**
39
* Matches the given resource path and extracts the variable values
40
* @param path The resource path to match
41
* @return A map from variable names to their values
42
* @throws ValidationException If the path does not match this template
43
*/
44
Map<String, String> match(String path);
45
46
/**
47
* Matches a full resource name (including endpoint) and extracts variables
48
* @param path The full resource path to match
49
* @return A map from variable names to their values, including $hostname if present
50
* @throws ValidationException If the path does not match this template
51
*/
52
Map<String, String> matchFromFullName(String path);
53
54
/**
55
* Matches the path and returns the variable map, with validation and custom error messaging
56
* @param path The resource path to match
57
* @param exceptionMessagePrefix The prefix for the exception message if validation fails
58
* @return A map from variable names to their values
59
* @throws ValidationException If the path does not match this template
60
*/
61
Map<String, String> validatedMatch(String path, String exceptionMessagePrefix);
62
63
/**
64
* Validates that the given path matches this template
65
* @param path The resource path to validate
66
* @param exceptionMessagePrefix The prefix for the exception message if validation fails
67
* @throws ValidationException If the path does not match this template
68
*/
69
void validate(String path, String exceptionMessagePrefix);
70
71
/**
72
* Instantiates the template using the provided variable values
73
* @param values A map from variable names to their values
74
* @return The instantiated path
75
* @throws ValidationException If required variables are missing
76
*/
77
String instantiate(Map<String, String> values);
78
79
/**
80
* Instantiates the template using the provided key-value pairs
81
* @param keysAndValues Alternating keys and values (key1, value1, key2, value2, ...)
82
* @return The instantiated path
83
* @throws ValidationException If required variables are missing or wrong number of arguments
84
*/
85
String instantiate(String... keysAndValues);
86
87
/**
88
* Instantiates the template allowing unbound variables to remain as wildcards
89
* @param values A map from variable names to their values
90
* @return The partially instantiated path with wildcards for unbound variables
91
*/
92
String instantiatePartial(Map<String, String> values);
93
94
/**
95
* Returns the set of variable names used in this template
96
* @return A set of variable names
97
*/
98
Set<String> vars();
99
100
/**
101
* Returns the parent template (template with the last segment removed)
102
* @return The parent template, or null if this template has no parent
103
*/
104
PathTemplate parentTemplate();
105
106
/**
107
* Returns a template where all variables are replaced with wildcards
108
* @return A template with wildcards instead of variables
109
*/
110
PathTemplate withoutVars();
111
112
/**
113
* Returns a sub-template for the specified variable
114
* @param varName The variable name
115
* @return The sub-template, or null if the variable doesn't exist
116
*/
117
PathTemplate subTemplate(String varName);
118
119
/**
120
* Returns the single variable name if this template has exactly one variable
121
* @return The variable name, or null if the template doesn't have exactly one variable
122
*/
123
String singleVar();
124
125
/**
126
* Returns true if this template ends with a literal string (not a variable)
127
* @return True if the template ends with a literal
128
*/
129
boolean endsWithLiteral();
130
131
/**
132
* Returns true if this template ends with a custom verb
133
* @return True if the template ends with a custom verb
134
*/
135
boolean endsWithCustomVerb();
136
137
/**
138
* Creates a TemplatedResourceName from the given path using this template
139
* @param path The resource path
140
* @return A TemplatedResourceName instance
141
* @throws ValidationException If the path does not match this template
142
*/
143
TemplatedResourceName parse(String path);
144
145
/**
146
* Encodes the given values as a path using positional matching
147
* @param values The values to encode
148
* @return The encoded path
149
*/
150
String encode(String... values);
151
152
/**
153
* Decodes a path into positional values
154
* @param path The path to decode
155
* @return A list of decoded values
156
*/
157
List<String> decode(String path);
158
}
159
```
160
161
**Constants:**
162
163
```java { .api }
164
/**
165
* Special variable name for hostname bindings in full resource names
166
*/
167
String HOSTNAME_VAR = "$hostname";
168
```
169
170
**Usage Examples:**
171
172
```java
173
import com.google.api.pathtemplate.PathTemplate;
174
import java.util.Map;
175
176
// Create a path template
177
PathTemplate template = PathTemplate.create("projects/{project}/topics/{topic}");
178
179
// Extract variables from a path
180
Map<String, String> vars = template.match("projects/my-project/topics/my-topic");
181
// vars contains: {"project": "my-project", "topic": "my-topic"}
182
183
// Generate a path from variables
184
String path = template.instantiate("project", "my-project", "topic", "my-topic");
185
// path is: "projects/my-project/topics/my-topic"
186
187
// Check if a path matches
188
boolean matches = template.matches("projects/test/topics/news");
189
// matches is true
190
191
// Get all variable names in the template
192
Set<String> variableNames = template.vars();
193
// variableNames contains: ["project", "topic"]
194
195
// Work with nested resources - get parent template
196
PathTemplate parent = template.parentTemplate();
197
// parent template is: "projects/{project}"
198
199
// Handle full resource names with endpoints
200
PathTemplate fullTemplate = PathTemplate.create("projects/{project}/topics/{topic}");
201
Map<String, String> fullVars = fullTemplate.matchFromFullName(
202
"//pubsub.googleapis.com/projects/my-project/topics/my-topic"
203
);
204
// fullVars contains: {"$hostname": "pubsub.googleapis.com", "project": "my-project", "topic": "my-topic"}
205
```
206
207
### TemplatedResourceName Class
208
209
A resource name implementation that combines a path template with variable values, implementing the `Map<String, String>` interface for easy access to variable values.
210
211
```java { .api }
212
/**
213
* A resource name that is based on a path template
214
*/
215
class TemplatedResourceName implements Map<String, String> {
216
/**
217
* Creates a TemplatedResourceName from a template and resource path
218
* @param template The path template
219
* @param path The resource path that matches the template
220
* @return A TemplatedResourceName instance
221
* @throws ValidationException If the path does not match the template
222
*/
223
static TemplatedResourceName create(PathTemplate template, String path);
224
225
/**
226
* Creates a TemplatedResourceName from a template and variable values
227
* @param template The path template
228
* @param values A map of variable names to values
229
* @return A TemplatedResourceName instance
230
* @throws ValidationException If required variables are missing
231
*/
232
static TemplatedResourceName create(PathTemplate template, Map<String, String> values);
233
234
/**
235
* Creates a TemplatedResourceName from a template and full resource name (including endpoint)
236
* @param template The path template
237
* @param path The full resource path including endpoint
238
* @return A TemplatedResourceName instance
239
* @throws ValidationException If the path does not match the template
240
*/
241
static TemplatedResourceName createFromFullName(PathTemplate template, String path);
242
243
/**
244
* Returns the path template used to create this resource name
245
* @return The path template
246
*/
247
PathTemplate template();
248
249
/**
250
* Returns true if this resource name has an endpoint
251
* @return True if an endpoint is present
252
*/
253
boolean hasEndpoint();
254
255
/**
256
* Returns the endpoint of this resource name, or null if none
257
* @return The endpoint string, or null
258
*/
259
String endpoint();
260
261
/**
262
* Creates a copy of this resource name with the specified endpoint
263
* @param endpoint The endpoint to set
264
* @return A new TemplatedResourceName with the specified endpoint
265
*/
266
TemplatedResourceName withEndpoint(String endpoint);
267
268
/**
269
* Returns the parent resource name by using the parent template
270
* @return The parent resource name, or null if this resource has no parent
271
*/
272
TemplatedResourceName parentName();
273
274
/**
275
* Returns true if this resource name starts with the given parent name
276
* @param parentName The potential parent resource name
277
* @return True if this resource is a child of the given parent
278
*/
279
boolean startsWith(TemplatedResourceName parentName);
280
281
/**
282
* Resolves this resource name to a resource object via API call
283
* @param resourceType The type of resource to resolve to
284
* @param version The API version to use
285
* @return The resolved resource
286
* @throws Exception If the resolution fails
287
*/
288
<T> T resolve(Class<T> resourceType, String version) throws Exception;
289
}
290
```
291
292
**Resource Name Resolver:**
293
294
```java { .api }
295
/**
296
* Interface for pluggable resource name resolution
297
*/
298
interface Resolver {
299
/**
300
* Resolves a resource name to a resource object
301
* @param resourceName The resource name to resolve
302
* @param resourceType The type of resource to resolve to
303
* @param version The API version to use
304
* @return The resolved resource
305
* @throws Exception If the resolution fails
306
*/
307
<T> T resolve(TemplatedResourceName resourceName, Class<T> resourceType, String version) throws Exception;
308
}
309
310
/**
311
* Registers a global resource name resolver
312
* @param resolver The resolver to register
313
*/
314
static void registerResourceNameResolver(Resolver resolver);
315
```
316
317
**Usage Examples:**
318
319
```java
320
import com.google.api.pathtemplate.PathTemplate;
321
import com.google.api.pathtemplate.TemplatedResourceName;
322
import java.util.HashMap;
323
import java.util.Map;
324
325
// Create from path and template
326
PathTemplate template = PathTemplate.create("projects/{project}/topics/{topic}");
327
TemplatedResourceName resourceName = TemplatedResourceName.create(
328
template,
329
"projects/my-project/topics/my-topic"
330
);
331
332
// Access variable values (implements Map<String, String>)
333
String project = resourceName.get("project"); // "my-project"
334
String topic = resourceName.get("topic"); // "my-topic"
335
336
// Create from template and values
337
Map<String, String> values = new HashMap<>();
338
values.put("project", "another-project");
339
values.put("topic", "another-topic");
340
TemplatedResourceName fromValues = TemplatedResourceName.create(template, values);
341
342
// Work with parent resources
343
TemplatedResourceName parent = resourceName.parentName();
344
// parent represents "projects/my-project"
345
346
boolean isChild = resourceName.startsWith(parent); // true
347
348
// Work with endpoints
349
TemplatedResourceName withEndpoint = resourceName.withEndpoint("pubsub.googleapis.com");
350
boolean hasEndpoint = withEndpoint.hasEndpoint(); // true
351
String endpoint = withEndpoint.endpoint(); // "pubsub.googleapis.com"
352
353
// Create from full name with endpoint
354
TemplatedResourceName fromFullName = TemplatedResourceName.createFromFullName(
355
template,
356
"//pubsub.googleapis.com/projects/my-project/topics/my-topic"
357
);
358
```
359
360
### ValidationException
361
362
Exception thrown when path template operations fail validation, with support for contextual error messages.
363
364
```java { .api }
365
/**
366
* Exception thrown when path template validation fails
367
*/
368
class ValidationException extends IllegalArgumentException {
369
/**
370
* Creates a ValidationException with the given message
371
* @param message The error message
372
*/
373
public ValidationException(String message);
374
375
/**
376
* Creates a ValidationException with the given message and cause
377
* @param message The error message
378
* @param cause The underlying cause
379
*/
380
public ValidationException(String message, Throwable cause);
381
382
/**
383
* Sets a validation context for the current thread
384
* @param context The validation context description
385
*/
386
static void pushCurrentThreadValidationContext(String context);
387
388
/**
389
* Clears the validation context for the current thread
390
*/
391
static void popCurrentThreadValidationContext();
392
}
393
```
394
395
**Usage Examples:**
396
397
```java
398
import com.google.api.pathtemplate.PathTemplate;
399
import com.google.api.pathtemplate.ValidationException;
400
401
PathTemplate template = PathTemplate.create("projects/{project}/topics/{topic}");
402
403
try {
404
// This will throw ValidationException because the path doesn't match
405
template.match("projects/my-project/buckets/my-bucket");
406
} catch (ValidationException e) {
407
System.err.println("Path validation failed: " + e.getMessage());
408
}
409
410
// Use validation context for better error messages
411
ValidationException.pushCurrentThreadValidationContext("Processing user input");
412
try {
413
template.validate("invalid/path", "User provided path");
414
} catch (ValidationException e) {
415
// Exception message will include context information
416
System.err.println("Validation error: " + e.getMessage());
417
} finally {
418
ValidationException.popCurrentThreadValidationContext();
419
}
420
```
421
422
## Common Patterns
423
424
### Resource Hierarchy Navigation
425
426
```java
427
// Navigate up and down resource hierarchies
428
PathTemplate projectTemplate = PathTemplate.create("projects/{project}");
429
PathTemplate topicTemplate = PathTemplate.create("projects/{project}/topics/{topic}");
430
PathTemplate subscriptionTemplate = PathTemplate.create("projects/{project}/subscriptions/{subscription}");
431
432
// Create resource names
433
TemplatedResourceName project = TemplatedResourceName.create(projectTemplate, "projects/my-project");
434
TemplatedResourceName topic = TemplatedResourceName.create(topicTemplate, "projects/my-project/topics/news");
435
436
// Check relationships
437
boolean isChild = topic.startsWith(project); // true
438
439
// Get parent
440
TemplatedResourceName topicParent = topic.parentName();
441
// topicParent represents "projects/my-project"
442
```
443
444
### Template Composition
445
446
```java
447
// Create templates for different resource types in the same project
448
PathTemplate baseTemplate = PathTemplate.create("projects/{project}");
449
Set<String> baseVars = baseTemplate.vars(); // ["project"]
450
451
// Extend templates while maintaining the base structure
452
PathTemplate topicTemplate = PathTemplate.create("projects/{project}/topics/{topic}");
453
PathTemplate subscriptionTemplate = PathTemplate.create("projects/{project}/subscriptions/{subscription}");
454
455
// Extract common variables
456
Map<String, String> topicVars = topicTemplate.match("projects/my-project/topics/news");
457
String commonProject = topicVars.get("project"); // "my-project"
458
459
Map<String, String> subVars = subscriptionTemplate.match("projects/my-project/subscriptions/alerts");
460
String sameProject = subVars.get("project"); // "my-project" (same as above)
461
```
462
463
### Partial Path Generation
464
465
```java
466
PathTemplate template = PathTemplate.create("projects/{project}/topics/{topic}/subscriptions/{subscription}");
467
468
// Generate partial paths when not all variables are known
469
Map<String, String> partialValues = new HashMap<>();
470
partialValues.put("project", "my-project");
471
partialValues.put("topic", "news");
472
// subscription is missing
473
474
String partial = template.instantiatePartial(partialValues);
475
// partial is: "projects/my-project/topics/news/subscriptions/*"
476
```