Implementation:Apache Paimon JsonSerdeUtil
| Knowledge Sources | |
|---|---|
| Domains | Serialization, JSON Processing |
| Last Updated | 2026-02-08 00:00 GMT |
Overview
JsonSerdeUtil provides utilities for JSON serialization and deserialization using Jackson with Paimon-specific type handling.
Description
JsonSerdeUtil is a utility class providing centralized JSON processing capabilities for Apache Paimon through a shared, pre-configured ObjectMapper instance. The class addresses the performance concern that creating ObjectMapper instances is expensive, so it maintains a single static OBJECT_MAPPER_INSTANCE configured with Paimon-specific serializers and deserializers for TableSchema, DataField, and DataType objects. The mapper is configured to ignore unknown properties during deserialization (for forward compatibility) and to not fail on empty beans during serialization.
The utility provides a comprehensive suite of methods for common JSON operations: parseJsonMap() for parsing JSON objects into LinkedHashMap with type conversion, fromJson() for deserializing JSON strings into Java objects, toJson() for pretty-printed serialization, toFlatJson() for compact serialization, and various node extraction methods like getNodeAs(), extractValue(), and isNodeExists() for navigating JSON trees. Additional utilities support value conversion, node type validation, and null checking.
The class includes a sophisticated registration system (registerJsonObjects()) allowing custom serializers and deserializers to be added through a fluent API. Internally, it creates a Paimon-specific Jackson module that registers handlers for core Paimon types, enabling seamless serialization of complex type hierarchies. The implementation also includes JavaTimeModule for Java 8 temporal type support.
Usage
Use JsonSerdeUtil for all JSON serialization/deserialization in Paimon applications to ensure consistent handling of Paimon types, proper configuration, and optimal performance through ObjectMapper reuse. It is particularly important when persisting schemas, types, or configuration objects.
Code Reference
Source Location
Signature
public class JsonSerdeUtil {
public static final ObjectMapper OBJECT_MAPPER_INSTANCE;
public static <V> LinkedHashMap<String, V> parseJsonMap(String jsonString, Class<V> valueType)
public static <T extends JsonNode> T getNodeAs(JsonNode root, String fieldName, Class<T> clazz)
public static <T> T fromJson(String json, TypeReference<T> typeReference)
public static <T> T fromJson(String json, Class<T> clazz)
public static <T> String toJson(T t)
public static <T> String toFlatJson(T t)
public static <T> void registerJsonObjects(SimpleModule module,
Class<T> clazz,
JsonSerializer<T> serializer,
JsonDeserializer<T> deserializer)
public static <T extends JsonNode> T asSpecificNodeType(String json, Class<T> clazz)
throws JsonProcessingException
public static <T> T extractValueOrDefault(JsonNode jsonNode,
Class<T> valueType,
T defaultValue,
String... path)
throws JsonProcessingException
public static <T> T extractValue(JsonNode jsonNode, Class<T> valueType, String... path)
throws JsonProcessingException
public static boolean isNodeExists(JsonNode jsonNode, String... path)
public static <T> T convertValue(Object fromValue, TypeReference<T> toValueTypeRef)
public static String writeValueAsString(Object value) throws JsonProcessingException
public static boolean isNull(JsonNode jsonNode)
}
Import
import org.apache.paimon.utils.JsonSerdeUtil;
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| json | String | Context-dependent | JSON string to parse |
| object | Object | Context-dependent | Java object to serialize |
| jsonNode | JsonNode | Context-dependent | JSON node for navigation |
| path | String... | Context-dependent | Path elements for nested navigation |
Outputs
| Name | Type | Description |
|---|---|---|
| Parsed object | T (generic) | Deserialized Java object |
| JSON string | String | Serialized JSON (pretty or flat) |
| JSON node | JsonNode | Extracted or parsed JSON node |
| Existence check | boolean | Whether a path exists in JSON |
Usage Examples
// Serialize objects to JSON
DataType intType = DataTypes.INT();
String json = JsonSerdeUtil.toJson(intType);
// Pretty-printed with indentation
String flatJson = JsonSerdeUtil.toFlatJson(intType);
// Compact single-line format
// Deserialize from JSON
String schemaJson = "{\"fields\": [...], \"options\": {...}}";
TableSchema schema = JsonSerdeUtil.fromJson(schemaJson, TableSchema.class);
// Deserialize with TypeReference
String mapJson = "{\"key1\": \"value1\", \"key2\": \"value2\"}";
Map<String, String> map = JsonSerdeUtil.fromJson(
mapJson,
new TypeReference<Map<String, String>>() {}
);
// Parse JSON map with type conversion
String jsonMap = "{\"id\": 123, \"name\": \"test\"}";
LinkedHashMap<String, String> parsed = JsonSerdeUtil.parseJsonMap(
jsonMap,
String.class
);
// Navigate JSON nodes
JsonNode root = JsonSerdeUtil.OBJECT_MAPPER_INSTANCE.readTree(jsonString);
ObjectNode obj = JsonSerdeUtil.getNodeAs(root, "config", ObjectNode.class);
ArrayNode arr = JsonSerdeUtil.getNodeAs(root, "items", ArrayNode.class);
// Extract values from nested paths
JsonNode configNode = JsonSerdeUtil.OBJECT_MAPPER_INSTANCE.readTree(jsonString);
String value = JsonSerdeUtil.extractValue(
configNode,
String.class,
"database", "options", "path"
); // Extracts config.database.options.path
// Extract with default value
Integer timeout = JsonSerdeUtil.extractValueOrDefault(
configNode,
Integer.class,
30, // default
"connection", "timeout"
);
// Check if path exists
boolean hasPath = JsonSerdeUtil.isNodeExists(
configNode,
"features", "vectorSearch"
);
// Check for null
JsonNode node = root.get("optionalField");
boolean isNull = JsonSerdeUtil.isNull(node); // true if null or missing
// Convert between types
Object source = Map.of("key", "value");
Map<String, Object> converted = JsonSerdeUtil.convertValue(
source,
new TypeReference<Map<String, Object>>() {}
);
// Direct ObjectMapper access for custom needs
ObjectMapper mapper = JsonSerdeUtil.OBJECT_MAPPER_INSTANCE;
JsonNode tree = mapper.readTree(jsonString);
// Write value as string
Map<String, String> data = Map.of("a", "1", "b", "2");
String output = JsonSerdeUtil.writeValueAsString(data);
// Parse as specific node type
String arrayJson = "[1, 2, 3]";
ArrayNode array = JsonSerdeUtil.asSpecificNodeType(arrayJson, ArrayNode.class);