CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-apache-groovy--groovy-json

JSON library for the Apache Groovy programming language providing JSON parsing, generation, and manipulation capabilities

Pending
Overview
Eval results
Files

low-level-processing.mddocs/

Low-level Processing

Token-based JSON processing for fine-grained control over parsing and custom JSON processing workflows.

Capabilities

JsonLexer

Streaming JSON lexer that tokenizes JSON input for low-level processing and custom parsing scenarios.

/**
 * Streaming JSON token lexer implementing Iterator<JsonToken>
 */
public class JsonLexer implements Iterator<JsonToken> {
    /** Constructor with Reader input */
    public JsonLexer(Reader reader);
    
    /** Get the underlying LineColumnReader */
    public LineColumnReader getReader();
    
    /** Get the next JSON token */
    public JsonToken nextToken();
    
    /** Skip whitespace characters and return count */
    public int skipWhitespace();
    
    /** Iterator interface: check if more tokens available */
    public boolean hasNext();
    
    /** Iterator interface: get next token */
    public JsonToken next();
    
    /** Iterator interface: remove operation (throws UnsupportedOperationException) */
    public void remove();
    
    /** Unescape JSON string content */
    public static String unescape(String input);
}

Usage Examples:

import groovy.json.JsonLexer;
import groovy.json.JsonToken;
import groovy.json.JsonTokenType;
import java.io.StringReader;

// Basic tokenization
String jsonInput = '{"name":"Alice","age":30,"active":true}';
JsonLexer lexer = new JsonLexer(new StringReader(jsonInput));

while (lexer.hasNext()) {
    JsonToken token = lexer.next();
    System.out.println("Type: " + token.getType() + 
                      ", Value: " + token.getValue() +
                      ", Position: " + token.getStartLine() + ":" + token.getStartColumn());
}

// Custom JSON validator
public boolean isValidJson(String json) {
    try {
        JsonLexer lexer = new JsonLexer(new StringReader(json));
        int depth = 0;
        boolean inObject = false, inArray = false;
        
        while (lexer.hasNext()) {
            JsonToken token = lexer.next();
            switch (token.getType()) {
                case OPEN_BRACE:
                    depth++;
                    inObject = true;
                    break;
                case CLOSE_BRACE:
                    depth--;
                    if (depth < 0) return false;
                    break;
                case OPEN_BRACKET:
                    depth++;
                    inArray = true;
                    break;
                case CLOSE_BRACKET:
                    depth--;
                    if (depth < 0) return false;
                    break;
            }
        }
        return depth == 0;
    } catch (Exception e) {
        return false;
    }
}

// Extract specific values by path
public Object extractJsonValue(String json, String[] path) {
    JsonLexer lexer = new JsonLexer(new StringReader(json));
    // Implementation for path-based extraction
    // ... custom logic using token stream
}

JsonToken

Represents a single JSON token with value, type, and position information.

/**
 * Represents a single JSON token with position and value information
 */
public class JsonToken {
    /** Get the parsed value of the token (Boolean, Number, String, or null) */
    public Object getValue();
    
    /** Get the token type */
    public JsonTokenType getType();
    public void setType(JsonTokenType type);
    
    /** Get/set the raw text content */
    public String getText();
    public void setText(String text);
    
    /** Position information - line numbers */
    public long getStartLine();
    public void setStartLine(long startLine);
    public long getEndLine();
    public void setEndLine(long endLine);
    
    /** Position information - column numbers */
    public long getStartColumn();
    public void setStartColumn(long startColumn);
    public long getEndColumn();
    public void setEndColumn(long endColumn);
    
    /** String representation of the token */
    public String toString();
}

Usage Examples:

// Token inspection and debugging
JsonToken token = lexer.nextToken();
if (token.getType() == JsonTokenType.STRING) {
    System.out.println("String token: '" + token.getValue() + "' at " +
                      token.getStartLine() + ":" + token.getStartColumn());
}

// Error reporting with position
if (token.getType() == JsonTokenType.STRING && !isValidEmail((String) token.getValue())) {
    throw new ValidationException("Invalid email at line " + token.getStartLine() + 
                                ", column " + token.getStartColumn());
}

JsonTokenType

Enumeration of all possible JSON token types with validation and matching capabilities.

/**
 * Enumeration of all JSON token types
 */
public enum JsonTokenType {
    /** Structural tokens */
    OPEN_CURLY,    // {
    CLOSE_CURLY,   // }
    OPEN_BRACKET,  // [
    CLOSE_BRACKET, // ]
    COLON,         // :
    COMMA,         // ,
    
    /** Literal value tokens */
    NULL,          // null
    TRUE,          // true  
    FALSE,         // false
    NUMBER,        // numeric values
    STRING,        // string values
    
