Implementation:Apache Paimon RESTUtil
| Knowledge Sources | |
|---|---|
| Domains | REST API, Utilities, HTTP |
| Last Updated | 2026-02-08 00:00 GMT |
Overview
RESTUtil provides utility methods for REST operations including URL encoding/decoding, property merging, request body encoding, and HTTP response processing.
Description
RESTUtil is a comprehensive utility class that centralizes common operations needed for REST API communication in Apache Paimon. It provides a wide range of functionality essential for building and processing HTTP requests and responses.
The class offers property management utilities for extracting configuration properties with specific prefixes and merging property maps with proper override semantics. This is particularly useful when dealing with catalog configuration where different property namespaces need to be isolated or combined.
URL handling functionality includes encoding and decoding strings using UTF-8, building complete request URLs with query parameters, and validating SQL LIKE patterns for prefix matching. The URL building uses Apache HttpClient's URIBuilder for proper parameter encoding and formatting.
Request body encoding is flexible, supporting both JSON serialization for structured request objects and form-encoded data for Map-based requests. The utility automatically detects the input type and applies the appropriate encoding strategy.
Response processing utilities help determine request success based on HTTP status codes (200, 202, 204) and extract response bodies as strings. The utility also includes validation for prefix SQL patterns, ensuring they only contain wildcards at the end to support efficient prefix-based queries.
Usage
Use RESTUtil throughout REST catalog implementations for consistent handling of common operations like URL encoding, property management, request encoding, and response processing. These utilities ensure proper UTF-8 encoding, standardized error handling, and consistent request/response formatting.
Code Reference
Source Location
- Repository: Apache_Paimon
- File: paimon-api/src/main/java/org/apache/paimon/rest/RESTUtil.java
Signature
public class RESTUtil {
public static Map<String, String> extractPrefixMap(Options options, String prefix);
public static Map<String, String> extractPrefixMap(
Map<String, String> properties, String prefix);
public static Map<String, String> merge(
Map<String, String> baseProperties,
Map<String, String> overrideProperties);
public static String encodeString(String toEncode);
public static String decodeString(String encoded);
public static void validatePrefixSqlPattern(String pattern);
public static String encodedBody(Object body);
public static String extractResponseBodyAsString(ClassicHttpResponse response)
throws IOException, ParseException;
public static boolean isSuccessful(ClassicHttpResponse response);
public static String buildRequestUrl(String url, Map<String, String> queryParams);
}
Import
import org.apache.paimon.rest.RESTUtil;
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| options | Options | Yes | Paimon options object containing properties |
| properties | Map<String, String> | Yes | Property map to process |
| prefix | String | Yes | Prefix to extract from property keys |
| baseProperties | Map<String, String> | No | Base property map for merging |
| overrideProperties | Map<String, String> | No | Override property map for merging |
| toEncode | String | Yes | String to URL encode |
| encoded | String | Yes | String to URL decode |
| pattern | String | No | SQL LIKE pattern to validate |
| body | Object | No | Request body to encode (RESTRequest or Map) |
| response | ClassicHttpResponse | Yes | HTTP response to process |
| url | String | Yes | Base URL for building request URL |
| queryParams | Map<String, String> | No | Query parameters to append to URL |
Outputs
| Name | Type | Description |
|---|---|---|
| extractPrefixMap() | Map<String, String> | Returns properties matching the prefix with prefix removed from keys |
| merge() | Map<String, String> | Returns merged property map with overrides taking precedence |
| encodeString() | String | Returns URL-encoded string in UTF-8 |
| decodeString() | String | Returns URL-decoded string from UTF-8 |
| validatePrefixSqlPattern() | void | Throws exception if pattern is not a valid prefix pattern |
| encodedBody() | String | Returns encoded request body (JSON or form-encoded), or null |
| extractResponseBodyAsString() | String | Returns response body as UTF-8 string, or null if no entity |
| isSuccessful() | boolean | Returns true if response status is 200, 202, or 204 |
| buildRequestUrl() | String | Returns complete URL with query parameters appended |
Usage Examples
import org.apache.paimon.rest.RESTUtil;
import org.apache.paimon.options.Options;
import java.util.HashMap;
import java.util.Map;
// Example 1: Extract properties with prefix
Options options = new Options();
options.set("catalog.warehouse", "/path/to/warehouse");
options.set("catalog.uri", "https://catalog.example.com");
options.set("table.format", "orc");
Map<String, String> catalogProps = RESTUtil.extractPrefixMap(options, "catalog.");
// Result: {"warehouse": "/path/to/warehouse", "uri": "https://..."}
// Example 2: Merge property maps
Map<String, String> baseProps = new HashMap<>();
baseProps.put("timeout", "30000");
baseProps.put("retry.count", "3");
Map<String, String> overrideProps = new HashMap<>();
overrideProps.put("retry.count", "5"); // Override
overrideProps.put("compression", "gzip"); // New property
Map<String, String> merged = RESTUtil.merge(baseProps, overrideProps);
// Result: {"timeout": "30000", "retry.count": "5", "compression": "gzip"}
// Example 3: URL encoding/decoding
String tableName = "my_table$partition";
String encoded = RESTUtil.encodeString(tableName);
// Result: "my_table%24partition"
String decoded = RESTUtil.decodeString(encoded);
// Result: "my_table$partition"
// Example 4: Build request URL with query parameters
String baseUrl = "https://catalog.example.com/api/tables";
Map<String, String> params = new HashMap<>();
params.put("namespace", "default");
params.put("limit", "100");
params.put("filter", "type=managed");
String fullUrl = RESTUtil.buildRequestUrl(baseUrl, params);
// Result: "https://catalog.example.com/api/tables?namespace=default&limit=100&filter=type%3Dmanaged"
// Example 5: Encode request body as JSON
CreateTableRequest request = new CreateTableRequest("my_table", schema);
String jsonBody = RESTUtil.encodedBody(request);
// Result: JSON string representation
// Example 6: Encode form data
Map<String, String> formData = new HashMap<>();
formData.put("grant_type", "client_credentials");
formData.put("scope", "catalog:write");
String formBody = RESTUtil.encodedBody(formData);
// Result: "grant_type=client_credentials&scope=catalog%3Awrite"
// Example 7: Check response success
ClassicHttpResponse response = httpClient.execute(request);
if (RESTUtil.isSuccessful(response)) {
String body = RESTUtil.extractResponseBodyAsString(response);
System.out.println("Success: " + body);
} else {
System.err.println("Request failed with code: " + response.getCode());
}
// Example 8: Validate SQL pattern
try {
RESTUtil.validatePrefixSqlPattern("default.%"); // Valid
RESTUtil.validatePrefixSqlPattern("def%ault"); // Throws exception
} catch (IllegalArgumentException e) {
System.err.println("Invalid pattern: " + e.getMessage());
}
// Example 9: Handle null body encoding
String nullBody = RESTUtil.encodedBody(null);
// Result: null
// Example 10: Extract properties from map
Map<String, String> allProps = new HashMap<>();
allProps.put("dlf.region", "cn-hangzhou");
allProps.put("dlf.access-key-id", "LTAI***");
allProps.put("s3.endpoint", "s3.amazonaws.com");
Map<String, String> dlfProps = RESTUtil.extractPrefixMap(allProps, "dlf.");
// Result: {"region": "cn-hangzhou", "access-key-id": "LTAI***"}