CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-apache-avro--avro-compiler

Compilers for Avro IDL and Avro Specific Java API - provides code generation tools for converting Avro schemas and IDL definitions into Java classes

Pending
Overview
Eval results
Files

schema-utilities.mddocs/

Schema Utilities

Utility functions for schema traversal, cloning, manipulation operations, and the visitor pattern for custom schema processing.

Capabilities

Schemas Utility Class

Static utility methods for common schema operations.

/**
 * Avro Schema utilities, to traverse and manipulate schemas.
 * All methods are static and thread-safe.
 */
public final class Schemas {
    
    /**
     * Copy aliases from one schema to another (only for named types: RECORD, ENUM, FIXED)
     * @param from Source schema
     * @param to Destination schema
     */
    public static void copyAliases(Schema from, Schema to);
    
    /**
     * Copy aliases from one field to another
     * @param from Source field
     * @param to Destination field
     */
    public static void copyAliases(Schema.Field from, Schema.Field to);
    
    /**
     * Copy logical types from one schema to another
     * @param from Source schema with logical type
     * @param to Destination schema
     */
    public static void copyLogicalTypes(Schema from, Schema to);
    
    /**
     * Copy properties from one JsonProperties object to another
     * @param from Source properties
     * @param to Destination properties
     */
    public static void copyProperties(JsonProperties from, JsonProperties to);
    
    /**
     * Check if schema generates a Java class (ENUM, RECORD, FIXED types)
     * @param schema Schema to check
     * @return true if schema generates Java class
     */
    public static boolean hasGeneratedJavaClass(Schema schema);
    
    /**
     * Get the Java class name for a schema
     * @param schema Schema to get class name for
     * @return Fully qualified Java class name
     */
    public static String getJavaClassName(Schema schema);
    
    /**
     * Depth-first visit of schema tree using visitor pattern
     * @param start Starting schema for traversal
     * @param visitor Visitor implementation
     * @return Result from visitor.get()
     */
    public static <T> T visit(Schema start, SchemaVisitor<T> visitor);
}

SchemaVisitor Interface

Visitor pattern interface for custom schema processing and traversal.

/**
 * Visitor pattern interface for schema traversal.
 * Generic type T represents the result type of the visit operation.
 */
public interface SchemaVisitor<T> {
    
    /**
     * Invoked for schemas that do not have "child" schemas (like string, int ...)
     * or for a previously encountered schema with children, which will be treated
     * as a terminal to avoid circular recursion.
     * @param terminal Terminal schema node
     * @return Action to control traversal
     */
    SchemaVisitorAction visitTerminal(Schema terminal);
    
    /**
     * Invoked for schema with children before proceeding to visit the children.
     * @param nonTerminal Non-terminal schema node
     * @return Action to control traversal
     */
    SchemaVisitorAction visitNonTerminal(Schema nonTerminal);
    
    /**
     * Invoked for schemas with children after its children have been visited.
     * @param nonTerminal Non-terminal schema node after visiting children
     * @return Action to control traversal
     */
    SchemaVisitorAction afterVisitNonTerminal(Schema nonTerminal);
    
    /**
     * Invoked when visiting is complete.
     * @return Final result of the visit operation
     */
    T get();
}

SchemaVisitorAction Enum

Controls the flow of schema traversal operations.

/**
 * Actions for controlling schema traversal behavior
 */
public enum SchemaVisitorAction {
    /** Continue normal traversal */
    CONTINUE,
    
    /** Skip the current subtree but continue with siblings */
    SKIP_SUBTREE,
    
    /** Skip remaining siblings at current level */
    SKIP_SIBLINGS,
    
    /** Terminate the entire traversal immediately */
    TERMINATE
}

CloningVisitor Class

Built-in visitor implementation for cloning schemas with customizable property copying.

/**
 * Visitor implementation for cloning schemas.
 * Creates a clone of the original Schema with docs and other nonessential 
 * fields stripped by default. What attributes are copied is customizable.
 */
public final class CloningVisitor implements SchemaVisitor<Schema> {
    
    /** Interface for customizing property copying behavior */
    public interface PropertyCopier {
        void copy(Schema first, Schema second);
        void copy(Schema.Field first, Schema.Field second);
    }
    
    /** 
     * Create cloning visitor that copies only serialization necessary fields
     * @param root Root schema to clone
     */
    public CloningVisitor(Schema root);
    
