CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-net-minidev--json-smart

JSON Small and Fast Parser - A lightweight, high-performance JSON processing library for Java

Pending
Overview
Eval results
Files

parsing.mddocs/

Advanced JSON Parsing

JSON-Smart provides powerful and configurable parsing capabilities through the JSONParser class and MultipleJsonParser for streaming scenarios. This document covers advanced parsing features, configuration options, and error handling.

JSONParser - Configurable Parsing

JSONParser offers fine-grained control over parsing behavior through various modes and flags.

Parser Mode Constants

Parsing Flags

public static final int ACCEPT_SIMPLE_QUOTE = 1;
public static final int ACCEPT_NON_QUOTE = 2;
public static final int ACCEPT_NAN = 4;
public static final int IGNORE_CONTROL_CHAR = 8;
public static final int USE_INTEGER_STORAGE = 16;
public static final int ACCEPT_LEADING_ZERO = 32;
public static final int ACCEPT_USELESS_COMMA = 64;
public static final int USE_HI_PRECISION_FLOAT = 128;
public static final int ACCEPT_TAILLING_DATA = 256;
public static final int ACCEPT_TAILLING_SPACE = 512;
public static final int REJECT_127_CHAR = 1024;
public static final int BIG_DIGIT_UNRESTRICTED = 2048;
public static final int LIMIT_JSON_DEPTH = 4096;
public static final int ACCEPT_INCOMPLETE = 8192;

Individual flags that control specific parsing behaviors:

  • ACCEPT_SIMPLE_QUOTE: Allow single quotes for strings ('hello')
  • ACCEPT_NON_QUOTE: Allow unquoted strings ({key: value})
  • ACCEPT_NAN: Parse NaN and Infinity values
  • IGNORE_CONTROL_CHAR: Ignore control characters in strings
  • USE_INTEGER_STORAGE: Use int instead of long when possible
  • ACCEPT_LEADING_ZERO: Allow numbers with leading zeros (007)
  • ACCEPT_USELESS_COMMA: Allow trailing commas ([1,2,3,])
  • USE_HI_PRECISION_FLOAT: Use BigDecimal for floating-point numbers
  • ACCEPT_TAILLING_DATA: Allow extra data after JSON
  • ACCEPT_TAILLING_SPACE: Allow trailing whitespace
  • REJECT_127_CHAR: Reject ASCII character 127
  • BIG_DIGIT_UNRESTRICTED: Use double for large numbers
  • LIMIT_JSON_DEPTH: Limit nesting depth (default enabled)
  • ACCEPT_INCOMPLETE: Support streaming/incomplete JSON

Preset Modes

public static final int MODE_PERMISSIVE;
public static final int MODE_PERMISSIVE_WITH_INCOMPLETE;
public static final int MODE_RFC4627;
public static final int MODE_JSON_SIMPLE;
public static final int MODE_STRICTEST;
public static int DEFAULT_PERMISSIVE_MODE;

Predefined combinations of flags for common use cases:

  • MODE_PERMISSIVE: Fast, flexible parsing (default)
  • MODE_PERMISSIVE_WITH_INCOMPLETE: Permissive + streaming support
  • MODE_RFC4627: Strict RFC4627 compliance
  • MODE_JSON_SIMPLE: Compatibility with json-simple library
  • MODE_STRICTEST: Most restrictive parsing

Constructors

public JSONParser();
public JSONParser(int permissiveMode);

Create parser instances with default or custom modes.

// Default permissive parser
JSONParser parser = new JSONParser();

// Strict RFC4627 parser
JSONParser strictParser = new JSONParser(JSONParser.MODE_RFC4627);

// Custom mode with specific flags
int customMode = JSONParser.ACCEPT_SIMPLE_QUOTE | JSONParser.ACCEPT_USELESS_COMMA;
JSONParser customParser = new JSONParser(customMode);

// Streaming parser
JSONParser streamParser = new JSONParser(JSONParser.MODE_PERMISSIVE_WITH_INCOMPLETE);

Parsing Methods

Basic Parsing

public Object parse(String in) throws ParseException;
public Object parse(Reader in) throws ParseException, IOException;
public Object parse(InputStream in) throws ParseException, IOException;
public Object parse(byte[] in) throws ParseException;

Parse JSON from various input sources.

JSONParser parser = new JSONParser(JSONParser.MODE_PERMISSIVE);

