Common utilities for Google APIs in Java
—
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.
Core class for representing and processing path templates. Supports variable extraction from paths, path generation from variables, and template validation.
/**
* Represents a path template which can be used to parse and serialize resource names
*/
class PathTemplate {
/**
* Creates a template from the given pattern
* @param template The template pattern string (e.g., "projects/{project}/topics/{topic}")
* @return A PathTemplate instance
* @throws ValidationException If the template is invalid
*/
static PathTemplate create(String template);
/**
* Creates a template from the given pattern without URL encoding
* @param template The template pattern string
* @return A PathTemplate instance
* @throws ValidationException If the template is invalid
*/
static PathTemplate createWithoutUrlEncoding(String template);
/**
* Matches the given resource path against this template
* @param path The resource path to match
* @return True if the path matches this template
*/
boolean matches(String path);
/**
* Matches the given resource path and extracts the variable values
* @param path The resource path to match
* @return A map from variable names to their values
* @throws ValidationException If the path does not match this template
*/
Map<String, String> match(String path);
/**
* Matches a full resource name (including endpoint) and extracts variables
* @param path The full resource path to match
* @return A map from variable names to their values, including $hostname if present
* @throws ValidationException If the path does not match this template
*/
Map<String, String> matchFromFullName(String path);
/**
* Matches the path and returns the variable map, with validation and custom error messaging
* @param path The resource path to match
* @param exceptionMessagePrefix The prefix for the exception message if validation fails
* @return A map from variable names to their values
* @throws ValidationException If the path does not match this template
*/
Map<String, String> validatedMatch(String path, String exceptionMessagePrefix);
/**
* Validates that the given path matches this template
* @param path The resource path to validate
* @param exceptionMessagePrefix The prefix for the exception message if validation fails
* @throws ValidationException If the path does not match this template
*/
void validate(String path, String exceptionMessagePrefix);
/**
* Instantiates the template using the provided variable values
* @param values A map from variable names to their values
* @return The instantiated path
* @throws ValidationException If required variables are missing
*/
String instantiate(Map<String, String> values);
/**
* Instantiates the template using the provided key-value pairs
* @param keysAndValues Alternating keys and values (key1, value1, key2, value2, ...)
* @return The instantiated path
* @throws ValidationException If required variables are missing or wrong number of arguments
*/
String instantiate(String... keysAndValues);
/**
* Instantiates the template allowing unbound variables to remain as wildcards
* @param values A map from variable names to their values
* @return The partially instantiated path with wildcards for unbound variables
*/
String instantiatePartial(Map<String, String> values);
/**
* Returns the set of variable names used in this template
* @return A set of variable names
*/
Set<String> vars();
/**
* Returns the parent template (template with the last segment removed)
* @return The parent template, or null if this template has no parent
*/
PathTemplate parentTemplate();
/**
* Returns a template where all variables are replaced with wildcards
* @return A template with wildcards instead of variables
*/
PathTemplate withoutVars();
/**
* Returns a sub-template for the specified variable
* @param varName The variable name
* @return The sub-template, or null if the variable doesn't exist
*/
PathTemplate subTemplate(String varName);
/**
* Returns the single variable name if this template has exactly one variable
* @return The variable name, or null if the template doesn't have exactly one variable
*/
String singleVar();
/**
* Returns true if this template ends with a literal string (not a variable)
* @return True if the template ends with a literal
*/
boolean endsWithLiteral();
/**
* Returns true if this template ends with a custom verb
* @return True if the template ends with a custom verb
*/
boolean endsWithCustomVerb();
/**
* Creates a TemplatedResourceName from the given path using this template
* @param path The resource path
* @return A TemplatedResourceName instance
* @throws ValidationException If the path does not match this template
*/
TemplatedResourceName parse(String path);
/**
* Encodes the given values as a path using positional matching
* @param values The values to encode
* @return The encoded path
*/
String encode(String... values);
/**
* Decodes a path into positional values
* @param path The path to decode
* @return A list of decoded values
*/
List<String> decode(String path);
}Constants:
/**
* Special variable name for hostname bindings in full resource names
*/
String HOSTNAME_VAR = "$hostname";Usage Examples:
import com.google.api.pathtemplate.PathTemplate;
import java.util.Map;
// Create a path template
PathTemplate template = PathTemplate.create("projects/{project}/topics/{topic}");
// Extract variables from a path
Map<String, String> vars = template.match("projects/my-project/topics/my-topic");
// vars contains: {"project": "my-project", "topic": "my-topic"}
// Generate a path from variables
String path = template.instantiate("project", "my-project", "topic", "my-topic");
// path is: "projects/my-project/topics/my-topic"
// Check if a path matches
boolean matches = template.matches("projects/test/topics/news");
// matches is true
// Get all variable names in the template
Set<String> variableNames = template.vars();
// variableNames contains: ["project", "topic"]
// Work with nested resources - get parent template
PathTemplate parent = template.parentTemplate();
// parent template is: "projects/{project}"
// Handle full resource names with endpoints
PathTemplate fullTemplate = PathTemplate.create("projects/{project}/topics/{topic}");
Map<String, String> fullVars = fullTemplate.matchFromFullName(
"//pubsub.googleapis.com/projects/my-project/topics/my-topic"
);
// fullVars contains: {"$hostname": "pubsub.googleapis.com", "project": "my-project", "topic": "my-topic"}A resource name implementation that combines a path template with variable values, implementing the Map<String, String> interface for easy access to variable values.
/**
* A resource name that is based on a path template
*/
class TemplatedResourceName implements Map<String, String> {
/**
* Creates a TemplatedResourceName from a template and resource path
* @param template The path template
* @param path The resource path that matches the template
* @return A TemplatedResourceName instance
* @throws ValidationException If the path does not match the template
*/
static TemplatedResourceName create(PathTemplate template, String path);
/**
* Creates a TemplatedResourceName from a template and variable values
* @param template The path template
* @param values A map of variable names to values
* @return A TemplatedResourceName instance
* @throws ValidationException If required variables are missing
*/
static TemplatedResourceName create(PathTemplate template, Map<String, String> values);
/**
* Creates a TemplatedResourceName from a template and full resource name (including endpoint)
* @param template The path template
* @param path The full resource path including endpoint
* @return A TemplatedResourceName instance
* @throws ValidationException If the path does not match the template
*/
static TemplatedResourceName createFromFullName(PathTemplate template, String path);
/**
* Returns the path template used to create this resource name
* @return The path template
*/
PathTemplate template();
/**
* Returns true if this resource name has an endpoint
* @return True if an endpoint is present
*/
boolean hasEndpoint();
/**
* Returns the endpoint of this resource name, or null if none
* @return The endpoint string, or null
*/
String endpoint();
/**
* Creates a copy of this resource name with the specified endpoint
* @param endpoint The endpoint to set
* @return A new TemplatedResourceName with the specified endpoint
*/
TemplatedResourceName withEndpoint(String endpoint);
/**
* Returns the parent resource name by using the parent template
* @return The parent resource name, or null if this resource has no parent
*/
TemplatedResourceName parentName();
/**
* Returns true if this resource name starts with the given parent name
* @param parentName The potential parent resource name
* @return True if this resource is a child of the given parent
*/
boolean startsWith(TemplatedResourceName parentName);
/**
* Resolves this resource name to a resource object via API call
* @param resourceType The type of resource to resolve to
* @param version The API version to use
* @return The resolved resource
* @throws Exception If the resolution fails
*/
<T> T resolve(Class<T> resourceType, String version) throws Exception;
}Resource Name Resolver:
/**
* Interface for pluggable resource name resolution
*/
interface Resolver {
/**
* Resolves a resource name to a resource object
* @param resourceName The resource name to resolve
* @param resourceType The type of resource to resolve to
* @param version The API version to use
* @return The resolved resource
* @throws Exception If the resolution fails
*/
<T> T resolve(TemplatedResourceName resourceName, Class<T> resourceType, String version) throws Exception;
}
/**
* Registers a global resource name resolver
* @param resolver The resolver to register
*/
static void registerResourceNameResolver(Resolver resolver);Usage Examples:
import com.google.api.pathtemplate.PathTemplate;
import com.google.api.pathtemplate.TemplatedResourceName;
import java.util.HashMap;
import java.util.Map;
// Create from path and template
PathTemplate template = PathTemplate.create("projects/{project}/topics/{topic}");
TemplatedResourceName resourceName = TemplatedResourceName.create(
template,
"projects/my-project/topics/my-topic"
);
// Access variable values (implements Map<String, String>)
String project = resourceName.get("project"); // "my-project"
String topic = resourceName.get("topic"); // "my-topic"
// Create from template and values
Map<String, String> values = new HashMap<>();
values.put("project", "another-project");
values.put("topic", "another-topic");
TemplatedResourceName fromValues = TemplatedResourceName.create(template, values);
// Work with parent resources
TemplatedResourceName parent = resourceName.parentName();
// parent represents "projects/my-project"
boolean isChild = resourceName.startsWith(parent); // true
// Work with endpoints
TemplatedResourceName withEndpoint = resourceName.withEndpoint("pubsub.googleapis.com");
boolean hasEndpoint = withEndpoint.hasEndpoint(); // true
String endpoint = withEndpoint.endpoint(); // "pubsub.googleapis.com"
// Create from full name with endpoint
TemplatedResourceName fromFullName = TemplatedResourceName.createFromFullName(
template,
"//pubsub.googleapis.com/projects/my-project/topics/my-topic"
);Exception thrown when path template operations fail validation, with support for contextual error messages.
/**
* Exception thrown when path template validation fails
*/
class ValidationException extends IllegalArgumentException {
/**
* Creates a ValidationException with the given message
* @param message The error message
*/
public ValidationException(String message);
/**
* Creates a ValidationException with the given message and cause
* @param message The error message
* @param cause The underlying cause
*/
public ValidationException(String message, Throwable cause);
/**
* Sets a validation context for the current thread
* @param context The validation context description
*/
static void pushCurrentThreadValidationContext(String context);
/**
* Clears the validation context for the current thread
*/
static void popCurrentThreadValidationContext();
}Usage Examples:
import com.google.api.pathtemplate.PathTemplate;
import com.google.api.pathtemplate.ValidationException;
PathTemplate template = PathTemplate.create("projects/{project}/topics/{topic}");
try {
// This will throw ValidationException because the path doesn't match
template.match("projects/my-project/buckets/my-bucket");
} catch (ValidationException e) {
System.err.println("Path validation failed: " + e.getMessage());
}
// Use validation context for better error messages
ValidationException.pushCurrentThreadValidationContext("Processing user input");
try {
template.validate("invalid/path", "User provided path");
} catch (ValidationException e) {
// Exception message will include context information
System.err.println("Validation error: " + e.getMessage());
} finally {
ValidationException.popCurrentThreadValidationContext();
}// Navigate up and down resource hierarchies
PathTemplate projectTemplate = PathTemplate.create("projects/{project}");
PathTemplate topicTemplate = PathTemplate.create("projects/{project}/topics/{topic}");
PathTemplate subscriptionTemplate = PathTemplate.create("projects/{project}/subscriptions/{subscription}");
// Create resource names
TemplatedResourceName project = TemplatedResourceName.create(projectTemplate, "projects/my-project");
TemplatedResourceName topic = TemplatedResourceName.create(topicTemplate, "projects/my-project/topics/news");
// Check relationships
boolean isChild = topic.startsWith(project); // true
// Get parent
TemplatedResourceName topicParent = topic.parentName();
// topicParent represents "projects/my-project"// Create templates for different resource types in the same project
PathTemplate baseTemplate = PathTemplate.create("projects/{project}");
Set<String> baseVars = baseTemplate.vars(); // ["project"]
// Extend templates while maintaining the base structure
PathTemplate topicTemplate = PathTemplate.create("projects/{project}/topics/{topic}");
PathTemplate subscriptionTemplate = PathTemplate.create("projects/{project}/subscriptions/{subscription}");
// Extract common variables
Map<String, String> topicVars = topicTemplate.match("projects/my-project/topics/news");
String commonProject = topicVars.get("project"); // "my-project"
Map<String, String> subVars = subscriptionTemplate.match("projects/my-project/subscriptions/alerts");
String sameProject = subVars.get("project"); // "my-project" (same as above)PathTemplate template = PathTemplate.create("projects/{project}/topics/{topic}/subscriptions/{subscription}");
// Generate partial paths when not all variables are known
Map<String, String> partialValues = new HashMap<>();
partialValues.put("project", "my-project");
partialValues.put("topic", "news");
// subscription is missing
String partial = template.instantiatePartial(partialValues);
// partial is: "projects/my-project/topics/news/subscriptions/*"Install with Tessl CLI
npx tessl i tessl/maven-com-google-api--api-common