    /** Check if input matches this token type pattern */
    public boolean matching(String input);
    
    /** Get descriptive label for this token type */
    public String getLabel();
    
    /** Get validator (String, Pattern, or Closure) */
    public Object getValidator();
    
    /** Find token type that starts with given character */
    public static JsonTokenType startingWith(char c);
}

Usage Examples:

// Token type checking
JsonToken token = lexer.nextToken();
switch (token.getType()) {
    case OPEN_BRACE:
        System.out.println("Starting object");
        break;
    case OPEN_BRACKET:
        System.out.println("Starting array");
        break;
    case STRING:
        System.out.println("String value: " + token.getValue());
        break;
    case NUMBER:
        System.out.println("Numeric value: " + token.getValue());
        break;
    case TRUE:
    case FALSE:
        System.out.println("Boolean value: " + token.getValue());
        break;
    case NULL:
        System.out.println("Null value");
        break;
}

// Token type pattern matching
String input = "true";
if (JsonTokenType.TRUE.matching(input)) {
    System.out.println("Input matches TRUE token");
}

// Find token type by starting character
JsonTokenType type = JsonTokenType.startingWith('{');
System.out.println("Token starting with '{': " + type); // OPEN_BRACE

Advanced Low-level Processing

Custom JSON Parser Implementation

import groovy.json.JsonLexer;
import groovy.json.JsonToken;
import groovy.json.JsonTokenType;

public class CustomJsonParser {
    private JsonLexer lexer;
    private JsonToken currentToken;
    
    public CustomJsonParser(Reader reader) {
        this.lexer = new JsonLexer(reader);
        advance();
    }
    
    private void advance() {
        currentToken = lexer.hasNext() ? lexer.next() : null;
    }
    
    private void expect(JsonTokenType expectedType) {
        if (currentToken == null || currentToken.getType() != expectedType) {
            throw new RuntimeException("Expected " + expectedType + 
                                     " but found " + 
                                     (currentToken != null ? currentToken.getType() : "EOF"));
        }
        advance();
    }
    
    public Object parseValue() {
        if (currentToken == null) {
            throw new RuntimeException("Unexpected end of input");
        }
        
        switch (currentToken.getType()) {
            case TRUE:
                advance();
                return true;
            case FALSE:
                advance();
                return false;
            case NULL:
                advance();
                return null;
            case STRING:
                String stringValue = (String) currentToken.getValue();
                advance();
                return stringValue;
            case NUMBER:
                Number numberValue = (Number) currentToken.getValue();
                advance();
                return numberValue;
            case OPEN_BRACE:
                return parseObject();
            case OPEN_BRACKET:
                return parseArray();
            default:
                throw new RuntimeException("Unexpected token: " + currentToken.getType());
        }
    }
    
    private Map<String, Object> parseObject() {
        Map<String, Object> object = new LinkedHashMap<>();
        expect(JsonTokenType.OPEN_BRACE);
        
        if (currentToken != null && currentToken.getType() == JsonTokenType.CLOSE_BRACE) {
            advance();
            return object;
        }
        
        do {
            if (currentToken == null || currentToken.getType() != JsonTokenType.STRING) {
                throw new RuntimeException("Expected string key");
            }
            String key = (String) currentToken.getValue();
            advance();
            
            expect(JsonTokenType.COLON);
            Object value = parseValue();
            object.put(key, value);
            
            if (currentToken != null && currentToken.getType() == JsonTokenType.COMMA) {
                advance();
            } else {
                break;
            }
        } while (true);
        
        expect(JsonTokenType.CLOSE_BRACE);
        return object;
    }
    
    private List<Object> parseArray() {
        List<Object> array = new ArrayList<>();
        expect(JsonTokenType.OPEN_BRACKET);
        
        if (currentToken != null && currentToken.getType() == JsonTokenType.CLOSE_BRACKET) {
            advance();
            return array;
        }
        
        do {
            array.add(parseValue());
            
            if (currentToken != null && currentToken.getType() == JsonTokenType.COMMA) {
                advance();
            } else {
                break;
            }
        } while (true);
        
        expect(JsonTokenType.CLOSE_BRACKET);
        return array;
    }
}

JSON Stream Processor

