An open API service indexing awesome lists of open source software.

https://github.com/inqwise/inqwise-walker

A convenient and powerful object walker for Java, designed to traverse complex object graphs with ease. It provides a simple, event-driven API for navigating nested structures, making it ideal for data processing, validation, and transformation tasks.
https://github.com/inqwise/inqwise-walker

event-driven java library object-traversal object-walker reactive vertx

Last synced: 5 months ago
JSON representation

A convenient and powerful object walker for Java, designed to traverse complex object graphs with ease. It provides a simple, event-driven API for navigating nested structures, making it ideal for data processing, validation, and transformation tasks.

Awesome Lists containing this project

README

          

= Inqwise Walker - Object Traversal Framework
:toc:
:toclevels: 3
:source-highlighter: highlight.js
:icons: font

image:https://github.com/inqwise/inqwise-walker/actions/workflows/ci.yml/badge.svg[CI, link=https://github.com/inqwise/inqwise-walker/actions/workflows/ci.yml]
image:https://github.com/inqwise/inqwise-walker/actions/workflows/release.yml/badge.svg[Release, link=https://github.com/inqwise/inqwise-walker/actions/workflows/release.yml]
image:https://github.com/inqwise/inqwise-walker/actions/workflows/codeql.yml/badge.svg[CodeQL, link=https://github.com/inqwise/inqwise-walker/actions/workflows/codeql.yml]
image:https://codecov.io/gh/inqwise/inqwise-walker/branch/main/graph/badge.svg[Codecov, link=https://codecov.io/gh/inqwise/inqwise-walker]
image:https://snyk.io/test/github/inqwise/inqwise-walker/badge.svg[Snyk Security, link=https://snyk.io/test/github/inqwise/inqwise-walker]
image:https://img.shields.io/maven-central/v/com.inqwise/inqwise-walker.svg?label=Maven%20Central[Maven Central, link=https://search.maven.org/search?q=g:%22com.inqwise%22%20AND%20a:%22inqwise-walker%22]
image:https://img.shields.io/badge/License-MIT-yellow.svg[License: MIT, link=https://opensource.org/licenses/MIT]
image:https://img.shields.io/badge/Java-21%2B-blue.svg[Java Version, link=https://openjdk.java.net/projects/jdk/21/]

A powerful and flexible Java library for traversing complex object hierarchies with event-driven processing.

== Overview

Inqwise Walker provides a framework for walking through object structures with customizable event handlers, flow control, and extensible walker implementations. It's particularly useful for processing JSON data, nested objects, and implementing visitor patterns.

=== Key Features

* ๐Ÿ”„ **Event-driven processing** with customizable handlers
* ๐Ÿ—๏ธ **Extensible architecture** - create custom walkers for any object type
* ๐ŸŽฎ **Flow control** - pause, resume, and early termination
* ๐Ÿ›ก๏ธ **Error handling** with success/failure callbacks
* ๐Ÿ“ **Path tracking** - know exactly where you are in the object hierarchy
* ๐Ÿงต **Thread-safe operations** for concurrent access
* ๐Ÿ“Š **Context data sharing** between processing stages

== Quick Start

=== Maven Dependency

[source,xml]
----

com.inqwise
inqwise-walker
${latest.version}

----

=== Basic Usage

[source,java]
----
import com.inqwise.walker.*;
import io.vertx.core.json.JsonObject;
import io.vertx.core.json.JsonArray;

// Create a JSON structure
JsonObject person = new JsonObject()
.put("name", "John Doe")
.put("age", 30)
.put("address", new JsonObject()
.put("street", "123 Main St")
.put("city", "New York"))
.put("hobbies", new JsonArray()
.add("reading")
.add("swimming"));

// Create walker with nested support
JsonObjectWalker walker = JsonObjectWalker.instance();

// Add event handler
walker.handler(event -> {
String path = event.meta().get(ObjectWalker.Keys.PATH).toString();
Object value = event.indicatedObject();
System.out.println("Path: " + path + " -> Value: " + value);
});

// Start walking
ObjectWalkingContext context = walker.handle(person);
System.out.println("Success: " + context.success());
----

== Architecture

=== Core Components

==== ObjectWalker (Abstract Base Class)
The foundation of the framework providing:

* Walker registration and delegation
* Event handler management
* Flow control coordination
* Error handling infrastructure

==== Built-in Walkers

[cols="1,3"]
|===
|Walker |Description

|`JsonObjectWalker`
|Traverses Vert.x JsonObject instances with path tracking

|`JsonArrayWalker`
|Processes JsonArray elements with indexed paths

|`DifferencesWalker`
|Handles difference objects from inqwise-difference library
|===

==== Context Management

* **ObjectWalkingContext**: Manages walking state, flow control, and data storage
* **ObjectWalkingEvent**: Provides event information and control methods
* **IndicatedItem**: Wraps objects with metadata during processing

=== Processing Flow

