https://github.com/filip26/polymorph-tree
Uniform API to read/write tree data models - cross-format, cross-library.
https://github.com/filip26/polymorph-tree
cbor jackson-databind jakarta-json-api json-api
Last synced: 2 months ago
JSON representation
Uniform API to read/write tree data models - cross-format, cross-library.
- Host: GitHub
- URL: https://github.com/filip26/polymorph-tree
- Owner: filip26
- License: apache-2.0
- Created: 2025-09-08T21:52:34.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2025-10-13T11:37:16.000Z (2 months ago)
- Last Synced: 2025-10-13T16:24:08.946Z (2 months ago)
- Topics: cbor, jackson-databind, jakarta-json-api, json-api
- Language: Java
- Homepage: https://apicatalog.com
- Size: 427 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Security: SECURITY.md
Awesome Lists containing this project
README
# 🌳 Tree I/O
**Uniform API to read/write tree data models — cross-format, cross-library.**
**tree-io** provides a consistent abstraction for working with **tree-like data structures**. It is **format-agnostic** (JSON, YAML, CBOR, …) and **library-agnostic** (Jackson, Gson, Jakarta, …), allowing you to **read, manipulate, and write trees uniformly** without depending on a specific parser or serializer.
## ✨ Features
- 🌐 Uniform, library-agnostic API for tree data processing
- 🗂️ Supports multiple formats: JSON, YAML, CBOR
- 🔌 Works with Jackson, Gson, Jakarta, and other libraries
- 🛠️ Extensible adapter model for adding new formats or libraries
## 🏗️ Use Cases
- Uniform processing of tree-structured data
- Building library-agnostic processors and pipelines
- Manipulating hierarchical data in a consistent way
## 🔌 Implementations of Tree I/O API
Artifact | Version | Javadoc
-----------------------|---------|---------------
**Tree I/O API** | [](https://search.maven.org/search?q=g:com.apicatalog%20AND%20a:tree-io-api) | [](https://javadoc.io/doc/com.apicatalog/tree-io-api)
Jakarta JSON API | [](https://search.maven.org/search?q=g:com.apicatalog%20AND%20a:tree-io-jakarta) | [](https://javadoc.io/doc/com.apicatalog/tree-io-jakarta)
Jackson 2 Tree Model | [](https://search.maven.org/search?q=g:com.apicatalog%20AND%20a:tree-io-jackson2) | [](https://javadoc.io/doc/com.apicatalog/tree-io-jackson2)
CBOR | [](https://search.maven.org/search?q=g:com.apicatalog%20AND%20a:tree-io-cbor) | [](https://javadoc.io/doc/com.apicatalog/tree-io-cbor)
## Examples
### High-Level Transformation
The most common use case is a full transformation from a source to a destination.
```javascript
// Have a source object (e.g., a Map) and a destination (e.g., a JsonGenerator)
Map source = Map.of("hello", "world");
JsonGenerator destination = ... ;
// Create an adapter for the source and a writer for the destination
var adapter = new NativeAdapter();
var jsonWriter = new Jackson2Writer(destination);
var cborWriter = new CborWriter(destination);
// Run the transformation with a single call
jsonWriter.node(source, adapter);
// or/and
cborWriter.node(source, adapter);
```
### Direct Node Inspection using NodeAdapter
Use a NodeAdapter directly when you need to read, inspect, or extract specific values from a tree structure without traversing the entire tree.
```javascript
// Given any 'node' object and a suitable 'adapter'...
// To inspect and process it safely:
// 1. Check for structural types first.
if (adapter.isMap(node)) {
// If it's a map, iterate its entries.
for (Entry, ?> entry : adapter.entries(node)) {
// ... process key and value recursively
}
} else if (adapter.isCollection(node)) {
// If it's a collection, iterate its elements.
for (Object element : adapter.elements(node)) {
// ... process element recursively
}
// 2. Then, check for scalar types.
} else if (adapter.isString(node)) {
String value = adapter.stringValue(node);
} else if (adapter.isNumber(node)) {
// For numbers, check for the specific type before extracting.
if (adapter.isIntegral(node)) {
long intValue = adapter.longValue(node);
} else {
BigDecimal decimalValue = adapter.decimalValue(node);
}
} else if (adapter.isNull(node)) {
// It's a null value.
}
```
### Manual Traversal using NodeVisitor
For complex processing like searching or validation, you can manually iterate through the tree using the step() method of a NodeVisitor.
```javascript
// Given a source object and a suitable adapter...
Object source = ... ;
NodeAdapter adapter = ... ;
// 1. Create the visitor instance.
NodeVisitor visitor = NodeVisitor.of(source, adapter);
// 2. Loop step-by-step through every node in the tree.
while (visitor.step()) {
// 3. Inspect the visitor's state after each step.
Object node = visitor.currentNode();
NodeType type = visitor.currentNodeType();
Context context = visitor.currentNodeContext();
// 4. Perform actions based on the node's role in the tree.
switch (context) {
case ROOT:
// Process the top-level node.
break;
case PROPERTY_KEY:
// The current node is a key in a map.
// The next step() will move to its value.
break;
case PROPERTY_VALUE:
// The current node is a value in a map.
break;
case COLLECTION_ELEMENT:
// The current node is an element in a collection.
break;
case END:
// A synthetic marker showing a map or collection has ended.
break;
}
}
```
## 📦 Artifacts
```xml
com.apicatalog
tree-io-api
${tree-io.version}
com.apicatalog
tree-io-jakarta
${tree-io.version}
com.apicatalog
tree-io-jackson2
${tree-io.version}
com.apicatalog
tree-io-cbor
${tree-io.version}
```
## 🤝 Contributing
Contributions are welcome! Please submit a pull request.
### Building
Fork and clone the repository, then build with Maven:
```bash
> cd tree-io
> mvn package
```
## 💼 Commercial Support
Commercial support and consulting are available.
For inquiries, please contact: filip26@gmail.com