// Process large JSON streams without loading entire document
public class JsonStreamProcessor {
    public void processJsonStream(Reader reader, StreamHandler handler) {
        JsonLexer lexer = new JsonLexer(reader);
        Stack<String> path = new Stack<>();
        
        while (lexer.hasNext()) {
            JsonToken token = lexer.next();
            
            switch (token.getType()) {
                case OPEN_BRACE:
                    handler.startObject(getCurrentPath(path));
                    break;
                case CLOSE_BRACE:
                    handler.endObject(getCurrentPath(path));
                    if (!path.isEmpty()) path.pop();
                    break;
                case OPEN_BRACKET:
                    handler.startArray(getCurrentPath(path));
                    break;
                case CLOSE_BRACKET:
                    handler.endArray(getCurrentPath(path));
                    if (!path.isEmpty()) path.pop();
                    break;
                case STRING:
                    if (isPropertyName(lexer)) {
                        path.push((String) token.getValue());
                    } else {
                        handler.stringValue(getCurrentPath(path), (String) token.getValue());
                    }
                    break;
                case NUMBER:
                    handler.numberValue(getCurrentPath(path), (Number) token.getValue());
                    break;
                case TRUE:
                case FALSE:
                    handler.booleanValue(getCurrentPath(path), (Boolean) token.getValue());
                    break;
                case NULL:
                    handler.nullValue(getCurrentPath(path));
                    break;
            }
        }
    }
    
    private String getCurrentPath(Stack<String> path) {
        return String.join(".", path);
    }
    
    interface StreamHandler {
        void startObject(String path);
        void endObject(String path);
        void startArray(String path);
        void endArray(String path);
        void stringValue(String path, String value);
        void numberValue(String path, Number value);
        void booleanValue(String path, Boolean value);
        void nullValue(String path);
    }
}

JSON Validation with Error Location

public class JsonValidator {
    public static class ValidationError {
        private final String message;
        private final long line;
        private final long column;
        
        public ValidationError(String message, JsonToken token) {
            this.message = message;
            this.line = token.getStartLine();
            this.column = token.getStartColumn();
        }
        
        public String getMessage() { return message; }
        public long getLine() { return line; }
        public long getColumn() { return column; }
        
        @Override
        public String toString() {
            return String.format("%s at line %d, column %d", message, line, column);
        }
    }
    
    public static List<ValidationError> validate(String json) {
        List<ValidationError> errors = new ArrayList<>();
        
        try {
            JsonLexer lexer = new JsonLexer(new StringReader(json));
            Stack<JsonTokenType> stack = new Stack<>();
            
            while (lexer.hasNext()) {
                JsonToken token = lexer.next();
                
                switch (token.getType()) {
                    case OPEN_BRACE:
                        stack.push(JsonTokenType.OPEN_BRACE);
                        break;
                    case CLOSE_BRACE:
                        if (stack.isEmpty() || stack.pop() != JsonTokenType.OPEN_BRACE) {
                            errors.add(new ValidationError("Unmatched closing brace", token));
                        }
                        break;
                    case OPEN_BRACKET:
                        stack.push(JsonTokenType.OPEN_BRACKET);
                        break;
                    case CLOSE_BRACKET:
                        if (stack.isEmpty() || stack.pop() != JsonTokenType.OPEN_BRACKET) {
                            errors.add(new ValidationError("Unmatched closing bracket", token));
                        }
                        break;
                }
            }
            
            if (!stack.isEmpty()) {
                errors.add(new ValidationError("Unclosed " + 
                    (stack.peek() == JsonTokenType.OPEN_BRACE ? "object" : "array"), null));
            }
            
        } catch (Exception e) {
            errors.add(new ValidationError("Parse error: " + e.getMessage(), null));
        }
        
        return errors;
    }
}

Performance Considerations

Memory-Efficient Processing

// Process large JSON files without loading into memory
public void processLargeJsonFile(File jsonFile) throws IOException {
    try (FileReader reader = new FileReader(jsonFile);
         BufferedReader buffered = new BufferedReader(reader)) {
        
        JsonLexer lexer = new JsonLexer(buffered);
        
        // Process tokens as they're read
        while (lexer.hasNext()) {
            JsonToken token = lexer.next();
            processToken(token);
            
            // Periodically yield to prevent blocking
            if (Thread.interrupted()) {
                throw new InterruptedException("Processing interrupted");
            }
        }
    }
}

Token Filtering and Optimization

// Skip unwanted tokens for performance
public List<String> extractStringValues(String json) {
    List<String> strings = new ArrayList<>();
    JsonLexer lexer = new JsonLexer(new StringReader(json));
    
    while (lexer.hasNext()) {
        JsonToken token = lexer.next();
        if (token.getType() == JsonTokenType.STRING) {
            strings.add((String) token.getValue());
        }
        // Skip other token types for performance
    }
    
    return strings;
}

Install with Tessl CLI

npx tessl i tessl/maven-org-apache-groovy--groovy-json

docs

index.md

json-building.md

json-output.md

json-parsing.md

low-level-processing.md

utilities.md

tile.json