    /**
     * Create cloning visitor with custom property copying behavior
     * @param copyProperties Custom property copier
     * @param copyDocs Whether to copy documentation
     * @param root Root schema to clone
     */
    public CloningVisitor(PropertyCopier copyProperties, boolean copyDocs, Schema root);
}

ResolvingVisitor Class

Visitor implementation for resolving schema references in IDL contexts.

/**
 * Visitor for resolving unresolved schema references.
 * Used primarily in IDL processing contexts.
 */
public final class ResolvingVisitor implements SchemaVisitor<Schema> {
    
    /**
     * Create resolving visitor
     * @param root Root schema
     * @param replace Map of schemas to replace
     * @param symbolTable Function to resolve symbol names to schemas
     */
    public ResolvingVisitor(Schema root, IdentityHashMap<Schema, Schema> replace,
                           Function<String, Schema> symbolTable);
}

IsResolvedSchemaVisitor Class

Visitor to check if a schema is fully resolved (no unresolved references).

/**
 * Visitor that checks if the current schema is fully resolved.
 * Returns true if schema has no unresolved parts.
 */
public final class IsResolvedSchemaVisitor implements SchemaVisitor<Boolean> {
    
    /** Create visitor to check schema resolution status */
    IsResolvedSchemaVisitor();
}

Usage Examples

Basic Schema Utilities

import org.apache.avro.Schema;
import org.apache.avro.compiler.schema.Schemas;

// Check if schema generates Java class
Schema userSchema = new Schema.Parser().parse(new File("user.avsc"));
boolean hasClass = Schemas.hasGeneratedJavaClass(userSchema);  // true for RECORD

Schema stringSchema = Schema.create(Schema.Type.STRING);
boolean hasClass2 = Schemas.hasGeneratedJavaClass(stringSchema);  // false

// Get Java class name
String className = Schemas.getJavaClassName(userSchema);
// Returns: "com.example.User" (if namespace is com.example)

Schema Property Copying

import org.apache.avro.Schema;
import org.apache.avro.compiler.schema.Schemas;

// Copy aliases between schemas
Schema originalSchema = /* ... */;
Schema clonedSchema = /* ... */;

Schemas.copyAliases(originalSchema, clonedSchema);
Schemas.copyLogicalTypes(originalSchema, clonedSchema);
Schemas.copyProperties(originalSchema, clonedSchema);

Custom Schema Visitor

import org.apache.avro.Schema;
import org.apache.avro.compiler.schema.*;

// Count all record schemas in a complex schema
public class RecordCountingVisitor implements SchemaVisitor<Integer> {
    private int recordCount = 0;
    
    @Override
    public SchemaVisitorAction visitTerminal(Schema terminal) {
        if (terminal.getType() == Schema.Type.RECORD) {
            recordCount++;
        }
        return SchemaVisitorAction.CONTINUE;
    }
    
    @Override
    public SchemaVisitorAction visitNonTerminal(Schema nonTerminal) {
        if (nonTerminal.getType() == Schema.Type.RECORD) {
            recordCount++;
        }
        return SchemaVisitorAction.CONTINUE;
    }
    
    @Override
    public SchemaVisitorAction afterVisitNonTerminal(Schema nonTerminal) {
        return SchemaVisitorAction.CONTINUE;
    }
    
    @Override
    public Integer get() {
        return recordCount;
    }
}

// Usage
Schema complexSchema = /* ... */;
Integer recordCount = Schemas.visit(complexSchema, new RecordCountingVisitor());
System.out.println("Found " + recordCount + " record schemas");

Schema Name Collection Visitor

import java.util.*;

// Collect all named schema types
public class NameCollectingVisitor implements SchemaVisitor<Set<String>> {
    private Set<String> names = new HashSet<>();
    
    @Override
    public SchemaVisitorAction visitTerminal(Schema terminal) {
        if (terminal.getName() != null) {
            names.add(terminal.getFullName());
        }
        return SchemaVisitorAction.CONTINUE;
    }
    
    @Override
    public SchemaVisitorAction visitNonTerminal(Schema nonTerminal) {
        if (nonTerminal.getName() != null) {
            names.add(nonTerminal.getFullName());
        }
        return SchemaVisitorAction.CONTINUE;
    }
    
    @Override
    public SchemaVisitorAction afterVisitNonTerminal(Schema nonTerminal) {
        return SchemaVisitorAction.CONTINUE;
    }
    
