Class JSONParser


  • public class JSONParser
    extends java.lang.Object
    A streaming JSON parser using the push (receive) model.

    Unlike traditional parsers that take an InputStream and block during parsing, this parser uses a non-blocking push model:

    For convenience, a traditional blocking parse(InputStream) method is also provided which internally delegates to the streaming API.

    Parsing events are delivered via JSONContentHandler as tokens are recognized. The parser handles BOM detection, then delegates directly to JSONTokenizer, which tokenizes against the raw bytes - UTF-8 decoding only ever happens for the actual content of a string value/key, never for structural characters, whitespace, numbers, or literals.

    Buffer Management Contract

    This parser follows the standard non-blocking streaming contract:

    • The caller provides a buffer in read mode (ready for get operations)
    • The parser consumes as many complete tokens as possible
    • After receive(ByteBuffer) returns, the buffer's position indicates where unconsumed data begins
    • If there is unconsumed data (partial token), the caller MUST call ByteBuffer.compact() before reading more data into the buffer
    • The next receive() call will continue from where parsing left off

    Usage (Streaming)

    
     JSONParser parser = new JSONParser();
     parser.setContentHandler(myHandler);
     
     ByteBuffer buffer = ByteBuffer.allocate(8192);
     while (channel.read(buffer) > 0) {
         buffer.flip();
         parser.receive(buffer);
         buffer.compact();
     }
     parser.close();
     

    Usage (InputStream)

    
     JSONParser parser = new JSONParser();
     parser.setContentHandler(myHandler);
     parser.parse(inputStream);
     

    Character Encoding

    The parser assumes UTF-8 encoding by default. BOM detection is performed on the first chunk.
    Author:
    Chris Burdess
    • Constructor Summary

      Constructors 
      Constructor Description
      JSONParser()
      Creates a new JSON parser with a default buffer size of 8KB.
      JSONParser​(int bufferSize)
      Creates a new JSON parser with the specified buffer size.
    • Method Summary

      All Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      void close()
      Close the parser, signaling end of input.
      void disableAllLimits()
      Disables every configurable limit (nesting depth, number/string/key length, document length, token count) in one call.
      void parse​(java.io.InputStream in)
      Parse a JSON document from an InputStream.
      void receive​(java.nio.ByteBuffer data)
      Receive bytes into the parser.
      void reset()
      Reset the parser to parse a new document.
      void setContentHandler​(JSONContentHandler handler)
      Register a content handler to be notified of parsing events.
      void setMaxDocumentLength​(long maxDocumentLength)
      Sets the maximum total number of bytes in one document.
      void setMaxNameLength​(int maxNameLength)
      Sets the maximum number of characters in a single object key.
      void setMaxNestingDepth​(int maxNestingDepth)
      Sets the maximum object/array nesting depth.
      void setMaxNumberLength​(int maxNumberLength)
      Sets the maximum number of characters in a single number token.
      void setMaxStringLength​(int maxStringLength)
      Sets the maximum number of characters in a single string value.
      void setMaxTokenCount​(long maxTokenCount)
      Sets the maximum total number of tokens in one document.
      void setRejectDuplicateKeys​(boolean rejectDuplicateKeys)
      Sets whether a repeated key within the same object should be treated as a parse error.
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Constructor Detail

      • JSONParser

        public JSONParser()
        Creates a new JSON parser with a default buffer size of 8KB.
      • JSONParser

        public JSONParser​(int bufferSize)
        Creates a new JSON parser with the specified buffer size.
        Parameters:
        bufferSize - the initial size of the character buffer in bytes
    • Method Detail

      • setContentHandler

        public void setContentHandler​(JSONContentHandler handler)
        Register a content handler to be notified of parsing events.
        Parameters:
        handler - the content handler
      • setRejectDuplicateKeys

        public void setRejectDuplicateKeys​(boolean rejectDuplicateKeys)
        Sets whether a repeated key within the same object should be treated as a parse error. Off by default: RFC 8259 does not mandate unique object keys, and checking for duplicates has a (small) performance cost, so this is opt-in rather than automatic.

        Worth enabling wherever the parsed data crosses a trust boundary: different systems (or different libraries) can disagree about which of two duplicate keys "wins," which is a known class of vulnerability (JSON key-confusion/smuggling) when the same payload is interpreted differently by two components.

        Takes effect from the next document onward (i.e. the next parse(java.io.InputStream) call, or the next reset() followed by receive(java.nio.ByteBuffer)) - changing it mid-document has no effect on a tokenizer already created for that document.

        Parameters:
        rejectDuplicateKeys - true to throw a JSONException on a repeated key within the same object
      • setMaxNestingDepth

        public void setMaxNestingDepth​(int maxNestingDepth)
        Sets the maximum object/array nesting depth. Guards against stack/ memory exhaustion from a maliciously or accidentally deeply nested document. Default 1000 (matches Jackson's StreamReadConstraints default). A value <= 0 disables this check.
        Parameters:
        maxNestingDepth - the maximum nesting depth, or <= 0 to disable
      • setMaxNumberLength

        public void setMaxNumberLength​(int maxNumberLength)
        Sets the maximum number of characters in a single number token. Guards against the CPU/memory cost of converting a pathologically long digit sequence to a BigInteger/double. Default 1000 (matches Jackson). A value <= 0 disables this check.
        Parameters:
        maxNumberLength - the maximum number token length, or <= 0 to disable
      • setMaxStringLength

        public void setMaxStringLength​(int maxStringLength)
        Sets the maximum number of characters in a single string value. Guards against a huge single-string memory allocation. Default 20,000,000 (matches Jackson). A value <= 0 disables this check.
        Parameters:
        maxStringLength - the maximum string length, or <= 0 to disable
      • setMaxNameLength

        public void setMaxNameLength​(int maxNameLength)
        Sets the maximum number of characters in a single object key. Default 50,000 (matches Jackson). A value <= 0 disables this check.
        Parameters:
        maxNameLength - the maximum key length, or <= 0 to disable
      • setMaxDocumentLength

        public void setMaxDocumentLength​(long maxDocumentLength)
        Sets the maximum total number of bytes in one document. Unlimited (0) by default - matches Jackson, which also leaves this off by default since it's very application-specific. A value <= 0 disables this check.
        Parameters:
        maxDocumentLength - the maximum document size in bytes, or <= 0 to disable
      • setMaxTokenCount

        public void setMaxTokenCount​(long maxTokenCount)
        Sets the maximum total number of tokens in one document. Guards against a huge flat array/object (many small elements) that would otherwise slip past the other limits. Unlimited (0) by default - matches Jackson. A value <= 0 disables this check.
        Parameters:
        maxTokenCount - the maximum token count, or <= 0 to disable
      • disableAllLimits

        public void disableAllLimits()
        Disables every configurable limit (nesting depth, number/string/key length, document length, token count) in one call. Intended for trusted input and for internal testing/benchmarking, where the industry-standard defaults would otherwise be unnecessarily restrictive rather than protective.
      • parse

        public void parse​(java.io.InputStream in)
                   throws JSONException
        Parse a JSON document from an InputStream.

        This is a convenience method that reads the input stream in chunks and delegates to the streaming receive(ByteBuffer) API. The stream is read until EOF, then close() is called.

        The parser is automatically reset before parsing, allowing this method to be called multiple times to parse different documents.

        Note: This method does not close the InputStream.

        Parameters:
        in - the input stream to parse
        Throws:
        JSONException - if there is a parsing error
      • receive

        public void receive​(java.nio.ByteBuffer data)
                     throws JSONException
        Receive bytes into the parser.

        Bytes are processed immediately. Parsing events are fired to the content handler as tokens are recognized. Incomplete tokens are left in the buffer - the position is set to the start of the incomplete token.

        Buffer Contract: The byte buffer must be in read mode (after flip()). After this method returns:

        • The buffer's position indicates where unconsumed data begins
        • If position() < limit(), there is a partial token that needs more data to complete
        • The caller MUST call buffer.compact() before reading more data into the buffer
        Parameters:
        data - the byte buffer to process (must be in read mode)
        Throws:
        JSONException - if there is a parsing error or stream is closed
      • close

        public void close()
                   throws JSONException
        Close the parser, signaling end of input.

        This validates that the JSON document is complete. The closed state is signaled to the tokenizer, which will treat end-of-buffer as end-of-token (e.g., for numbers without delimiters like "42").

        After closing, further calls to receive() will throw an exception. Use reset() to prepare the parser for a new document.

        Throws:
        JSONException - if the document is incomplete or malformed
      • reset

        public void reset()
        Reset the parser to parse a new document.

        Clears all internal state, allowing the parser to be reused. This is called automatically by parse(InputStream).