// Parse string with single quotes (permissive mode)
Object obj1 = parser.parse("{'name': 'John', 'age': 30}");

// Parse with trailing comma (permissive mode)
Object obj2 = parser.parse("[1, 2, 3,]");

// Strict parser rejects malformed JSON
JSONParser strict = new JSONParser(JSONParser.MODE_RFC4627);
try {
    strict.parse("{'name': 'John'}"); // Throws ParseException
} catch (ParseException e) {
    System.out.println("Strict parsing failed: " + e.getMessage());
}

Parsing with Custom Mappers

public Object parse(String in, JsonReaderI<?> mapper) throws ParseException;
public <T> T parse(String in, JsonReaderI<T> mapper) throws ParseException;
public <T> T parse(Reader in, JsonReaderI<T> mapper) throws ParseException, IOException;
public <T> T parse(InputStream in, JsonReaderI<T> mapper) throws ParseException, IOException;
public <T> T parse(byte[] in, JsonReaderI<T> mapper) throws ParseException;

Parse with custom deserialization logic.

// Custom mapper for dates
JsonReaderI<LocalDate> dateMapper = new JsonReaderI<LocalDate>(new JsonReader()) {
    @Override
    public LocalDate convert(Object current) {
        if (current instanceof String) {
            return LocalDate.parse((String) current);
        }
        return null;
    }
};

JSONParser parser = new JSONParser();
LocalDate date = parser.parse("\"2023-10-15\"", dateMapper);

Parser Mode Examples

Permissive Mode Features

JSONParser permissive = new JSONParser(JSONParser.MODE_PERMISSIVE);

// Single quotes
Object obj1 = permissive.parse("{'name': 'John'}");

// Unquoted keys  
Object obj2 = permissive.parse("{name: 'John'}");

// Trailing commas
Object obj3 = permissive.parse("[1, 2, 3,]");
Object obj4 = permissive.parse("{'a': 1, 'b': 2,}");

// Leading zeros
Object obj5 = permissive.parse("{\"count\": 007}");

// Special numbers
Object obj6 = permissive.parse("{\"value\": NaN, \"max\": Infinity}");

// Extra data after JSON (ignored)
Object obj7 = permissive.parse("{\"valid\": true} extra data here");

Strict RFC4627 Mode

JSONParser strict = new JSONParser(JSONParser.MODE_RFC4627);

// Valid RFC4627 JSON
Object valid = strict.parse("{\"name\": \"John\", \"age\": 30}");

// These will throw ParseException in strict mode:
try {
    strict.parse("{'name': 'John'}");          // Single quotes not allowed
    strict.parse("{name: 'John'}");            // Unquoted keys not allowed
    strict.parse("[1, 2, 3,]");                // Trailing commas not allowed
    strict.parse("{\"count\": 007}");          // Leading zeros not allowed
    strict.parse("{\"value\": NaN}");          // NaN not allowed
} catch (ParseException e) {
    System.out.println("Strict parsing error: " + e.getMessage());
}

Custom Mode Configuration

// Create custom mode for specific needs
int webApiMode = JSONParser.ACCEPT_SIMPLE_QUOTE |      // Allow single quotes
                 JSONParser.ACCEPT_USELESS_COMMA |      // Allow trailing commas  
                 JSONParser.USE_HI_PRECISION_FLOAT |    // Use BigDecimal
                 JSONParser.ACCEPT_TAILLING_SPACE;      // Allow trailing spaces

JSONParser webParser = new JSONParser(webApiMode);

// High precision numbers
Object result = webParser.parse("{'price': 123.456789012345678901234567890,}");
JSONObject obj = (JSONObject) result;
BigDecimal price = (BigDecimal) obj.get("price"); // Maintains full precision

MultipleJsonParser - Streaming Support

MultipleJsonParser handles multiple JSON values in a single input stream, separated by whitespace.

Constructors

public MultipleJsonParser(String in, int permissiveMode);
public MultipleJsonParser(Reader in, int permissiveMode);
public MultipleJsonParser(InputStream in, int permissiveMode);
public MultipleJsonParser(byte[] in, int permissiveMode);

Create streaming parsers for various input sources.

// Multiple JSON objects in string
String multiJson = """
    {"name": "Alice"}
    {"name": "Bob"}
    {"name": "Charlie"}
    [1, 2, 3]
    "simple string"
    42
    true
    """;