    @Override
    public Set<String> get() {
        return names;
    }
}

// Usage
Set<String> schemaNames = Schemas.visit(schema, new NameCollectingVisitor());

Conditional Traversal Control

// Visitor that stops at first error type encountered
public class ErrorFindingVisitor implements SchemaVisitor<Schema> {
    private Schema errorSchema = null;
    
    @Override
    public SchemaVisitorAction visitTerminal(Schema terminal) {
        if (terminal.getType() == Schema.Type.RECORD && 
            terminal.getName().endsWith("Error")) {
            errorSchema = terminal;
            return SchemaVisitorAction.TERMINATE;  // Stop immediately
        }
        return SchemaVisitorAction.CONTINUE;
    }
    
    @Override
    public SchemaVisitorAction visitNonTerminal(Schema nonTerminal) {
        if (nonTerminal.getType() == Schema.Type.UNION) {
            // Skip all union types and their children
            return SchemaVisitorAction.SKIP_SUBTREE;
        }
        return SchemaVisitorAction.CONTINUE;
    }
    
    @Override
    public SchemaVisitorAction afterVisitNonTerminal(Schema nonTerminal) {
        return SchemaVisitorAction.CONTINUE;
    }
    
    @Override
    public Schema get() {
        return errorSchema;
    }
}

Schema Cloning

import org.apache.avro.compiler.schema.CloningVisitor;

// Clone a schema structure (default: copy only essential fields)
Schema originalSchema = /* ... */;
Schema clonedSchema = Schemas.visit(originalSchema, new CloningVisitor(originalSchema));

// Clone with custom property copying
CloningVisitor.PropertyCopier customCopier = new CloningVisitor.PropertyCopier() {
    @Override
    public void copy(Schema first, Schema second) {
        Schemas.copyAliases(first, second);
        Schemas.copyLogicalTypes(first, second);
        // Copy custom properties
        first.forEachProperty(second::addProp);
    }
    
    @Override
    public void copy(Schema.Field first, Schema.Field second) {
        Schemas.copyAliases(first, second);
    }
};

Schema clonedWithDocs = Schemas.visit(originalSchema, 
    new CloningVisitor(customCopier, true, originalSchema));

Schema Resolution Checking

import org.apache.avro.compiler.idl.IsResolvedSchemaVisitor;

// Check if schema is fully resolved (no unresolved references)
Schema schema = /* ... */;
Boolean isResolved = Schemas.visit(schema, new IsResolvedSchemaVisitor());

if (isResolved) {
    System.out.println("Schema is fully resolved");
} else {
    System.out.println("Schema has unresolved references");
}

Schema Reference Resolution

import org.apache.avro.compiler.idl.ResolvingVisitor;
import java.util.*;
import java.util.function.Function;

// Resolve schema references using symbol table
IdentityHashMap<Schema, Schema> replacements = new IdentityHashMap<>();
Function<String, Schema> symbolTable = schemaName -> {
    // Look up schema by name in symbol table
    return findSchemaByName(schemaName);
};

Schema unresolvedSchema = /* ... */;
Schema resolvedSchema = Schemas.visit(unresolvedSchema, 
    new ResolvingVisitor(unresolvedSchema, replacements, symbolTable));

Field Alias Copying

// Copy aliases between record fields
Schema.Field originalField = /* ... */;
Schema.Field newField = /* ... */;

Schemas.copyAliases(originalField, newField);
// Now newField has all the aliases from originalField

Traversal Behavior

The Schemas.visit() method performs depth-first traversal with these characteristics:

  • Circular Reference Handling: Previously visited schemas are treated as terminals to avoid infinite recursion
  • Order: Array elements, record fields, union types, and map values are visited in definition order
  • State Management: Visitor maintains its own state across the traversal
  • Early Termination: TERMINATE action stops traversal immediately and returns current result
  • Subtree Skipping: SKIP_SUBTREE skips children but continues with siblings
  • Sibling Skipping: SKIP_SIBLINGS skips remaining siblings at current level

Thread Safety

  • All Schemas utility methods are thread-safe
  • SchemaVisitor implementations should be designed for single-threaded use
  • Each visitor instance should be used for only one traversal operation

Install with Tessl CLI

npx tessl i tessl/maven-org-apache-avro--avro-compiler

docs

build-integration.md

configuration.md

index.md

protocol-code-generation.md

schema-code-generation.md

schema-utilities.md

tile.json