[source]
----
ObjectWalker.handle(object)
โ†“
Create ObjectWalkingContext
โ†“
For each object in hierarchy:
โ†“
Generate ObjectWalkingEvent
โ†“
Call registered event handlers
โ†“
Delegate to appropriate walker
โ†“
Continue until complete or terminated
----

== Advanced Features

=== Custom Walker Implementation

Create walkers for your own data types:

[source,java]
----
public class PersonWalker extends ObjectWalker {
public PersonWalker() {
super(null);
}

@Override
protected Class> type() {
return Person.class;
}

@Override
protected Iterator createObjectIterator(
IndicatedItem item, ObjectWalkingContext context) {
Person person = (Person) item.value();
String basePath = item.meta().getOrDefault(Keys.PATH, ".").toString();

return List.of(
item.newSubItem(person.getName()).put(Keys.PATH, basePath + ".name"),
item.newSubItem(person.getAge()).put(Keys.PATH, basePath + ".age")
).iterator();
}
}
----

=== Flow Control

[source,java]
----
walker.handler(event -> {
String path = event.meta().get(ObjectWalker.Keys.PATH).toString();

// Pause processing
if (path.equals(".metadata")) {
event.context().pause();
// Do some async work...
event.context().resume();
}

// Early termination
if (path.equals(".stop-here")) {
event.end();
}
});
----

=== Context Data Sharing

[source,java]
----
walker.handler(event -> {
String path = event.meta().get(ObjectWalker.Keys.PATH).toString();
Object value = event.indicatedObject();

// Store data in context
if (path.contains("user")) {
event.context().put("userCount",
(Integer) event.context().get("userCount") + 1);
}
});

// Access shared data after walking
Integer userCount = context.get("userCount");
----

=== Error Handling

[source,java]
----
walker.handler(event -> {
// Processing that might throw exceptions
if (someCondition) {
throw new RuntimeException("Processing error");
}
});

walker.errorHandler(context -> {
System.err.println("Error: " + context.cause().getMessage());
System.err.println("Failed at level: " + context.levelIndex());
});

walker.endHandler(context -> {
if (context.success()) {
System.out.println("Walking completed successfully");
}
});
----

== Use Cases

=== Data Validation
Walk through complex objects to validate structure and values:

[source,java]
----
walker.handler(event -> {
String path = event.meta().get(ObjectWalker.Keys.PATH).toString();
Object value = event.indicatedObject();

if (path.endsWith(".email") && !isValidEmail(value.toString())) {
throw new ValidationException("Invalid email at " + path);
}
});
----

=== Data Transformation
Convert objects from one format to another:

[source,java]
----
Map result = new HashMap<>();

walker.handler(event -> {
String path = event.meta().get(ObjectWalker.Keys.PATH).toString();
Object value = event.indicatedObject();

// Transform field names and values
String transformedPath = transformPath(path);
Object transformedValue = transformValue(value);

result.put(transformedPath, transformedValue);
});
----

=== Metrics Collection
Gather statistics about object structures:

[source,java]
----
AtomicInteger fieldCount = new AtomicInteger(0);
AtomicInteger arrayCount = new AtomicInteger(0);
AtomicInteger objectCount = new AtomicInteger(0);

walker.handler(event -> {
fieldCount.incrementAndGet();

if (event.hasWalker()) {
if (event.getWalker() instanceof JsonArrayWalker) {
arrayCount.incrementAndGet();
} else if (event.getWalker() instanceof JsonObjectWalker) {
objectCount.incrementAndGet();
}
}
});
----

== Building and Testing

=== Prerequisites
* Java 21+
* Maven 3.6.3+

=== Build Commands

[source,bash]
----
# Compile the project
mvn compile

# Run tests
mvn test

# Create JAR
mvn package

# Install to local repository
mvn install
----

=== Running Examples

[source,bash]
----
# Compile and run usage examples
mvn exec:java -Dexec.mainClass="com.inqwise.walker.example.WalkerUsageExample"
----

== Dependencies

The library has minimal runtime dependencies:

* **Vert.x Core** (5.0.4) - For JSON processing (provided scope)
* **Google Guava** (33.4.0-jre) - For collections utilities (provided scope)
* **Apache Log4j** (2.25.2) - For logging (api required, core provided)
* **Inqwise Difference** (1.1.6) - For difference processing (provided scope)

Test dependencies include JUnit 5.11.3 and Vert.x test utilities.

== Contributing

We welcome contributions! Please see our link:CONTRIBUTING.md[contributing guidelines] for details on:

* Code style and conventions
* Submitting issues and feature requests
* Creating pull requests
* Running tests locally

== License

This project is licensed under the MIT License - see the link:LICENSE[LICENSE] file for details.

== Support

* **Documentation**: Check this README and the link:WalkerUsageExample.java[usage examples]
* **Issues**: Report bugs and request features on link:https://github.com/inqwise/inqwise-walker/issues[GitHub Issues]
* **Discussions**: Ask questions on link:https://github.com/inqwise/inqwise-walker/discussions[GitHub Discussions]

---

Built with โค๏ธ by the link:https://www.inqwise.com[Inqwise] team.