MultipleJsonParser multiParser = new MultipleJsonParser(multiJson, JSONParser.MODE_PERMISSIVE);

// Stream from file
FileReader reader = new FileReader("multi.json");
MultipleJsonParser fileParser = new MultipleJsonParser(reader, JSONParser.MODE_PERMISSIVE);

Parsing Methods

public Object parseNext() throws ParseException;
public <T> T parseNext(JsonReaderI<T> mapper) throws ParseException; 
public <T> T parseNext(Class<T> mapTo) throws ParseException;
public boolean hasNext();

Parse multiple JSON values sequentially.

String multiJson = """
    {"id": 1, "name": "Alice"}
    {"id": 2, "name": "Bob"}  
    {"id": 3, "name": "Charlie"}
    """;

MultipleJsonParser parser = new MultipleJsonParser(multiJson, JSONParser.MODE_PERMISSIVE);

// Process each JSON object
while (parser.hasNext()) {
    JSONObject user = parser.parseNext(JSONObject.class);
    int id = user.getAsNumber("id").intValue();
    String name = user.getAsString("name");
    System.out.println("User " + id + ": " + name);
}

Streaming File Processing

// Process large file with multiple JSON objects
try (FileInputStream fis = new FileInputStream("large-data.json")) {
    MultipleJsonParser parser = new MultipleJsonParser(fis, JSONParser.MODE_PERMISSIVE);
    
    int count = 0;
    while (parser.hasNext()) {
        Object obj = parser.parseNext();
        
        // Process each object
        if (obj instanceof JSONObject) {
            JSONObject jsonObj = (JSONObject) obj;
            // Handle object
        } else if (obj instanceof JSONArray) {
            JSONArray jsonArr = (JSONArray) obj;
            // Handle array
        }
        
        count++;
        if (count % 1000 == 0) {
            System.out.println("Processed " + count + " objects");
        }
    }
}

ParseException - Error Handling

ParseException provides detailed information about parsing errors.

Error Type Constants

public static final int ERROR_UNEXPECTED_CHAR = 0;
public static final int ERROR_UNEXPECTED_TOKEN = 1;
public static final int ERROR_UNEXPECTED_EXCEPTION = 2;
public static final int ERROR_UNEXPECTED_EOF = 3;
public static final int ERROR_UNEXPECTED_UNICODE = 4;
public static final int ERROR_UNEXPECTED_DUPLICATE_KEY = 5;
public static final int ERROR_UNEXPECTED_LEADING_0 = 6;
public static final int ERROR_UNEXPECTED_JSON_DEPTH = 7;

Constructors and Methods

public ParseException(int position, int errorType, Object unexpectedObject);
public ParseException(int position, Throwable cause);

public int getErrorType();
public int getPosition();
public Object getUnexpectedObject();

Handle parsing errors with detailed information.

JSONParser parser = new JSONParser(JSONParser.MODE_RFC4627);

try {
    parser.parse("{'invalid': json}");
} catch (ParseException e) {
    int errorType = e.getErrorType();
    int position = e.getPosition();
    Object unexpected = e.getUnexpectedObject();
    
    switch (errorType) {
        case ParseException.ERROR_UNEXPECTED_CHAR:
            System.out.println("Unexpected character '" + unexpected + "' at position " + position);
            break;
        case ParseException.ERROR_UNEXPECTED_TOKEN:
            System.out.println("Unexpected token '" + unexpected + "' at position " + position);
            break;
        case ParseException.ERROR_UNEXPECTED_EOF:
            System.out.println("Unexpected end of input at position " + position);
            break;
        case ParseException.ERROR_UNEXPECTED_JSON_DEPTH:
            System.out.println("JSON too deeply nested at position " + position);
            break;
        default:
            System.out.println("Parse error: " + e.getMessage());
    }
}

Advanced Parsing Examples

Incomplete JSON Processing

// Process incomplete JSON streams (useful for real-time data)
int streamMode = JSONParser.MODE_PERMISSIVE | JSONParser.ACCEPT_INCOMPLETE;
JSONParser streamParser = new JSONParser(streamMode);

String incompleteJson = "{\"name\": \"John\", \"age\":"; // Incomplete
try {
    Object result = streamParser.parse(incompleteJson);
    // May return partial object or handle gracefully
} catch (ParseException e) {
    if (e.getErrorType() == ParseException.ERROR_UNEXPECTED_EOF) {
        System.out.println("Incomplete JSON detected, waiting for more data...");
    }
}

