0
# Resource Names
1
2
Resource name functionality provides type-safe handling of Google API resource identifiers. This system enables consistent resource name parsing, validation, and field access across different resource types and formats.
3
4
## Capabilities
5
6
### ResourceName Interface
7
8
Core interface that all generated resource name types must implement. Provides standardized access to resource name field values and enables polymorphic handling of different resource name types.
9
10
```java { .api }
11
/**
12
* Interface that all resource name types must implement
13
*/
14
interface ResourceName {
15
/**
16
* Returns a map of field names to their values for this resource name
17
* @return An unmodifiable map from field names to field values
18
*/
19
Map<String, String> getFieldValuesMap();
20
21
/**
22
* Returns the value of the specified field name
23
* @param fieldName The name of the field to retrieve
24
* @return The field value, or null if the field doesn't exist
25
*/
26
String getFieldValue(String fieldName);
27
}
28
```
29
30
**Usage Examples:**
31
32
```java
33
import com.google.api.resourcenames.ResourceName;
34
35
// Assume you have a generated resource name class like ProjectName
36
// This is just an example - actual generated classes would implement this interface
37
class ProjectName implements ResourceName {
38
private final String project;
39
40
public ProjectName(String project) {
41
this.project = project;
42
}
43
44
@Override
45
public Map<String, String> getFieldValuesMap() {
46
return Collections.singletonMap("project", project);
47
}
48
49
@Override
50
public String getFieldValue(String fieldName) {
51
return "project".equals(fieldName) ? project : null;
52
}
53
54
@Override
55
public String toString() {
56
return "projects/" + project;
57
}
58
}
59
60
// Using the ResourceName interface polymorphically
61
ResourceName resourceName = new ProjectName("my-project");
62
Map<String, String> fields = resourceName.getFieldValuesMap();
63
// fields contains: {"project": "my-project"}
64
65
String projectValue = resourceName.getFieldValue("project");
66
// projectValue is: "my-project"
67
68
String nonExistentField = resourceName.getFieldValue("topic");
69
// nonExistentField is: null
70
```
71
72
### UntypedResourceName Class
73
74
A fallback resource name implementation for handling resource names with unknown or unexpected formats. Always accepts any non-null string as a valid resource name.
75
76
```java { .api }
77
/**
78
* A resource name implementation for unknown formats
79
*/
80
class UntypedResourceName implements ResourceName {
81
/**
82
* Creates an UntypedResourceName from an existing ResourceName
83
* @param resourceName The existing resource name to wrap
84
* @return An UntypedResourceName instance
85
*/
86
static UntypedResourceName of(ResourceName resourceName);
87
88
/**
89
* Parses a formatted string into an UntypedResourceName
90
* @param formattedString The resource name string to parse
91
* @return An UntypedResourceName instance
92
* @throws NullPointerException If formattedString is null
93
*/
94
static UntypedResourceName parse(String formattedString);
95
96
/**
97
* Checks if the given string can be parsed as an UntypedResourceName
98
* @param formattedString The string to check
99
* @return True if the string is non-null (UntypedResourceName accepts any non-null string)
100
*/
101
static boolean isParsableFrom(String formattedString);
102
103
@Override
104
public Map<String, String> getFieldValuesMap() {
105
// Returns map with empty string key mapping to the raw resource name
106
return ImmutableMap.of("", rawResourceName);
107
}
108
109
@Override
110
public String getFieldValue(String fieldName) {
111
// Returns the raw resource name if fieldName is empty string, null otherwise
112
return "".equals(fieldName) ? rawResourceName : null;
113
}
114
115
/**
116
* Returns the original formatted string
117
* @return The original resource name string
118
*/
119
@Override
120
public String toString();
121
}
122
```
123
124
**Usage Examples:**
125
126
```java
127
import com.google.api.resourcenames.UntypedResourceName;
128
import com.google.api.resourcenames.ResourceName;
129
130
// Create from string - accepts any non-null string
131
UntypedResourceName untyped = UntypedResourceName.parse("projects/my-project/topics/my-topic");
132
String value = untyped.toString();
133
// value is: "projects/my-project/topics/my-topic"
134
135
// Check if a string can be parsed (always true for non-null strings)
136
boolean canParse = UntypedResourceName.isParsableFrom("any-string-at-all");
137
// canParse is: true
138
139
boolean cannotParse = UntypedResourceName.isParsableFrom(null);
140
// cannotParse is: false
141
142
// Create from existing ResourceName
143
ResourceName existingResource = /* some existing resource name */;
144
UntypedResourceName wrapped = UntypedResourceName.of(existingResource);
145
146
// Field access - returns the raw value for empty string key, null for other keys
147
String fieldValue = untyped.getFieldValue("project");
148
// fieldValue is: null (field name doesn't match empty string)
149
150
String rawValue = untyped.getFieldValue("");
151
// rawValue is: "projects/my-project/topics/my-topic" (raw resource name string)
152
153
Map<String, String> fields = untyped.getFieldValuesMap();
154
// fields is: {"": "projects/my-project/topics/my-topic"} (empty string key maps to raw value)
155
156
// Useful as a fallback when parsing fails for typed resource names
157
String resourceString = "unknown/format/resource/name";
158
try {
159
// Try to parse as specific resource type first
160
ProjectName typed = ProjectName.parse(resourceString);
161
} catch (Exception e) {
162
// Fall back to untyped if specific parsing fails
163
UntypedResourceName fallback = UntypedResourceName.parse(resourceString);
164
// Always succeeds for non-null strings
165
}
166
```
167
168
### ResourceNameFactory Interface
169
170
Factory interface for creating ResourceName instances from formatted strings. Used by generated resource name classes to provide a consistent parsing interface.
171
172
```java { .api }
173
/**
174
* Factory interface for creating ResourceName instances
175
* @param <T> The type of ResourceName this factory creates
176
*/
177
interface ResourceNameFactory<T extends ResourceName> {
178
/**
179
* Parses a formatted string into a ResourceName of type T
180
* @param formattedString The resource name string to parse
181
* @return A parsed ResourceName instance
182
* @throws IllegalArgumentException If the string cannot be parsed
183
*/
184
T parse(String formattedString);
185
}
186
```
187
188
**Usage Examples:**
189
190
```java
191
import com.google.api.resourcenames.ResourceNameFactory;
192
import com.google.api.resourcenames.ResourceName;
193
194
// Example implementation for a hypothetical ProjectName class
195
class ProjectNameFactory implements ResourceNameFactory<ProjectName> {
196
@Override
197
public ProjectName parse(String formattedString) {
198
if (!formattedString.startsWith("projects/")) {
199
throw new IllegalArgumentException("Invalid project name format: " + formattedString);
200
}
201
String projectId = formattedString.substring("projects/".length());
202
return new ProjectName(projectId);
203
}
204
}
205
206
// Using the factory
207
ResourceNameFactory<ProjectName> factory = new ProjectNameFactory();
208
ProjectName project = factory.parse("projects/my-project");
209
210
// Factories enable polymorphic resource name creation
211
ResourceNameFactory<? extends ResourceName> genericFactory = getFactoryForType("project");
212
ResourceName resource = genericFactory.parse("projects/my-project");
213
```
214
215
## Common Patterns
216
217
### Polymorphic Resource Name Handling
218
219
```java
220
import com.google.api.resourcenames.ResourceName;
221
import com.google.api.resourcenames.UntypedResourceName;
222
223
// Handle different resource name types uniformly
224
public void processResource(ResourceName resourceName) {
225
// Access fields polymorphically
226
Map<String, String> fields = resourceName.getFieldValuesMap();
227
228
// Log all field values
229
for (Map.Entry<String, String> entry : fields.entrySet()) {
230
System.out.println(entry.getKey() + ": " + entry.getValue());
231
}
232
233
// Check for specific fields
234
String project = resourceName.getFieldValue("project");
235
if (project != null) {
236
System.out.println("Project: " + project);
237
}
238
239
// Get the string representation
240
String resourceString = resourceName.toString();
241
System.out.println("Resource: " + resourceString);
242
}
243
244
// Can be called with any ResourceName implementation
245
processResource(new ProjectName("my-project"));
246
processResource(UntypedResourceName.parse("custom/resource/format"));
247
```
248
249
### Fallback Parsing Strategy
250
251
```java
252
import com.google.api.resourcenames.UntypedResourceName;
253
254
// Robust resource name parsing with fallback
255
public ResourceName parseResourceName(String resourceString, String expectedType) {
256
try {
257
// Try to parse as specific known types first
258
switch (expectedType) {
259
case "project":
260
return ProjectName.parse(resourceString);
261
case "topic":
262
return TopicName.parse(resourceString);
263
case "subscription":
264
return SubscriptionName.parse(resourceString);
265
default:
266
// Unknown type - use untyped
267
return UntypedResourceName.parse(resourceString);
268
}
269
} catch (Exception e) {
270
// If parsing fails, fall back to untyped
271
System.err.println("Failed to parse as " + expectedType + ", using untyped: " + e.getMessage());
272
return UntypedResourceName.parse(resourceString);
273
}
274
}
275
276
// Usage
277
ResourceName resource1 = parseResourceName("projects/my-project", "project");
278
// Returns a strongly-typed ProjectName
279
280
ResourceName resource2 = parseResourceName("unknown/format", "project");
281
// Returns an UntypedResourceName (parsing failed)
282
283
ResourceName resource3 = parseResourceName("custom/resource/path", "unknown");
284
// Returns an UntypedResourceName (unknown type)
285
```
286
287
### Factory-Based Resource Creation
288
289
```java
290
import com.google.api.resourcenames.ResourceNameFactory;
291
import java.util.HashMap;
292
import java.util.Map;
293
294
// Registry of factories for different resource types
295
public class ResourceNameRegistry {
296
private final Map<String, ResourceNameFactory<? extends ResourceName>> factories = new HashMap<>();
297
298
public void registerFactory(String type, ResourceNameFactory<? extends ResourceName> factory) {
299
factories.put(type, factory);
300
}
301
302
public ResourceName parse(String type, String resourceString) {
303
ResourceNameFactory<? extends ResourceName> factory = factories.get(type);
304
if (factory != null) {
305
try {
306
return factory.parse(resourceString);
307
} catch (Exception e) {
308
// Fall back to untyped on parsing failure
309
return UntypedResourceName.parse(resourceString);
310
}
311
} else {
312
// Unknown type - use untyped
313
return UntypedResourceName.parse(resourceString);
314
}
315
}
316
}
317
318
// Setup and usage
319
ResourceNameRegistry registry = new ResourceNameRegistry();
320
registry.registerFactory("project", new ProjectNameFactory());
321
registry.registerFactory("topic", new TopicNameFactory());
322
323
// Parse different resource types
324
ResourceName project = registry.parse("project", "projects/my-project");
325
ResourceName topic = registry.parse("topic", "projects/my-project/topics/my-topic");
326
ResourceName unknown = registry.parse("unknown", "some/custom/format");
327
```
328
329
### Resource Name Validation
330
331
```java
332
import com.google.api.resourcenames.ResourceName;
333
import com.google.api.resourcenames.UntypedResourceName;
334
335
// Validate and extract information from resource names
336
public class ResourceNameValidator {
337
338
public boolean isValidProject(ResourceName resourceName) {
339
String project = resourceName.getFieldValue("project");
340
return project != null && !project.isEmpty() && project.matches("[a-z][a-z0-9-]*");
341
}
342
343
public boolean isTypedResourceName(ResourceName resourceName) {
344
// UntypedResourceName returns empty field map
345
return !resourceName.getFieldValuesMap().isEmpty();
346
}
347
348
public String extractProjectId(ResourceName resourceName) {
349
String project = resourceName.getFieldValue("project");
350
if (project == null) {
351
// Try to extract from string representation
352
String resourceString = resourceName.toString();
353
if (resourceString.startsWith("projects/")) {
354
String[] parts = resourceString.split("/");
355
if (parts.length >= 2) {
356
return parts[1];
357
}
358
}
359
}
360
return project;
361
}
362
}
363
364
// Usage
365
ResourceNameValidator validator = new ResourceNameValidator();
366
367
ResourceName typedResource = new ProjectName("my-project");
368
boolean isValid = validator.isValidProject(typedResource); // true
369
boolean isTyped = validator.isTypedResourceName(typedResource); // true
370
371
ResourceName untypedResource = UntypedResourceName.parse("projects/my-project");
372
boolean isValidUntyped = validator.isValidProject(untypedResource); // false (no field extraction)
373
boolean isTypedUntyped = validator.isTypedResourceName(untypedResource); // false
374
String projectId = validator.extractProjectId(untypedResource); // "my-project" (extracted from string)
375
```
376
377
## Integration with Path Templates
378
379
Resource names work seamlessly with path templates for comprehensive resource handling:
380
381
```java
382
import com.google.api.pathtemplate.PathTemplate;
383
import com.google.api.pathtemplate.TemplatedResourceName;
384
import com.google.api.resourcenames.ResourceName;
385
386
// TemplatedResourceName implements ResourceName interface
387
PathTemplate template = PathTemplate.create("projects/{project}/topics/{topic}");
388
TemplatedResourceName templatedName = TemplatedResourceName.create(
389
template,
390
"projects/my-project/topics/my-topic"
391
);
392
393
// Use as ResourceName
394
ResourceName resourceName = templatedName;
395
String project = resourceName.getFieldValue("project"); // "my-project"
396
String topic = resourceName.getFieldValue("topic"); // "my-topic"
397
398
Map<String, String> fields = resourceName.getFieldValuesMap();
399
// fields contains: {"project": "my-project", "topic": "my-topic"}
400
401
// Convert to string
402
String resourceString = resourceName.toString();
403
// resourceString is: "projects/my-project/topics/my-topic"
404
```