High-Precision Number Handling

// Parse financial data requiring high precision
int precisionMode = JSONParser.MODE_PERMISSIVE | JSONParser.USE_HI_PRECISION_FLOAT;
JSONParser precisionParser = new JSONParser(precisionMode);

String financialJson = """
{
  "account": "12345",
  "balance": 123456.789012345678901234567890,
  "transactions": [
    {"amount": 0.000000000000000001, "type": "micro"},
    {"amount": 999999999999999999999.99, "type": "large"}
  ]
}
""";

JSONObject account = precisionParser.parse(financialJson, JSONObject.class);
BigDecimal balance = (BigDecimal) account.get("balance");
System.out.println("Exact balance: " + balance.toPlainString());

JSONArray transactions = (JSONArray) account.get("transactions");
for (Object txObj : transactions) {
    JSONObject tx = (JSONObject) txObj;
    BigDecimal amount = (BigDecimal) tx.get("amount");
    System.out.println("Transaction: " + amount.toPlainString());
}

Custom Error Recovery

public class RobustJSONProcessor {
    
    public List<Object> parseMultipleWithErrorRecovery(String input) {
        List<Object> results = new ArrayList<>();
        MultipleJsonParser parser = new MultipleJsonParser(input, JSONParser.MODE_PERMISSIVE);
        
        while (parser.hasNext()) {
            try {
                Object obj = parser.parseNext();
                results.add(obj);
            } catch (ParseException e) {
                // Log error and continue with next JSON object
                System.err.println("Failed to parse JSON at position " + e.getPosition() + 
                                 ": " + e.getMessage());
                
                // Add error marker to results
                JSONObject errorObj = new JSONObject()
                    .appendField("error", true)
                    .appendField("position", e.getPosition())
                    .appendField("message", e.getMessage());
                results.add(errorObj);
            }
        }
        
        return results;
    }
}

Performance-Optimized Parsing

// Configure parser for maximum performance
int fastMode = JSONParser.MODE_PERMISSIVE | 
               JSONParser.USE_INTEGER_STORAGE |     // Use int instead of long
               JSONParser.BIG_DIGIT_UNRESTRICTED;   // Use double for big numbers

JSONParser fastParser = new JSONParser(fastMode);

// Batch process large amounts of JSON data
List<String> jsonStrings = loadLargeJsonDataset();
List<Object> results = new ArrayList<>();

long startTime = System.currentTimeMillis();
for (String json : jsonStrings) {
    try {
        Object obj = fastParser.parse(json);
        results.add(obj);
    } catch (ParseException e) {
        // Handle errors
    }
}
long endTime = System.currentTimeMillis();

System.out.println("Processed " + jsonStrings.size() + 
                   " JSON objects in " + (endTime - startTime) + "ms");

Validation and Sanitization

public class JSONValidator {
    
    private final JSONParser strictParser = new JSONParser(JSONParser.MODE_RFC4627);
    private final JSONParser permissiveParser = new JSONParser(JSONParser.MODE_PERMISSIVE);
    
    public ValidationResult validateAndSanitize(String json) {
        // Try strict parsing first
        try {
            Object strictResult = strictParser.parse(json);
            return new ValidationResult(true, strictResult, null);
        } catch (ParseException strictError) {
            
            // Try permissive parsing for recovery
            try {
                Object permissiveResult = permissiveParser.parse(json);
                
                // Re-serialize to get clean JSON
                String cleanJson = JSONValue.toJSONString(permissiveResult);
                Object cleanResult = strictParser.parse(cleanJson);
                
                return new ValidationResult(false, cleanResult, 
                    "JSON was sanitized: " + strictError.getMessage());
                    
            } catch (ParseException permissiveError) {
                return new ValidationResult(false, null, 
                    "JSON is invalid: " + permissiveError.getMessage());
            }
        }
    }
    
    public static class ValidationResult {
        public final boolean isStrictlyValid;
        public final Object result;
        public final String message;
        
        public ValidationResult(boolean isStrictlyValid, Object result, String message) {
            this.isStrictlyValid = isStrictlyValid;
            this.result = result;
            this.message = message;
        }
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-net-minidev--json-smart

docs

configuration.md

core-api.md

customization.md

index.md

navigation.md

parsing.md

tile.json